Spring依赖注入方式和源码分析

手动注入|自动注入

Posted by Sunfy on 2021-09-14
Words 1.7k and Reading Time 6 Minutes
Viewed Times
Viewed Times
Visitors In Total

Spring中Bean的依赖注入

依赖注入的方式

手动注入

这种方式主要通过xml配置文件进行扫描。配置信息如下

从源码角度来说,手动注入又分为set方法注入和构造方法注入。

set方法注入

1
2
3
4
<bean name="orderService" class="top.sunfy.service.OrderService"/>
<bean name="userService" class="top.sunfy.service.UserService">
<property name="orderService" ref="orderService"/>
</bean>
1
2
3
4
5
6
7
8
9
public class UserService {
private OrderService orderService;
public void test() {
System.out.println(orderService);
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
}

说明,使用set方法注入时,在代码中必须添加相应的set方法,依赖注入时会根据set后面的名称去ioc容器中查找相应的方法,找到后进行赋值。

构造方法注入

1
2
3
4
<bean name="orderService" class="top.sunfy.service.OrderService"/>
<bean name="userService" class="top.sunfy.service.UserService">
<constructor-arg index="0" ref="orderService"/>
</bean>
1
2
3
4
5
6
7
8
9
public class UserService {
private OrderService orderService;
public UserService(OrderService orderService) {
this.orderService = orderService;
}
public void test() {
System.out.println(orderService);
}
}

说明,使用构造方法注入时,在代码中必须重写构造方法,并根据注入配置重写相对应的构造方法,依赖注入时会根据参数名称去IOC容器中查找相应的方法,找到后进行赋值。

自动注入

XML的autowire自动注入

image-20210915150329433

XML中,在定义一个bean时,我们可以通过autowire设置自动注入模式:

  • byName
  • byType
  • constructor
  • default
  • no

XML配置如下

1
<bean id="userService" class="top.sunfy.service.UserService" autowire="byName"/>

如上配置,spring会自动给UserService类中所有的属性自动赋值,不需要在属性上配置@Autowired注解,但是必须有set方法。

ByName自动填充属性时流程:

  • 找到所有set方法所对应的属性名称部分的名字。
  • 根据属性名称的名字去获取bean。

ByType自动填充属性时流程:

  • 获取set方法中的唯一参数的参数类型,并且根据类型去IOC容器中获取Bean。
  • 如果找到多个,会报错。

Constructor自动填充属性:

  • 使用这种方式时,就不需要写属性的set方法了,这个就是使用构造方法的方式进行注入,spring会利用构造方法中的参数信息去Spring容器中找bean,找到bean之后作为参数传给构造方法,从而实例化得到一个bean对象,并完成属性赋值,此时属性赋值需要我们在构造方法中自行编写。
  • 这块目前只考虑只有一个构造方法的情况,如果多个构造方法时,会涉及推断构造方法,这个具体后续有单独说明。
  • 这种方式中,就相当于ByType和ByName两种方式,和普通的ByType不同,如果采用Constructor进行自动填充,会通过ByType先在容器中查找,如果找到多个,会再根据名称去进行比对,最终确定唯一的内容,进行填充。通过一个示例说明:

spring.xml配置如下

1
2
3
<bean name="orderService" class="top.sunfy.service.OrderService"/>
<bean name="orderService1" class="top.sunfy.service.OrderService"/>
<bean id="userService" class="top.sunfy.service.UserService" autowire="constructor"/>

UserService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class UserService {
private OrderService orderService;
// 构造方法1
public UserService(OrderService orderService) {
this.orderService = orderService1;
}
// 构造方法2
//public UserService(OrderService orderService1) {
// this.orderService = orderService1;
//}
public void test() {
System.out.println(orderService);
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext xmlApplicationContext = new ClassPathXmlApplicationContext("classpath:/spring.xml");
UserService userService = xmlApplicationContext.getBean(UserService.class);
// 打印出了注入到UserService中的bean
userService.test();
// 分别打印IOC容器中的两个OrderService
System.out.println(xmlApplicationContext.getBean("orderService"));
System.out.println(xmlApplicationContext.getBean("orderService1"));
}
}

测试结果

1
2
3
4
5
6
7
8
构造方法一:
top.sunfy.service.OrderService@27d415d9
top.sunfy.service.OrderService@27d415d9
top.sunfy.service.OrderService@5c18298f
构造方法二:
top.sunfy.service.OrderService@27d415d9
top.sunfy.service.OrderService@5c18298f
top.sunfy.service.OrderService@27d415d9

结果分析,我们可以看出,通过上面的测试,我们证明了,在使用XML中使用Constructor自动属性填充时,会先根据Type进行查找,如果找到多个,会再根据名称进行找到。

no:表示关闭了autowire

default:这个表示默认值,我们刚才的使用过程中都是在<bean>标签中使用的,autowrite也可以使用在<beans>标签上,这样的设置表示,如果beans中设置了,那么bean中设置为default会模式使用beans中设置的。

通过上述的说明,可以看出XML中的Autowrite功能还是很强大,但是我们在平时中更多的使用的还是@Autowrite注解的方式,那这又是为什么呢?二者之间的区别是什么呢?

要回答这个问题,我们首先来了解一下@Autowired注解的使用和特点

@Autowired注解自动注入

@Autowired注解可以写在:

  • 属性上:先根据属性类型去找bean,如果找到多个再根据属性名确定。
  • 构造方法上:先根据方法参数类型去找bean,如果找到多个再根据属性名确定。
  • set方法上:先根据方法参数类型去找bean,如果找到多个再根据参数名确定。

从底层来看,到了

  • 属性注入
  • set方法注入
  • 构造方法注入

XML中的Autowrite和@Autowrite注解的区别?

  • @Autowirte相当于XML中的autowrite属性的注解方式的替代。看一个官网中的说明 Essentially, the @Autowired annotation provides the same capabilities as described in Autowiring Collaborators but with more fine-grained control and wider applicability(本质上,@Autowired注释提供了与Autowiring collaborator中描述的相同的功能,但具有更细粒度的控制和更广泛的适用性)
  • 看官网描述中提到的更细粒度的控制
  • XML中的autowirte控制的是整个bean的所有属性,而@Autowirte注解可以写在某个属性上,某个set方法上,某个构造方法上。假如一个bean有多个构造方法,那XML配置中使用构造方法注入时则无法控制到底使用哪个构造方法,而@Autowrite可以直接指定想用哪个构造方法。
  • @Autowrite可以控制哪些属性想被自动注入,哪些属性不想,这也体现了@Autowrite的细粒度控制。
  • @Autowrite无法区分ByType和ByName,会先ByType,如果找到多个再通过ByName。源码中的具体实现不同
  • XML的自动注入底层其实也就是set方法注入和构造方法注入。

源码分析

什么是属性描述器 PropertyDescriptor

image-20210914135343558

什么样的属性能进行自动注入?

image-20210914140832924

简单值检查方法:

image-20210914140944745

为什么使用@Autowrite注解的属性是static时,不会进行赋值呢。

@Autowrite注解的required属性的使用说明

@Autowrite注解注入时获取的是,参数的类型和名称,和方法名称并没有关系,都可以注入

构建自动装配元数据时,桥接方法的作用?

image-20210914155649171

同时使用@Autowrite注解和BeanDefinition给某个对象赋值,最终会是什么样的结果呢?


Copyright 2021 sunfy.top ALL Rights Reserved

...

...

00:00
00:00