Spring IOC 本质:IOC = Inversion of Control,控制反转
spring容器=bean
把对象的创建、依赖管理、生命周期控制权,从程序员自己手动 new,交给 Spring 容器统一管理。
传统写法(正控:程序员掌控一切)
c
// 自己手动new对象
UserService service = new UserService();
// 自己手动给属性赋值、创建依赖对象
UserDao dao = new UserDao();
service.setDao(dao);
控制权在你代码手里:你想什么时候 new、怎么赋值、什么时候销毁,全由代码硬编码决定。
IOC 写法(反转:容器接管控制权)
你只在配置 / 注解里告诉 Spring:需要哪些类、谁依赖谁。
Spring 容器自动:
创建实例对象
自动装配依赖(自动 set 注入 / 构造注入)
管理对象单例 / 多例、初始化、销毁
对象生命周期的控制权,反转交给了 IoC 容器,这就是控制反转。
- 核心两大核心职能,就是 IOC 容器的本体
① 实例化:Bean 工厂
容器就是一个超大 Map 容器:Map<bean名称, 实例对象>
启动时扫描所有组件,提前创建好对象存入 Map,后续你用 getBean() 直接从容器里取,不用自己 new。
② 依赖注入 DI(IOC 最核心落地手段)
DI = Dependency Injection 依赖注入
IOC 是思想,DI 是实现 IOC 的具体方式。
容器自动把一个类需要的其他对象,自动注入进去,不用手动编码装配依赖
Spring IoC 创建 Bean 对象的 5 种常用方式:
传统的创建对象方式
1、new User();//通过无参构造实例化化对象
2、new User(name);//通过有参构造实例化化对象
spring容器(bean)创建对象(实例化对象)
一、无参构造方法创建(默认最基础方式)
规则
Spring 会默认调用类无参构造函数实例化对象,XML / 注解方式默认都是此方式。
clike
<!-- 只指定类,底层自动调用无参构造 -->
<bean id="user" class="com.pojo.User"/>
前提:类必须存在无参构造,如果只写了有参构造、没写无参,直接报错。
二、有参构造器创建(构造注入)
方式 1:下标索引赋值
csharp
<bean id="user" class="com.pojo.User">
<!-- index 对应构造方法参数位置,从0开始 -->
<constructor-arg index="0" value="张三"/>
<constructor-arg index="1" value="18"/>
</bean>
方式 2:参数名匹配
bash
<constructor-arg name="username" value="李四"/>
方式 3:参数类型匹配
c
<constructor-arg type="java.lang.String" value="王五"/>
依赖注入
1、构造器注入
2、set方式注入(重点)
XML:set 注入、构造注入;
注解:@Autowired按类型、@Resource按名称、@Value注入配置;
DI 本质:容器帮你给类的依赖属性赋值。
三、DI 依赖注入(Dependency Injection)超全详解
DI = Dependency Injection 依赖注入
IOC 是思想(控制反转):把对象创建、依赖管理交给容器;
DI 是 IOC 的具体实现手段:容器主动将当前类需要的依赖对象,自动赋值注入进去,不用自己new依赖。
二、Spring 4 种主流注入方式
- Setter 注入(标签,最常用)
条件
类中必须提供 setXxx () 方法,Spring 通过反射调用 set 方法赋值。
bash
<!-- 1. 普通基本类型/字符串 -->
<bean id="user" class="com.pojo.User">
<property name="username" value="张三"/>
<property name="age" value="18"/>
</bean>
<!-- 2. 注入容器中其他Bean对象(ref引用) -->
<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService">
<!-- name对应setDao,ref指向另一个bean的id -->
<property name="dao" ref="userDao"/>
</bean>
- 构造器注入()
条件
类提供带参数构造方法,容器实例化 Bean 时直接通过构造方法传参创建对象。
cpp
<bean id="user" class="com.pojo.User">
<!-- 方式1:按构造参数下标(从0开始) -->
<constructor-arg index="0" value="李四"/>
<!-- 方式2:按参数名匹配 -->
<constructor-arg name="age" value="22"/>
<!-- 方式3:按参数类型匹配 -->
<constructor-arg type="int" value="22"/>
<!-- 注入其他Bean -->
<constructor-arg name="dao" ref="userDao"/>
</bean>
c
<!--p命令空间注入,直接注入属性值对比传统的set注入 -->
<bean id="user2" class="com.cn.User" p:name="p标签写法" p:gae="20"/>
<!--c命令空间注入,通过构造器注入属性值对比传统的构造注入-->
<bean id="user1" class="com.cn.User" c:name="构造器" c:gae="30"/>
两种对比:
c
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
1、语法:p:属性名="值"
<bean id="student" class="com.cn.Student"
p:name="张三"
p:age="20"/>
等价写法
<bean id="student" class="com.cn.Student">
<property name="name" value="张三"/>
<property name="age" value="20"/>
</bean>
2、 引用其他 Bean 对象(对象依赖)
p:属性名-ref="目标beanId"
<bean id="address" class="com.cn.Address" p:city="乌鲁木齐"/>
<bean id="student" class="com.cn.Student"
p:name="李四"
p:address-ref="address"/>
等价写法
<property name="address" ref="address"/>
-->
<!--1、传统写法-->
<bean id="adder" class="com.cn.Adderss"/>
<bean id="user" class="com.cn.User">
<property name="name" value="传统写法"/>
<property name="gae" value="20"/>
</bean>
<!--p:写法
1、语法:p:属性名="值"
reference:ref==引用
<bean id="student" class="com.cn.Student"
p:name="张三"
p:age="20"/>-->
<!--p命令空间注入,直接注入属性值对比传统的set注入 -->
<bean id="user2" class="com.cn.User" p:name="p标签写法" p:gae="20"/>
<!--c命令空间注入,通过构造器注入属性值对比传统的构造注入-->
<bean id="user1" class="com.cn.User" c:name="构造器" c:gae="30"/>
<bean id="stu" class="com.cn.User">
<!-- 第一个参数 -->
<constructor-arg value="小明"/>
<!-- 第二个参数 -->
<constructor-arg value="18"/>
</bean>
<bean id="stu1" class="com.cn.User">
<!-- 第一个参数 -->
<constructor-arg value="小明"/>
<!-- 第二个参数 -->
<constructor-arg value="18"/>
</bean>
<bean id="stu2" class="com.cn.User">
<constructor-arg index="0" value="小红"/>
<constructor-arg index="1" value="20"/>
</bean>
</beans>
- 字段注入(注解开发主流,直接给成员变量赋值)
不需要 set / 构造方法,直接在属性上加注解,底层反射暴力赋值。
① @Autowired(Spring 原生,按类型 byType 注入)
c
@Service
public class UserService {
// 直接注入,不需要set方法
@Autowired
private UserDao userDao;
}
③ @Value 注入普通字面量 / 配置文件值
bash
// 直接写死值
@Value("小明")
private String name;
// 读取properties配置文件
@Value("${db.url}")
private String url;