第六章:Spring IoC 注入

依赖注入的模式和类型

模式

手动模式 - 配置或者编程的方式,提前安排注入规则
  • XML 资源配置元信息
  • Java 注解配置元信息
  • API 配置元信息
自动模式 - 实现方提供依赖自动关联的方式,按照內建的注入规则
  • Autowiring(自动绑定)

自动绑定(Autowiring)

自动绑定(Autowiring)模式

自动绑定(Autowiring)限制和不足

依赖注入方式

Setter 方法依赖注入

UserHolder注入User

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class UserHolder {

private User user;

public UserHolder() {
}

public UserHolder(User user) {
this.user = user;
}

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

@Override
public String toString() {
return "UserHolder{" +
"user=" + user +
'}';
}
}

手动模式

XML 资源配置元信息
1
2
3
4
<!-- xml 手动 Setter 注入 -->
<bean class="com.cruise.thinking.in.spring.dependency.injection.holder.UserHolder">
<property name="user" ref="superUser"/>
</bean>
Java 注解配置元信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class AnnotationDependencySetterInjectionDemo {

public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

context.register(AnnotationDependencySetterInjectionDemo.class);

// 使用注解的方式启动Spring上下文也可以使用 Xml的特性
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
// 解析Xml,注册User
reader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");

context.refresh();

UserHolder userHolder = context.getBean(UserHolder.class);

System.out.println(userHolder);

context.close();

}

// 注入User到UserHolder
@Bean
public UserHolder userHolder(User user) {
UserHolder userHolder = new UserHolder();
userHolder.setUser(user);
return userHolder;
}
}
API 配置元信息
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
   public static void main(String[] args) {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

// 注册 UserHolder的 BeanDefinition
context.registerBeanDefinition("userHolder", createBeanDefinition());

// 使用注解的方式启动Spring上下文也可以使用 Xml的特性
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");

context.refresh();

UserHolder userHolder = context.getBean(UserHolder.class);

System.out.println(userHolder);

context.close();

}

// 使用javaAPI setter
private static BeanDefinition createBeanDefinition() {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
// Setter 注入是没有顺序的
beanDefinitionBuilder.addPropertyReference("user", "superUser");

return beanDefinitionBuilder.getBeanDefinition();
}

自动模式

byName

当SpringIOC中存在user名称的对象时,setter注入

1
<bean class="com.cruise.thinking.in.spring.dependency.injection.holder.UserHolder" autowire="byName"/>
byType

​ 将上面的byName改成byType即可

构造器依赖注入

手动模式

XML 资源配置元信息
1
2
3
4
5
6
<!-- xml 手动 constructor 注入 -->
<bean class="com.cruise.thinking.in.spring.dependency.injection.holder.UserHolder">
<!-- 使用name或者index都可以 -->
<!--<constructor-arg name="user" ref="superUser"/>-->
<constructor-arg index="0" ref="superUser"/>
</bean>
Java 注解配置元信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class AnnotationDependencyConstructorInjectionDemo {

public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

context.register(AnnotationDependencyConstructorInjectionDemo.class);

// 使用注解的方式启动Spring上下文也可以使用 Xml的特性
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");

context.refresh();

UserHolder userHolder = context.getBean(UserHolder.class);

System.out.println(userHolder);

context.close();

}

@Bean
public UserHolder userHolder(User user) {
return new UserHolder(user);
}
}
API 配置元信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class ApiDependencyConstructorInjectionDemo {

public static void main(String[] args) {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

// 注册 UserHolder的 BeanDefinition
context.registerBeanDefinition("userHolder", createBeanDefinition());

// 使用注解的方式启动Spring上下文也可以使用 Xml的特性
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");

context.refresh();

UserHolder userHolder = context.getBean(UserHolder.class);

System.out.println(userHolder);

context.close();

}

private static BeanDefinition createBeanDefinition() {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);

// 构造器参数是有顺序的
beanDefinitionBuilder.addConstructorArgReference("superUser");

return beanDefinitionBuilder.getBeanDefinition();
}
}

自动模式

constructor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AutowiringDependencyConstructorInjectionDemo {

public static void main(String[] args) {

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);

reader.loadBeanDefinitions("classpath:/META-INF/autowiring-dependency-injection-constructor.xml");

UserHolder bean = beanFactory.getBean(UserHolder.class);

System.out.println(bean);

}
}
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">

<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>

<!-- 基于 xml 自动 constructor 注入 -->
<bean class="com.cruise.thinking.in.spring.dependency.injection.holder.UserHolder" autowire="constructor"/>

</beans>

字段注入

手动模式

Java 注解配置元信息
@Autowired

会自动忽略static属性

@Resource
@Inject(可选)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class AnnotationDependencyFieldInjectionDemo {

@Autowired
private UserHolder userHolder;

@Resource
private UserHolder userHolder2;

@Inject
private UserHolder userHolder3;

/**
* 会自动忽略static属性
*/
@Autowired
private static UserHolder userHolder4;

public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

context.register(AnnotationDependencyFieldInjectionDemo.class);

// 使用注解的方式启动Spring上下文也可以使用 Xml的特性
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");

context.refresh();

AnnotationDependencyFieldInjectionDemo bean = context.getBean(AnnotationDependencyFieldInjectionDemo.class);

System.out.println(bean.userHolder);
System.out.println(bean.userHolder2);
System.out.println(bean.userHolder3);
System.out.println(bean.userHolder4); // null
System.out.println(bean.userHolder == bean.userHolder2); // true
System.out.println(bean.userHolder == bean.userHolder3); // true

context.close();
}

@Bean
public UserHolder userHolder(User user) {
// 构造器注入属性
return new UserHolder(user);
}
}

方法注入

手动模式

Java 注解配置元信息
@Autowired
@Resource
@Inject(可选)
@Bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class AnnotationDependencyMethodInjectionDemo {

private UserHolder userHolder;
private UserHolder userHolder2;
private UserHolder userHolder3;

/**
* {@link Autowired} 使用在方法上,方法名是任意的,只需要 Spring 容器中存在 参数类型的 Bean
*
* @param userHolder
*/
@Autowired
public void init(UserHolder userHolder) {
this.userHolder = userHolder;
}

/**
* {@link Resource} 使用在方法上,方法名是任意的
*
* @param userHolder2
*/
@Resource
public void init2(UserHolder userHolder2) {
this.userHolder2 = userHolder2;
}

/**
* {@link Inject} 使用在方法上,方法名是任意的
*
* @param userHolder3
*/
@Inject
public void init3(UserHolder userHolder3) {
this.userHolder3 = userHolder3;
}

/**
* 注册Bean
* @param user
* @return
*/
@Bean
public UserHolder userHolder(User user) {
// 构造器注入属性
return new UserHolder(user);
}

public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

context.register(AnnotationDependencyMethodInjectionDemo.class);

// 使用注解的方式启动Spring上下文也可以使用 Xml的特性
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");

context.refresh();

AnnotationDependencyMethodInjectionDemo bean = context.getBean(AnnotationDependencyMethodInjectionDemo.class);

System.out.println(bean.userHolder);
System.out.println(bean.userHolder2);
System.out.println(bean.userHolder3);
System.out.println(bean.userHolder == bean.userHolder2);
System.out.println(bean.userHolder == bean.userHolder3);

context.close();
}

}

回调注入(Aware接口)

image-20211220231138030

image-20211220231150517

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {

private BeanFactory beanFactory;

private ApplicationContext applicationContext;


public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AwareInterfaceDependencyInjectionDemo.class);

AwareInterfaceDependencyInjectionDemo bean = context.getBean(AwareInterfaceDependencyInjectionDemo.class);

System.out.println(bean.applicationContext == context);// true
System.out.println(bean.beanFactory == context.getBeanFactory());// true

context.close();
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

依赖注入类型选择

image-20211220231700978

基础类型注入

image-20211220231715367

CityHolder, 需要注入Object , Resource、Optional

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class CityHolder {

private City city;

private Resource cityResource;

private Optional<String> desc;

public City getCity() {
return city;
}

public void setCity(City city) {
this.city = city;
}

public Resource getCityResource() {
return cityResource;
}

public void setCityResource(Resource cityResource) {
this.cityResource = cityResource;
}

public Optional<String> getDesc() {
return desc;
}

public void setDesc(Optional<String> desc) {
this.desc = desc;
}

@Override
public String toString() {
return "CityHolder{" +
"city=" + city +
", cityResource=" + cityResource +
", desc=" + desc +
'}';
}
}

Xml的配置信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 基础类型注入 -->
<bean id="cityHolder" class="com.cruise.thinking.in.spring.dependency.injection.holder.CityHolder">
<!-- 注入 enum 类型 输入的是字符串 输出的是 enum -->
<property name="city" value="BEIJING"/>
<!-- 注入 Spring 类型 输入的是字符串 输出的是 Resource -->
<property name="cityResource" value="classpath:/META-INF/city.properties"/>
<!-- 注入 Optional 类型 -->
<property name="desc" ref="optional"/>
</bean>

<bean id="optional" class="java.util.Optional">
<constructor-arg name="value" value="北京"/>
</bean>

集合类型注入

image-20211220231724377

集合类型注入:数组,集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MultiCityHolder {

private City[] cities;

private List<City> cityList;

public City[] getCities() {
return cities;
}

public void setCities(City[] cities) {
this.cities = cities;
}

public List<City> getCityList() {
return cityList;
}

public void setCityList(List<City> cityList) {
this.cityList = cityList;
}

@Override
public String toString() {
return "MultiCityHolder{" +
"cities=" + Arrays.toString(cities) +
", cityList=" + cityList +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
<!-- 集合类型注入 -->
<bean id="multiCityHolder" class="com.cruise.thinking.in.spring.dependency.injection.holder.MultiCityHolder">
<property name="cities" value="BEIJING,HANGZHOU"/>
<!-- 二选一 -->
<!--<property name="cityList" value="BEIJING,SHANGHAI"/>-->
<property name="cityList">
<list>
<value>BEIJING</value>
<value>SHANGHAI</value>
</list>
</property>
</bean>

限定注入

image-20211226105214987

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public class QualifierDependencyInjectionDemo {

/**
* 注入 User 类型的 Bean ,如果存在多个则注入 Primary 的 Bean
*
*/
@Autowired
private User user;

/**
* 注入 User 类型的 且 beanName是 user的
*
*/
@Autowired
@Qualifier("user")
private User namedUser;

@Autowired
private List<User> allUsers;

@Autowired
@Qualifier
private List<User> qualifierUsers;

@Autowired
@UserGroup
private List<User> groupUsers;

@Bean
public User user() {
User user = new User();
user.setId(1L);
return user;
}

@Bean
@Primary
public SuperUser superUser() {
SuperUser superUser = new SuperUser();
superUser.setId(2L);
return superUser;
}

@Bean
@Qualifier // 进行分组
public User user1() {
User user = new User();
user.setId(3L);
return user;
}

@Bean
@Qualifier // 进行分组
public User user2() {
User user = new User();
user.setId(4L);
return user;
}

@Bean
@UserGroup
public User user3() {
User user = new User();
user.setId(5L);
return user;
}

@Bean
@UserGroup
public User user4() {
User user = new User();
user.setId(6L);
return user;
}

public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(QualifierDependencyInjectionDemo.class);

QualifierDependencyInjectionDemo bean = context.getBean(QualifierDependencyInjectionDemo.class);

// 输出 Primary 的 User
System.out.println("bean.user" + bean.user);
// 输出 限定了名称的 User
System.out.println("bean.namedUser" + bean.namedUser);
// 输出 全部 User,包含使用 @Qualifier 和 @UserGroup 注册的 Bean
System.out.println("bean.allUsers" + bean.allUsers);
// 输出 通过 @Qualifier 分组的 User,仅包含使用 @Qualifier 和 @UserGroup 注册的 Bean
System.out.println("bean.qualifierUsers" + bean.qualifierUsers);
// 输出 通过 @UserGroup 扩展的 User,仅包含使用 @UserGroup 注册的 Bean
System.out.println("bean.groupUsers" + bean.groupUsers);
context.close();
}
}
1
2
3
4
5
bean.usersuperUser{address='null'} User{id=2, name='null'}
bean.namedUserUser{id=1, name='null'}
bean.allUsers[User{id=1, name='null'}, superUser{address='null'} User{id=2, name='null'}, User{id=3, name='null'}, User{id=4, name='null'}, User{id=5, name='null'}, User{id=6, name='null'}]
bean.qualifierUsers[User{id=3, name='null'}, User{id=4, name='null'}, User{id=5, name='null'}, User{id=6, name='null'}]
bean.groupUsers[User{id=5, name='null'}, User{id=6, name='null'}]

UserGroup 上面有@Qualifier注解

1
2
3
4
5
6
7
8
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier
public @interface UserGroup {
}

延迟依赖注入

image-20211226113618284

依赖处理过程

image-20211226113804903

@Autowired 注入原理

JSR-330 @Inject 注入原理

Java通用注解注入原理

自定义依赖注入注解

面试题精选