所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。
Inject Mode And Type
依赖注入的模式和类型
依赖注入有自动注入(Autowring)
与手动注入
两种模式,
Setter方法
、构造器
、字段
、方法
、接口回调
五种类型
但是官方并不推荐自动模式
依赖注入的模式
自动模式 - 实现方提供依赖自动绑定方式,按照内建的注入规则
- Autowiring
手动模式 - 配置或者编程的方式,提前安排注入规则
- XML配置信息
- Java注解配置信息
- API配置信息
手动中的API配置信息
方式日常开发很少使用,但是面向容器开发或者基于Spring进行扩展时,必须要会使用。
依赖注入的类型
依赖注入类型 | 配置信息举例 | 备注 |
---|---|---|
Setter方法 | ref时可以通过Bean的Id或名字或Alis(别名)引用到, | |
构造器 | 通过构造器参数注入属性,官方较为推荐 | |
字段 | @Autowirted BeanUser beanUser | 官方不推荐,通过反射来修改类字段很危险,但是开发中使用这种方式很快捷 |
方法 | @Autowirted public void BeanUserMethord(BeanUser beanUser){} | 本质上和set方法注入一样,都是通过一个函数方法为字段赋值 |
接口回调 | clsss BeanUser implements BeanFactoryAware | 属于Spring的特殊方式,通过实现Aware接口,拿到一个BeanFactory,就可以自定义注入操作 |
Feature - Autowiring
Autowiring
:自动绑定
是Spring的一个重要特性,Spring容器能够通过自动绑定的关系,在合作(组合、依赖于被依赖类)的Bean之间,以自动化的方式将Bean的合作者关联上。
优点 :可以有效的减少构造器或属性的设定/配置,会根据设置的byName
和byType
自动寻找匹配的bean。
缺点:当设置自动绑定类型为byName
时, 如果字段名称变了而Bean命没有变,会无法绑定上。
小节:显示的引用绑定大于隐式的绑定。
自动绑定的模式
使用方式
- 注解:
@Autowire
- XML:
auto-wire=''
模式 | 说明 |
---|---|
no | 默认值,未激活Autowiring,需要手动指定依赖注入对象 |
byName | 根据被注入属性的名称做为Bean名称进行依赖查找,并将对象设置到该属性 |
byType | 根据被注入属性的类型做为依赖类型进行查找,并将对象设置到该属性 |
constructor | 特殊byType类型,用于构造器参数 |
所有模式,详见Autowire类
Autowiring自动绑定的不足
Autowiring主要匹配的是XML方式用,可以简化配置操作,但因为本身存在的歧义性
,导致在实际中却很少用到。
精确依赖问题
:- 构造器参数、方法参数上的值,可以覆盖掉Autowiring的值。
- 自动绑定是一种猜测行为,精准性无法把控。
- 多个Bean符合预期时,可能无法找到合适的方式去匹配(例如:byName无法定位且byType找到了多个的情况)。
- 简单类型问题:
- 因为自动绑定的是Bean这种对象,所以不可以绑定原生类型、String类型,Class类型(虽然不不可以自动绑定,但是可以使用@Value这种依赖注入的方式)
- 工具本身问题:
- Autowiring没有一个文档化的过程,只能通过静态的方式,去全部扫描是否缺失了Bean,无法提前预知。
为了避免这些歧义性出现在工程中
- 可以关闭自动绑定模式
- 可以设置autowire-candidate属性为false,以提醒显示的指定依赖。
- 可以设置
Bean
为primary
- 可as以增加注解配置进行详细配置
注入方式
Set方法注入
实现方式
- 手动模式
- XML配置
- 注解配置
- Spring API配置
- 自动模式(Autowiring模式)
- byName
- byType
示例环境
//将User类注入到UserManage中
public class UserManage {
private User user;
public UserManage (){}
public UserManage (User user){this.user = user;}
}
public class User {
private Long id;
}
手动模式
xml配置示例
<beans>
<bean class="Usermanage">
<property name="user" ref="user" />
</bean>
</beans>
注解配置示例
public class Demo {
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
applicationContext.close();
}
//====================核心代码====================
/**
* 将User注入容器中
* 因为容器的三级缓存原因,可以放在userManage下面,不会影响Bean的正常注册
* @param user 拿到容器中的user,通过调用set方法注入字段
*/
@Bean
public UserManage userManage(User user) {
UserManage userManage = new UserManage();
userManage.setUser(user);
return userHolder;
}
/**
* 将User注入容器中
* 因为容器的三级缓存原因,可以放在userManage下面,不会影响Bean的正常注册
*/
@Bean
public User user() {
User user = new User();
return user;
}
//====================核心代码====================
}
Spring API配置示例
public class Demo {
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
//====================核心代码====================
// 生成 UserManage 的 BeanDefinition
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
//假设已经通过注解或xml等方式,此时将User类注入进容器中
definitionBuilder.addPropertyReference("user", "user");
BeanDefinition userManageBeanDefinition = definitionBuilder.getBeanDefinition();
// 注册 UserHolder 的 BeanDefinition
applicationContext.registerBeanDefinition("userManage", userManageBeanDefinition);
//====================核心代码====================
applicationContext.refresh();
// 依赖查找并且创建 Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
applicationContext.close();
}
/**
* 先将User注入容器中
*/
@Bean
public User user() {
User user = new User();
return user;
}
}
自动模式
自动绑定模式更多的是用在XML方式中,故显示XML的方式,注解方式中使用@Resource,其实就已经指定了Type与优先寻找的id
ByName方式xml配置示例
<beans>
<bean class="Usermanage" autowire="byName">
<!-- 会替代这部分代码,寻找容器中id名为user的Bean,再调用Set方法注入 -->
<!-- <property name="user" ref="user" /> -->
</bean>
</beans>
ByType方式xml配置示例
<beans>
<bean class="Usermanage" autowire="byType">
<!-- 会替代这部分代码,寻找容器中Class类型为User的Bean,调用Set方法进行注入 -->
<!-- 当出现多个匹配的Bean时,会使用设置为primary的Bean -->
<!-- 当出现多个标识primary的Bean,或者有多个没有设置primary的Bean的情况,就抛出异常,注入失败 -->
<!-- <property name="user" ref="user" /> -->
</bean>
</beans>
如何即使用注解配置,又使用XML配置
public class Demo {
public static void main(String[] args) {
// 创建注解配置容器,设置XML读取类
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
//定义XML文件地址,加载XML资源,解析并且生成 BeanDefinition
String xmlResourcePath = "classpath:/META-INF/bean.xml";
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//此时启动容器,就有了注解与XML中的Bean信息
applicationContext.refresh();
}
}
构造器注入
- 手动模式
- xml配置
- Java注解配置
- API配置
- 自动模式
- constructor
手动模式
xml配置示例
<beans>
<bean class="Usermanage" autowire="byType">
<construct-arg name="user" ref="user" />
</bean>
</beans>
注解配置示例
public class Demo {
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
applicationContext.close();
}
//====================核心代码====================
/**
* @param user 容器中的user
*/
@Bean
public UserManage userManage(User user) {
//调用UserManage的有参构造器,实现手动构造器注入
UserManage userManage = new UserManage(user);
return userHolder;
}
//====================核心代码====================
/**
* 将User注入容器中
*/
@Bean
public User user() {
User user = new User();
return user;
}
}
Spring API配置示例
public class Demo {
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
// 生成 UserManage 的 BeanDefinition
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
//====================核心代码====================
//将容器中的User类,使用Api的方式进行构造器注入
//此方法只有一个参数,就是Bean名
//definitionBuilder.addConstructorArgReference(String)的调用顺序,就是UserManage的构造器参数顺序
//这也是比Set方式注入更好的原因之一 ----- 可以指定顺序
definitionBuilder.addConstructorArgReference("user");
BeanDefinition userManageBeanDefinition = definitionBuilder.getBeanDefinition();
//====================核心代码====================
// 注册 UserHolder 的 BeanDefinition
applicationContext.registerBeanDefinition("userManage", userManageBeanDefinition);
applicationContext.refresh();
// 依赖查找并且创建 Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
applicationContext.close();
}
/**
* 先将User注入容器中
*/
@Bean
public User user() {
User user = new User();
return user;
}
}
自动模式
constructor方式xml配置示例
<beans>
<bean class="Usermanage" autowire="constructor">
<!-- <construct-arg name="user" ref="user" /> -->
<!-- 会替代这部分代码,寻找容器中Class类型为User的Bean,调用构造器时进行注入 -->
<!-- 当出现多个匹配的Bean时,会使用设置为primary的Bean -->
<!-- 当出现多个标识primary的Bean,或者有多个没有设置primary的Bean的情况,就抛出异常,注入失败 -->
</bean>
</beans>
::: tip
这些基础性的知识,对于开发基于Spring的中间件,很重要
:::
字段方式注入
实现方式
- 手动模式
- 注解配置
- @Autowired
- @Resource
- @inject(JSR-330引入的新注解)
- 注解配置
手动模式代码示例
注解配置示例
public class Demo {
//====================核心代码====================
@Autowired
//按照byType的方式查找Bean
public User autoWiredUser;
@Autowired
//此处注入失败,@Autowire会忽略静态字段
public static User statisUser;
@Resource
//@Resource不填写bean名时,按照byType的方式查找Bean
public User resourceUser;
@Inject
//@Inject需单独引入JSR-330的jar包
public User injectUser;
//====================核心代码====================
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
//此处debug,即可看到demo对象的各个user字段是否被注入
Demo demo = applicationContext.getBean(Demo.class);
applicationContext.close();
}
/**
* 将User注入容器中
*/
@Bean
public User user() {
User user = new User();
return user;
}
}
方法注入
实现方式
- 手动模式
- 注解配置
- @Autowired
- @Resource
- @Inject
- @Bean
- 注解配置
手动模式
使用方法进行注入
public class Demo {
//====================核心代码====================
public User autoWiredUser;
public User resourceUser;
@Autowired
//参数名就是Bean名,找不到就按照byType的方式查找Bean
public void InitAutowiredUser(User autoWiredUser){
this.autoWiredUser = autoWiredUser;
}
@Resource
public void InitResourceUser(User resourceUser){
this.resourceUser= resourceUser;
}
//====================核心代码====================
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
//此处debug,即可看到demo对象的各个user字段是否被注入
Demo demo = applicationContext.getBean(Demo.class);
applicationContext.close();
}
/**
* 将User注入容器中
*/
@Bean
public User user() {
User user = new User();
return user;
}
}
感悟
加上了注解的方法,会在容器初始化时被执行,并且会带上Bean依赖信息,所以可以根据这种方式,对容器中的Bean进行各种操作
接口回调注入
实现方式
- Aware接口回调
- 自动模式
内建接口 | 说明 | 备注 |
---|---|---|
BeanFactoryAware | 获取IoC容器 - BeanFactory | |
ApplicationContextAware | 获取Spring应用上下文 - ApplicationContext对象 | |
EnvironmentAware | 获取Environment对象 | |
ResourceLoaderAware | 获取资源加载器对象 - ResourceLoader | |
BeanClassLoaderAware | 获取当前Bean Class的ClassLoader | |
BeanClassLoaderAware | 获取加在当前Bean Class的ClassLoader | |
BeanNameAware | 获取当前Bean的名称 | |
MessageSourceAware | 获取MessageSourceAware对象,用于国际化 | |
ApplicationEventPublisherAware | 获取ApplicationEventPublishAware对象,用于Spring事件 | |
EmbeddedValueResolverAwar | 获取StringValueResolver对象,用于占位符处理 |
都是内建的回调接口,暂时不能进行扩展
接口回调注入演示
BeanFactoryAware
和ApplicationContextAware
演示
public class Demo implements BeanFactoryAware,ApplicationContextAware{
//====================核心代码====================
private static BeanFactory beanFactory;
private static ApplicationContext context;
@Override
public void setBeanFactory(BeanFactory beanFactory){
Demo.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext){
Demo.context = applicationContext;
}
//====================核心代码====================
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
//此处打印BeanFactory和ApplicationContext,查看是否被回调注入
System.out.println(beanFactory == applicationContext.getBeanFactory);
System.out.println(context == applictionContext);
applicationContext.close();
}
注入选型
- 低依赖:构造器注入
- 多依赖:Setter方法注入
- 便利性:字段注入
- 声明类:方法注入
基础类型注入
- 原生类型(Primitive):八大类型
- 标量类型(Scalar):Number(包括子类,如Integer等包装类)、Character,Boolean、Enum、Locale、Charset、Currency、Properties、UUID
- 常规类型(General):Object、String、TimeZone、Calender、Optional等
- Spring类型:Resource、InputSource、Formatter等
详细会在类型转换小节研究
集合类型注入
- 数组类型(Array)
- 原生类型、标量类型、常规类型、Spring类型
- 集合类型(Collection)
- Collection:List、Set
- Map:Properties
XML中集合类型注入
<beans>
<bean class="UserManage">
<property name="userList" value="user1,user2" />
</bean>
</beans>
限定注入
- 使用@Qualifer限定
- 通过Bean名称限定
- 通过分组限定
- 基于@Qualifer扩展
- 自定义注解 - 如:@LoadBalanced
通过Bean名称限定注入配置示例
public class Demo {
//====================核心代码====================
@Autowired
@Qualifer("user1")
public User user3;
@Autowired
@Qualifer("user2")
public User user4;
//====================核心代码====================
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
//此处debug,即可看到demo对象的user3、user4字段被按照Bean名注入
Demo demo = applicationContext.getBean(Demo.class);
applicationContext.close();
}
/**
* 将User注入容器中
*/
@Bean
public User user1() {
User user = new User();
return user;
}
/**
* 将User注入容器中
*/
@Bean
public User user2() {
User user = new User();
return user;
}
}
通过分组限定配置示例
public class Demo {
//====================核心代码====================
@Autowired
//会查找所有User --- 两个user
public List<User> allUserList;
@Autowired
@Qualifer
//会按照Qualifer分组查找 -- 只有一个user2 被注入
public List<User> qualiferUserList;
//====================核心代码====================
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
//此处debug,即可看到demo对象的allUserList、qualiferUserList字段含有几个Bean
Demo demo = applicationContext.getBean(Demo.class);
applicationContext.close();
}
/**
* 将User注入容器中
*/
@Bean
public User user1() {
User user = new User();
return user;
}
/**
* 将User注入容器中
*/
@Bean
@Qualifer
public User user2() {
User user = new User();
return user;
}
}
自定义注解进行分组注入示例
@Qualifer
public @interface LoadBalanced{
//因为loadBalance继承了@Qualifer,所以使用@loadBalance也会注入Bean,、
//并且Bean会带上loadBalance的分组信息,此时就可以按照分组来注入
}
@Qualifer
public @interface QualiferGroup{
//同样的,可以自定义注解继承@Qualifer,实现自定义分组
}
public class Demo {
//====================核心代码====================
@Autowired
//会查找所有User --- 所有的三个user
public List<User> allUserList;
@Autowired
@Qualifer
//会按照Qualifer分组查找 -- 会有一个user2+一个user3,继承Qualifer的分组,也会被添加进来
public List<User> qualiferUserList;
@Autowired
@LoadBalance
//会按照LoadBalance分组查找 -- 只有一个user3
public List<User> loadBalanceUserList;
@Bean//注入普通user
public User user1() {
User user = new User();
return user;
}
@Bean//注入含Qualifer分组信息的user
@Qualifer
public User user2() {
User user = new User();
return user;
}
@Bean//注入含LoadBalance分组信息的user
@LoadBalance
public User user3() {
User user = new User();
return user;
}
//====================核心代码====================
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
//此处debug,即可看到demo对象的allUserList、qualiferUserList、loadBalanceUserList字段含有几个Bean
Demo demo = applicationContext.getBean(Demo.class);
applicationContext.close();
}
}
注解元素的继承,也叫注解元素的派生
延迟依赖注入
- API ObjectFactory延迟注入
- 单一类型
- 集合类型
- API ObjectProvider延迟注入
- 单一类型
- 集合类型
推荐使用ObjectProvider,Api更多,使用方法更灵活
ObjectProvider延迟注入示例
@Qualifer
public @interface LoadBalanced{
//因为loadBalance继承了@Qualifer,所以使用@loadBalance也会注入Bean,、
//并且Bean会带上loadBalance的分组信息,此时就可以按照分组来注入
}
@Qualifer
public @interface QualiferGroup{
//同样的,可以自定义注解继承@Qualifer,实现自定义分组
}
public class Demo {
//====================核心代码====================
@Autowired
public ObjectProvider<User> providerUser;
//@Autowired //ObjectFactory获取单个user
//public ObjectFactory<User> factorySingleUser;
//@Autowired //ObjectFactory获取多个user
//public ObjectProvider<List<User>> factoryListUser;
@Bean
public User user() {
User user = new User();
return user;
}
//====================核心代码====================
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
Demo demo = applicationContext.getBean(Demo.class);
User user = demo.providerUser.getObject();//可以获取一个标记为primary的User
demo.providerUser.foreach(System.sout::println)//可以获取注入的集合类型
applicationContext.close();
}
}
依赖处理过程
- 基础知识
- 依赖处理入口 - DefaultListableBeanFactory#resolveDependency
- 依赖描述符 - DependencyDescriptor
- 自动绑定候选对象处理器 - AutowireCandidateResolver
DefaultListableBeanFactory#resolveDependency
/**
* 2.5版本开始使用的两个重载方法作为基本的入口
* 2.5版本之前是用的处理入口?待考证
*/
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName)
/**
* @param descriptor 依赖描述符
* @param requestingBeanName 申请依赖注入的Bean(申请者)在容器中的名称
* @param autowiredBeanNames 用以处理注入的BeanName的Set集合
* @param typeConverter 类型转换器
*/
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter)
DependencyDescriptor.class
/**
* 存储依赖的描述信息
*
* 部分注入点的信息(注入的类型、方法参数、字段信息、注解信息)
* 4.3后,存储在{@link InjectionPoint}中
* 4.3之前,存储在{@link DependencyDescriptor} 中
*/
public class DependencyDescriptor extends InjectionPoint implements Serializable {
/**
* 申请注入操作的类(申请者)的类名
*/
private final Class<?> declaringClass;
/**
* 使用方法注入时的方法名称
* @Nullable 不使用方法注入时,允许为空
*/
@Nullable
private String methodName;
/**
* 使用方法/构造器注入时,方法/构造器参数的类型
* @Nullable 不使用方法/构造器注入时,允许为空
*/
@Nullable
private Class<?>[] parameterTypes;
/**
* 参数的索引位
*/
private int parameterIndex;
/**
* 使用字段注入时,被注入的字段名称
* @Nullable 不使用方法注入时,允许为空
* 以下三者必有其一不为空,否则没有注入的来源,会报错
* {@link DependencyDescriptor#methodName}
* {@link DependencyDescriptor#parameterTypes}
* {@link DependencyDescriptor#fieldName}
*/
@Nullable
private String fieldName;
/**
* 是否是必须的,默认为true
*/
private final boolean required;
/**
* 是否是饥饿的
* 为true时,必须存在需要注入的bean,否则就报错
* 为false时,相当于{@see Lazy}实现延迟加载、延迟注入
*/
private final boolean eager;
/**
* 嵌入层级
* ------
* 在NestedDependencyDescriptor中,会将嵌套层级+1,代表
* 目前我已知的
* 使用NestedDependencyDescriptor的地方有:
* - ObjectFactory.class
* - ObjectProvider.class
* - Optional<?>
* 使用MultiElementDescriptor extend NestedDependencyDescriptor 的地方有
* - array
* - Map.class
* - Collection.class.isAssignableFrom(type) && type.isInterface()
* 由此可见,此层级代表的是,需要注入Bean在数据结构中的层级
* 比如:@Autowrite private User; ==> nestingLevel = 1(顶层,无嵌套)
* 比如:@Autowrite List<User> userList; ==> nestingLevel = 2(依赖描述符发现是Collection的子接口,使用MultiElementDescriptor,层级加一)
* 比如:@Autowrite ObjectFactory<User> userObjectFactory; ==> nestingLevel = 2(依赖描述符使用NestedDependencyDescriptor,层级加一)
* 比如:@Autowrite ObjectFactory<List<User>> userListObjectFactory; ==> nestingLevel = 3(ObjectFactory的依赖描述符使用NestedDependencyDescriptor,发现内部是List,又使用MultiElementDescriptor作为依赖描述符,经历了两次嵌套层级加一,最终为3)
*/
private int nestingLevel = 1;
/**
* 申请处理依赖注入时的类名,通常和{@link DependencyDescriptor#declaringClass}是一个值,什么时候不一样?有待学习探查
*/
@Nullable
private Class<?> containingClass;
/**
* 泛型类型
*/
@Nullable
private transient volatile ResolvableType resolvableType;
/**
* 类型的描述符
* @see DependencyDescriptor 描述依赖的信息
* @see TypeDescriptor 描述泛型类型的信息
*/
@Nullable
private transient volatile TypeDescriptor typeDescriptor;
}
DependencyDescriptor 演示
public class Demo {
//====================核心代码====================
/**
* 此处生成的依赖描述符:DependencyDescriptor ->
* 申请注入的类:declaringClass = Demo.class
* 不是方法/构造器注入:methodName = null
* 不是方法/构造器注入:parameterTypes = null
* 参数索引位为默认0:parameterIndex = 0
* 字段名称:fieldName = userDesc
* 必须注入:required = true
* 实时注入:eager = true
* 嵌套层级为1:nestingLevel = 1
* 包含类:containingClass = Demo.class
* 没有泛型:resolvableType = null
* 泛型描述为null:typeDescriptor = null
* 不是方法/构造器注入:methodParameter = null
* 注入类的类型:field = User.class
* 没有设置注解:fieldAnnotations = null
* 使用位置{@link org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency(DependencyDescriptor , @Nullable String , @Nullable Set<String> , @Nullable TypeConverter )}
*/
@Autowired
public User userDesc;
/**
* 将User注入容器中
*/
@Bean
public User user() {
User user = new User();
return user;
}
//====================核心代码====================
public static void main(String[] args) {
// 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
applicationContext.close();
}
}
处理依赖的核心入口resolveDependency
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
/**
* 对Bean处理依赖的主要入口
*
* @param descriptor 依赖描述符
* @param requestingBeanName 请求注入bean的bean名称
* @param autowiredBeanNames 自动注入时指定的bean名称
* @param typeConverter 类型转换器
*/
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//在使用方法注入时,初始化参数探测器
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
//如果是Optional,则创建特殊的Optional包装
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
//如果是ObjectFactory/ObjectProvider这类延迟依赖,则创建延迟依赖处理器
//DependencyObjectProvider --> BeanObjectProvider --> ObjectProvider --> ObjectFactory,所以返回DependencyObjectProvider不会报错
else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
//Jsr330规范
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
//默认处理方法
else {
//默认返回null
//暂时不是很懂这一行的具体用处 - 从BeanFactory获取自动绑定候选对象处理器的延迟代理
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName);
if (result == null) {
//处理依赖的核心方法,业务程序大多数情况下使用的处理依赖的方法
//包括上方DependencyObjectProvider内延迟依赖获取数据时,也是使用的此方法获取真实依赖数据
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
/**
* 处理依赖的核心方法
* 根据依赖描述符、申请注入的Bean名称等信息,执行一系列操作,返回依赖对应的Bean实例
*/
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//处理嵌套多次注入的保护点,具体实际作用暂不清楚,待研究
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
//处理依赖的快捷方式,如果有快捷方式就返回,结束依赖处理
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType(); // <?>
//从自动绑定候选对象处理器中获取推荐的值:
//处理携带@Value时如何从配置文件中选取值的情况
//此情况时,if内的分析后续完善...
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
//处理注入类型为集合的情况,例如:@Autowrite private List<User> userList;
//存疑1待研究:内部有一个判断(Collection.class && isInterface) ==> 集合并且是接口,为什么要限制必须为接口?ArrayList就不当做集合处理了?
//存疑1部分理解:应用程序可能会真的需要一个ArrayList类型的Bean,此时如果按照元素类型而不是ArrayList类型来进行依赖查找并注入,肯定是一个不符合期望的结果。而interface和class,一个负责定义规则,一个负责具体实例化。Spring将interface作为注入多个Bean的规则,将class作为用户具体创建的Bean,也很符合逻辑,Spring真是将面向对象完全理解透了!
//存疑2待研究:Collection设计为Collection及其子类接口(Collection.class.isAssignableFrom(type))才按照元素类型注入,而Map为什么必须完全相等(Map.class == type)?
//存疑2部分理解:可能因为Map的结构特殊?或者更多的使用场景?实在没有头绪
//如果类型为集合,就会返回集合类型的Object
//使用descriptor.getDependencyType()判断类型
//方法内部候选类型:StreamDependencyDescriptor(Java 8 引入的) || isArray() || (Collection.class && isInterface) || Map.class ,都不匹配则返回null
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
//重点:使用申请注入Bean的bean名称、申请注入Bean的类型,依赖描述符,查找可以注入的候选者名单
//key为候选者的Bean名,value可能是Bean的Class信息,也可能是实例化的Bean
//注意!此方法需要后续再次复习,暂时没有理解内部方法的逻辑
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
//如果没有候选者,就判断下是否是必须注入的
//如果必须注入,就调用方法'raiseNoMatchingBeanFound()'抛出警告
//如果不是必须注入,就返回null,此时Bean的字段为null,外部直接使用会报空指针
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
//当有多个候选者时
if (matchingBeans.size() > 1) {
//从候选者中决定(determine)被注入者的bean名称
//内部会先判断是否有标记为primary的Bean(有多个primary则报错)
//再根据Bean的优先级获取,如果Bean没有继承OrderComparator或没有实现@Order注解,则返回null表示没有找到合适的Bean
//有多个优先级相同的Bean,则报错
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
//如果声明了必须注入,或者不是多个Bean类型(array、Collection、Map),则抛出NoUniqueBeanDefinitionException
//因为声明不必须,可以返回null。声明为多Bean(array、Map、<? extend Collection> && isInterface)类型,则不会走这段代码,会在上方的'resolveMultipleBeans'处理 <?>
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// 如果是可选的集合/映射,请忽略非唯一的情况:
// possibly it was meant to be an empty collection of multiple regular beans
// 它可能是多个普通Bean的空集合
// (before 4.3 in particular when we didn't even look for collection beans).
//(尤其是在4.3之前,我们甚至没有寻找收集bean集合)。
return null;
}
}
//从匹配的BeanMap中拿到需要注入的Bean
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
// 程序走到这,说明匹配的Bean只有一个,所以直接'.iterator().next();'拿到数据
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
//autowiredBeanNames 的用处暂时不是很懂,有待后续研究
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
//如果拿到的候选者value是一个Class,没有实例化,那就使用依赖描述符的获取候选者方法(执行getBean获取)返回Bean实例
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
//校验下是否是NullBean
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
//校验下拿到的类型和期望的类型是否匹配,不匹配就抛出BeanNotOfRequiredTypeException
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
//返回最终的实例Bean
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
}
处理过程解释一
在 AbstractApplicationContext#refresh#finishBeanFactoryInitialization 方法中,初始化所有还未初始化的 Bean(不是抽象、单例模式、不是懒加载方式)
通过 DefaultListableBeanFactory#preInstantiateSingletons 方法进行初始化,会通过 AbstractBeanFactory#getBean(beanName) 方法对每个 Bean 进行初始化
Bean 初始化的过程比较繁琐,大致过程如下:
-
先找到对应的 BeanDefinition 对象,然后会走到 AbstractAutowireCapableBeanFactory#createBean 方法,进行实例化、填充属性值、调用 Bean 的初始化方法
-
在填充属性值的过程,默认根据类型进行注入,那么在 AbstractAutowireCapableBeanFactory#autowireByType 的方法中会调用 DefaultListableBeanFactory#resolveDependency 方法进行注入,最后还是会通过 AbstractBeanFactory#getBean(beanName) 方法获取到需要注入的 Bean 对象
-
在填充属性值的时候也会通过 AutowiredAnnotationBeanPostProcessor 注入属性值,该注入增强器会对 @Autowired 或者 @Value 注解标注的属性进行注入,也是通过 DefaultListableBeanFactory#resolveDependency 方法进行注入。具体过程可看 AutowiredAnnotationBeanPostProcessor 的私有内部类 AutowiredFieldElement#inject 方法
处理过程解释二
DefaultListableBeanFactory#resolveDependency -->
1.判断是否懒加载–>doResolveDependency()
2.判断是否是多类型的bean resolveMultipleBeans()
3.根据类型查找匹配到的bean findAutowireCandidates()
4.bean个数大于1,选择bean即@Primary修饰 determineAutowireCandidate()
5.返回结果
零碎知识点
- 注入类型为Map<K,V>时,Spring默认实现是LinkedHashMap,含有顺序
@Autowired注入的规则与原理
注入过程
- 源信息解析
- 依赖查找
- 依赖注入(字段、方法)
::: tip 关键名词
RootBeanDefinition
:合并后,不可以再合并的根bean定义信息
PropertyValues
:从XML或者Annotation中获得的属性信息(字符、instance、数值等)
AbstractAutowireCapableBeanFactory
:注入处理的地方
InstantiationAwareBeanPostProcessor#postProcessProperties
:初始化结束后的回调接口,可以在此接口中修改Bean的属性
AbstractAutowireCapableBeanFactory#createBean
:创建Bean的方法
AbstractAutowireCapableBeanFactory#populateBean
:创建Bean得到实例后,为实例注入属性的方法(初始化阶段),也是此知识点最主要的方法
:::
源信息解析
- 需要知道Bean需要注入哪些东西->合并
BeanDefinition
拿到->遍历查找指定Class的字段、方法,并递归查找父类,查看需要注入些什么东西 - 如果携带(
@Autowrite
/@Resource
/@Value
/Class<? extends Annotation>
),则将Field
/Method
临时封装在InjectionMetadata
中,作为准备注入到Bean中的依赖元信息 - 解析(类型转换)成对应属性信息
PropertyValues
,buildAutowiringMetadata InjectionMetadata
在填充Bean属性时使用- 解析成
DependencyDescriptor
依赖查找
- 依赖处理
依赖注入(字段、方法)
处理过程解释一
1.在doCreateBean中会先调用applyMergedBeanDefinitionPostProcessors,后执行populateBean
所以会先调用postProcessMergedBeanDefinition后执行InstantiationAwareBeanPostProcessor的postProcessProperties。
2.postProcessProperties中有两个步骤:
(1)findAutowiringMetadata查找注入元数据,没有缓存就创建,具体是上一节内容。最终会返回InjectionMetadata,里面包括待注入的InjectedElement信息(field、method)等等
(2)执行InjectionMetadata的inject方法,具体为AutowiredFieldElement和AutowiredMethodElement的Inject方法
(2.1)AutowiredFieldElement inject具体流程:
(2.1.1)DependencyDescriptor的创建
(2.1.2)调用beanFactory的resolveDependency获取带注入的bean
(2.1.2.1)resolveDependency根据具体类型返回候选bean的集合或primary 的bean
(2.1.3)利用反射设置field
处理过程解释二
简单的说先合并BeanDefinition(因此存在继承关系所以需要合并父与子的BeanDefinition),合并好了之后就是要创建Bean,创建bean肯定要看看有没有配置什么字段需要注入->findAutowiringMetadata()。
但其实在合并BeanDefinition时候已经find过一次了,因为毕竟是BeanDefinition,元信息肯定是需要知道所有的,因此findAutowiringMetadata是有缓存的,所以postProcessProperties的findAutowiringMetadata其实查的是缓存。
那找到了需要的AutowiringMetadata之后肯定是要注入了,找到了结果叫InjectionMetadata,调用inject。inject步骤是先创建DependencyDescriptor,然后beanFactory.resolveDependency(DependencyDescriptor …),得到bean之后然后反射set字段
处理过程解释三
1.bean特殊实例化中讲过,通过AbstractAutowireCapableBeanFactory#createBean()–>doCreateBean()
2.AbstractAutowireCapableBeanFactory#doCreateBean()包括两部分
2.1 合并BeanDefinition处理操作,applyMergedBeanDefinitionPostProcessors()方法,最后调用AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition查找自动注入的元信息来封装注入元素信息即InjectionMetadata#checkedElements
2.2 填充bean的过程populateBean()方法1422行最后调用AutowiredAnnotationBeanPostProcessor#postProcessProperties方法分为两部分
2.2.1 查找自动注入元信息,findAutowiringMetadata()方法,缓存中存在则直接取不存在则构建
2.2.2 注入执行inject,具体为InjectionMetadata.InjectedElement的实现类AutowiredMethodElement的inject()方法,715通过依赖查找的方式来注入依赖即上一讲的DefaultListableBeanFactory的resolveDependency过程
处理过程解释四
先是找元信息然后进行注入:主要流程:AbstractAutowireCapableBeanFactory#createBean()–>doCreateBean()
1.调用applyMergedBeanDefinitionPostProcessors -> postProcessMergedBeanDefinition -> findAutowiringMetadata中找到该类中注解为Autowired、Value、Inject的字段、方法等
2.调用populateBean -> postProcessProperties,先调用findAutowiringMetadata找到待注入的元信息(比如user),然后调用metadata的inject方法,底层调用的是AutowiredFieldElement和AutowiredMethodElement的inject方法,
2.1 构造DependencyDescriptor(比如user)
2.2 调用beanFactory.resolveDependency获取待注入的bean(比如user),这里又是一轮的createBean(比如superUser不存在,则会创建)
2.3 获取后进行反射注入:field.set(bean, value)
注入部分的分析理应是在populationBean
中,但是applyMergedBeanDefinitionPostProcessors
中又有大量的设置Bean属性的知识点,虽然是Spring留给开发者的扩展点,但在Bean属性注入时,又有很重要的作用。
思来想去,还是决定从doCreateBean
开始分析,梳理applyMergedBeanDefinitionPostProcessors
和populationBean
的主要流程
创建Bean主要流程doCreateBean
源码解析
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
/**
* 实际创建指定的bean的方法
* 此时已经完成了创建(实例化)前的处理
* 可以进行Bean属性赋值前置操作、Bean创建、Bean属性赋值后置操作
*
* @param beanName Bean的名称
* @param mbd 因为Bean有继承(extend)关系(注解:extend Xxx,Xml:parent="xxx"),所以需要拿到合并<b>继承关系</b>后的BeanDefinition => {@Link RootBeanDefinition},这才有一个Bean需要注入的所有信息
* @param args 方法注入或者构造器注入时的参数
* @return 一个新的Bean实例
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
// Instantiate the bean.
// 实例化的Bean会先放在BeanWrapper中放着,最后再从BeanWrapper中取出来,类似代理?装饰者?
BeanWrapper instanceWrapper = null;
// 如果是单例,那就可以从缓存中拿
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
//缓存中没有数据,会使用反射拿到构造器创建Bean {@link Class#getDeclaredConstructor}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
// postProcessed:仅包内可见,判断MergedBeanDefinitionPostProcessor(BeanDefinition信息合并)流程是否被应用/使用过
if (!mbd.postProcessed) {
try {
// 执行所有的MergedBeanDefinitionPostProcessor,包含Spring自带的和用户自己添加的
// 业务开发时,通常不会自己实现MergedBeanDefinitionPostProcessor来扩展Spring
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
// 调用结束,设置合并流程已被调用过
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 有点重要,会涉及到Spring如何处理循环依赖
// 在创建Bean的初期,将Bean的早期引用放入缓存中
// 如果后续出现循环依赖,可以先拿引用缓存,保证Bean不会因为缺少依赖而不能实例化
// 这样,在初始化时就能拿到实例进行赋值
// 如果Bean是单例 ==> 默认单例
// 并且允许自动处理Bean之间的循环引用 ==> 默认允许
// 并且Bean处于实例化阶段 ==> createBean
// ==> 创建早期Bean引用并添加到缓存中 ==> addSingletonFactory
// Bean的缓存地点:
// ==> DefaultSingletonBeanRegistry#singletonFactories
// ==> DefaultSingletonBeanRegistry#registeredSingletons
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 主要方法:填充Bean中的属性,详细解析在下方
populateBean(beanName, mbd, instanceWrapper);
// 执行Bean初始化时的各种回调方法,方法内支持修改Bean的属性
// 暂不详细分析,到生命周期的文章中详细分析
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
//以下方法暂不分析,先专注在注入属性上
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
}
属性初始化流程populateBean
源码解析
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
/**
* 为了将Bean中定义的属性,创建Bean实例并填充到当前申请注入的Bean中
* 也就是付出实践了,从书面定义到实际添加
*
* @param beanName Bean的名称
* @param mbd Bean最终的定义信息 ==> RootBeanDefinition
* @param bw Bean的包装者,放着真正使用的Bean实例
*/
@SuppressWarnings("deprecation") // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 如果包装这Bean的包装者都为null,那还定义了有属性,null.setXxx?肯定得报错啊
// 但是什么情况下bw为null?粗略的看了下源码中的调用情况,发现传入时都不会为null。此处待研究。
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
// 一个扩展点:如果Bean实现了InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法,就会在这里回调,做自己想做的事。
// 打印日志?记录创建链路信息?修改Bean信息?都可以~
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 如果返回false,则结束整个初始化流程
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// 判断mdb中是否有注入信息,没有就返回null
// 一个小细节点:因为调用getPropertyValues时,没有属性就会触发初始化属性值的设置
// 所以避免错误初始化,使用hasPropertyValues判断
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 这一段的整体目的是,根据注入方式(AUTOWIRE_BY_NAME,AUTOWIRE_BY_TYPE),拿到注入的属性数据,并添加到PropertyValues 中
// 比如需要注入一个user,那这里就会PropertyValues中添加一个user-instance的映射关系
// ==> 当然,为了拿到user的instance,肯定也会触发doCreateBean和population,又递归到这里了
// 注意:此时并没有将属性注入到Bean中,而是将属性放到了psv里
// ==> 既然这个方法有bw,可以直接将属性设置到Bean中,但为什么不设置进去呢?
// ==> 因为Spring想给开发者更多的扩展点,扩展点就是下方的使用boolean hasInstAwareBpps的逻辑
// ==> 使开发者尽可能的在Bean的不同阶段,有控制/处理Bean的能力
// ==> 这里的控制能力,就是:在Bean真正赋值之前的开发自定义功能的能力
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 创建一个新的PropertyValues并集成旧PropertyValues中的值
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// 根据Bena名称拿到Bean的名称信息
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// 根据Bena类型拿到Bean的名称信息
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
// 难道最初这一段逻辑封装在一个方法里?所以会有创建了又赋值回来的操作?
pvs = newPvs;
}
// 判断Bean时候含有实例化时的前置/后置操作,默认是有的 ==> 注解驱动时是:AutowiredAnnotationBeanPostProcessor.class
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否需要进行依赖检查,查阅文章时发现,原来在3.0的时候就弃用了,代替者是构造器注入或者@Required,默认值为:DEPENDENCY_CHECK_NONE,不强制进行检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
// 通过上方的注入类型的判断可以知道,通过名称和类型注入时,psv都不会为空,那就只用使用构造器注入时回会为null,此时调用getPropertyValues()方法,初始化一下psv为空集合
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 重要流程:这里是Spring给开发者的扩展点,在Bean注入属性之前注入属性时的关键点
// Spring正是使用这个扩展点,执行真正注入属性的方法。沿用自身的设计逻辑,而不使用硬编码去注入信息,面向对象玩得很溜了
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 判断流程操作是不是初始化回调流程
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 进行强转
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 重点方法,一个扩展点,此处可以设置PropertyValues的值,PropertyValues全部设置好了,才进行最后的属性填充
// Spring在这里,通过BeanFactory查找与反射的方式,对Bean进行了属性的赋值
// 注意:经过Spring的默认流程处理,此时bw.getWrappedInstance()中的属性已经被赋值,这里返回的pvsToUse 是为了给后面的applyPropertyValues使用
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// 如果返回null,说明属性没有改变,继续调用已弃用的方法处理psv
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 5.1时弃用的方法,无论有没有更新,都返回新psv,如果要中断填充bean的流程,就返回null
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
// 暂不分析,我也不是很懂
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 拿到了需要注入的属性,开始真正应用这些值
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
/**
* 这是一个很重要的方法,但是涉及的东西太多了,暂时先不梳理,以后再回头来处理
* Apply the given property values, resolving any runtime references
* to other beans in this bean factory. Must use deep copy, so we
* don't permanently modify this property.
* @param beanName the bean name passed for better exception information
* @param mbd the merged bean definition
* @param bw the BeanWrapper wrapping the target object
* @param pvs the new property values
*/
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
if (writeMethod == null) {
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
}
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
}
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
}
InstantiationAwareBeanPostProcessor#postProcessProperties接口解释
/**
*
* 5.1时新增的回调方法,执行初始化回调方法,此时会提供以下信息给开发者,给开发者调整psv的能力
* 如果需要调整PropertyValues ,就返回调整后的PropertyValues
* 如果不需要调整PropertyValues,就返回null,将会调用旧版已弃用的方法
*
* InstantiationAwareBeanPostProcessor有两个默认实现
* ==> 实现一:CommonAnnotationBeanPostProcessor
* ==> 在@WebServiceRef、@EJB、@Resourcet这三种注入方式时会有对应回调
* ==> 实现二:AutowiredAnnotationBeanPostProcessor
* ==> 在@Autowired、@Value、@Inject这三种注入方式时会有对应回调
* 本次使用实现一:{@link AutowiredAnnotationBeanPostProcessor}来分析Bean在注入时的逻辑与规则,在下方进行详细解释
*
* @param pvs --- 待注入属性信息,第一次进入时的值为属性名:详见上方autowireByName和autowireByType
* @param bw.getWrappedInstance() --- 最终会返回的真实Bean
* @param beanName --- Bean的名称
*/
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
注解形式的自动注入,在填充PropertiesValues时的实现
注解形式的自动注入AutowiredAnnotationBeanPostProcessor
对InstantiationAwareBeanPostProcessor#postProcessProperties
的实现
扩展知识点:Java方法桥接
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
/**
* 注解形式的自动注入,会使用反射的形式,遍历Bean的字段和方法,查找哪些地方需要填充Bean实例
* 但是会将具体逻辑委托给InjectionMetadata.InjectedElement去实现
* 因为支持字段和方法的@Autowrite,所以InjectionMetadata.InjectedElement有两个实现
* 实现一:{@link AutowiredFieldElement} 字段级别的注入信息
* 实现二:{@link AutowiredMethodElement} 方法级别的注入信息
* 两个实现的逻辑差别不大,此处使用{@link AutowiredFieldElement}进行详细分析
* 构造器级别的注入,在另一个生命周期注入,暂不在此方法处理
*
* @param pvs 暂存属性值的对象
* @param bean 待填充属性的Bean对象
* @param beanName Bean的名称
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 因为注解写在类上,所以方法内部使用Bean的class信息寻找Bean所需的参数,
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 重点方法:将得到的pvs委派给InjectionMetadata去处理
// 下方会单开一个代码块展开梳理里面的逻辑
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
// 将最终的pvs返回
return pvs;
}
/**
* 寻找Class上标注的,需要注入的参数
*
* @param beanName Bean的名称
* @param clazz Bean对应的class信息
* @param pvs 暂存属性值的对象
*/
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
// 该方法使用类名作为缓存Key,以此兼容自定义调用者?不太懂这个兼容,待研究
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
// 先从缓存中取该类的注入信息,加快寻找速度(反射速度慢)
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
// 判断是否需要刷新缓存中的信息:根据名称获取的Class信息
// 如果一个Class和一个Bean名冲突,就会得到错误的缓存信息
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
// 对整个缓存池加锁,防止读写了脏数据
synchronized (this.injectionMetadataCache) {
// 加锁二次读取缓存,解决并发读取缓存出现缓存访问不到的情况
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
// 需要刷新就先清除再添加
metadata.clear(pvs);
}
// 重点方法:下方会展开解释,使用class信息构造注入元信息
metadata = buildAutowiringMetadata(clazz);
// 将查到的信息放入缓存中
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
// 返回找到的所有依赖信息
return metadata;
}
/**
* autowiredAnnotationTypes:当前类{@AutowiredAnnotationBeanPostProcessor}的一个重要字段
* autowiredAnnotationTypes:用做判断字段/方法是否要进行依赖注入
* 同样的,也可以往autowiredAnnotationTypes中添加自定义注解,达到扩展Spring的目的
* autowiredAnnotationTypes默认存储以下值,
* ==> Autowired.class
* ==> Value.class
* autowiredAnnotationTypes的初始化在{@link AutowiredAnnotationBeanPostProcessor#AutowiredAnnotationBeanPostProcessor()}无参构造器中
*/
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
/**
* 根据class信息,构建注入元信息
* 注入元素:需要注入的字段/方法
* 注入元信息:封装了所有的注入元素,为了给外部使用的
*
* @param clazz 待解析的class信息
*/
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
// 这个方法把我看懵了,我以为是判断class上有没有this.autowiredAnnotationTypes对应的注解
// 结果里面判断class和this.autowiredAnnotationTypes是不是java.开头,为什么这么判断?待研究
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
// 最终返回出去的元信息数组
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
// 当前判断的class信息,因为下面要开始递归判断类信息了
Class<?> targetClass = clazz;
do {
// 当前循环的注入元素列表,存储当前循环时得到的注入元素
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 使用反射遍历当前类中的所有DeclaredFields(属于当前类声明的字段),此时是用反射获取类字段信息,所以有顺序
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 会判断当前字段上有没有autowiredAnnotationTypes中包含的注解信息
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
//判断字段是否是静态的,静态字段直接return,不支持静态字段的注入
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
// 判断注解是否有required字段,没有则返回true,有字段,则返回对应的true/false
boolean required = determineRequiredStatus(ann);
// 创建注入元素(AutowiredFieldElement)并添加到当前循环的元信息列表
currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
}
});
// 使用反射遍历当前类中的所有DeclaredMethods(当前类声明的方法)
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// 判断方法是否是桥接方法,如果不是桥接方法,则进行下面的处理,如果是桥接方法,则我没看懂...待研究
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// 判断方法是否含有this.autowiredAnnotationTypes中的注解
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
// 如果是静态方法,就return,不支持静态方法的注入
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
// 方法注入理解不深
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
// 判断注解是否有required字段,没有则返回true,有字段,则返回对应的true/false
boolean required = determineRequiredStatus(ann);
// 寻找方法的属性描述符
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// 创建注入元素(AutowiredMethodElement)并添加到当前循环的注入元素列表
currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));
}
});
// 将本地存储的元素数组,放到当前类整体的元素数组中
elements.addAll(0, currElements);
// 切换判断目标为当前类的父类
targetClass = targetClass.getSuperclass();
}
// class为Object时,退出循环
while (targetClass != null && targetClass != Object.class);
// 将注入元素(InjectedElement)封装成注入元信息(InjectionMetadata)并返回给外部使用
return InjectionMetadata.forElements(elements, clazz);
}
}
上面梳理了创建注入信息的流程,接下来看看AutowiredAnnotationBeanPostProcessor
拿到了注入元信息后,是怎么将注入元信息与PropertiesValues关联起来的
注入元信息源码解析InjectionMetadata#inject
/**
* 注入元信息的顶层类
*/
public class InjectionMetadata {
/**
* postProcessProperties调用此方法时,会将
*
* @param target 注入信息的目标类
* @param beanName Bean的名称
* @param pvs 注入属性值
*/
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 此处的checkedElements ,就是InjectionMetadata.forElements(elements, clazz)时的elements
// ==> 创建InjectionMetadata时,会将elements赋值给内部的injectedElements属性
// ==> 在调用`checkConfigMembers`方法时,会将injectedElements赋值给checkedElements
Collection<InjectedElement> checkedElements = this.checkedElements;
// 如果没有调用`checkConfigMembers`方法,checkedElements 为空,依然会使用injectedElements参数来遍历处理
Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements);
// 开始遍历内部的注入元素
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
// 每个元素执行`inject`方法,处理对应的元素
// ==> 此处使用子类`AutowiredFieldElement`来展开梳理
// ==> 子类`AutowiredMethodElement`的整理逻辑异曲同工
element.inject(target, beanName, pvs);
}
}
}
}
前置知识点:注册Bean与Bean依赖关系 DefaultSingletonBeanRegistry 的registerDependentBean()方法对属性注入
字段注入AutowiredFieldElement
主要方法解析
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
/**
* Class representing injection information about an annotated field.
* 注解字段的类注入信息
*/
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
// 对应@Autowrite的required属性
private final boolean required;
// 判断字段注入元素中的信息是否创建了缓存
private volatile boolean cached = false;
// 字段注入元素对应的缓存信息
@Nullable
private volatile Object cachedFieldValue;
// 初始化一下默认值
public AutowiredFieldElement(Field field, boolean required) {
super(field, null);
this.required = required;
}
/**
* 该类的主要职责,根据注入元素信息,获取元素实例
* 注册Bean与Bean依赖关系:<a href="https://blog.csdn.net/Leon_Jinhai_Sun/article/details/109782537">DefaultSingletonBeanRegistry 的registerDependentBean()方法对属性注入</a>
* 整个方法通过存储的字段信息,直接生成依赖描述符去BeanFactory中查询是否有对应的Bean
* 其实忽略了传入的pvs,不对pvs修改也不使用,为什么忽略?有待研究
*
* @param bean 需要注入信息的Bean
* @param beanName Bean的名称
* @param pvs 从外部或内部定义的属性信息
*/
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// this.member里存的是,通过反射拿到的字段信息
Field field = (Field) this.member;
Object value;
// 如果有缓存,就从缓存中拿数据
if (this.cached) {
// 因为会有required = false 的情况,所以缓存里会存储依赖描述符(下方有介绍:AutowiredAnnotationBeanPostProcessor.ShortcutDependencyDescriptor)
// ==> 如果是依赖描述符,就触发一次依赖处理(beanFactory.resolveDependency)
// ==> 如果不是以来描述符,就直接返回缓存值
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
// 使用字段信息创建一个依赖描述符
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
// 设置此依赖的包含Bean ==> 指定这个依赖在申请注入的Bean中
desc.setContainingClass(bean.getClass());
// 此处不懂实际用处,待研究
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
// 要使用BeanFactory来查找Bean,所以得判断BeanFactory是否存在
Assert.state(beanFactory != null, "No BeanFactory available");
// 获取类型转换器,处理类似String==>Bean的情况
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
// 进行一次依赖处理,和上方的知识点串起来了,resolveDependency根据依赖描述符获取一个Bean
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
// 对当前Bean加锁
synchronized (this) {
// 如果当前没有缓存
if (!this.cached) {
// 找到了value 或者 必须注入的情况
if (value != null || this.required) {
// 就把当前的依赖描述符当做缓存值放着
this.cachedFieldValue = desc;
// 将Bean与Bean依赖关系注册到注册器中
registerDependentBeans(beanName, autowiredBeanNames);
// 如果只有一个依赖项
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
// 判断BeanFactory中是否含有此Bean,Bean的类型是否和需要的类型匹配
if (beanFactory.containsBean(autowiredBeanName) && beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
// 是需要的Bean,则创建依赖的快捷访问方式,并设置为缓存值
this.cachedFieldValue = new AutowiredAnnotationBeanPostProcessor.ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType());
}
}
}
else {
// 没有找到value时,缓存值为null
this.cachedFieldValue = null;
}
// 切换缓存状态为true,下次再对这个依赖元素判断时,可以取缓存中的值
this.cached = true;
}
}
}
// 如果依赖处理时拿到了Bean,就使用反射的方法对Bean设置值,到了这里,我们的Bean才注入了一个依赖
if (value != null) {
ReflectionUtils.makeAccessible(field);
// 为了走到这一步简直太太太太不容易了!
field.set(bean, value);
}
}
}
JSR-330 @inject注入
注入过程
当classpath中含有JSR-330时,复用AutowiredAnnotationBeanPostProcessor
的注入流程
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
/**
* 很重要的一个类型集合,只有这个集合内的注解才可以使用这个依赖注入流程
* 使用LinkedHashSet,所以有序,当同一个字段使用多个注入注解时,使用Set中的第一个匹配的注解信息来处理依赖注入
*/
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
/**
* autowiredAnnotationTypes的初始化在构造器中
* 默认添加了Autowired和Value
* 需要存在javax.inject.Inject时,才能使用@Inject注解进行依赖注入
* 同样的,也可以使用往autowiredAnnotationTypes中增加自定义注解,来扩展可注入的类型
*/
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
/**
* 寻找依赖注入的注解信息
* 在整个流程中常用的判断,用来获取字段、方法上的注入注解信息,如果没有autowiredAnnotationTypes中的注解,将不会处理依赖注入
*
* @param ao 访问的信息
*/
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao);
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
}
}
Java通用注解:@Resource和@EJB
注入注解,作用类似@Autowired
- @WebServiceRef
- @EJB
- @Resource
生命周期注解,作用类似于BeanPostProcessors
- @PostConstruct
- @PreDestroy
Bean的实例化周期执行顺序为
- @PostConstruct > InitializeBean > 自定义初始化方法
Bean的销毁周期执行顺序为
- @PreDestroy > DisposableBean > 自定义销毁方法
以上知识点在Spring中的实现,由CommonAnnotationBeanPostProcessor
实现,且整体实现逻辑和AutowiredAnnotationBeanPostProcessor
差不多,以下摘出部分主要不同点来梳理
/**
* Java 通用注解的生命周期实现类
*/
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
/**
* 在构造器中,设置了生命周期初始化与销毁的注解
* 排序值覆盖 -3
* AutowiredAnnotationBeanPostProcessor 默认 - 2
*/
public CommonAnnotationBeanPostProcessor() {
// 值得注意的是,order值继承于InitDestroyAnnotationBeanPostProcessor
// InitDestroyAnnotationBeanPostProcessor的排序值默认为最低
// 但CommonAnnotationBeanPostProcessor将排序值覆盖为(最低-3),也就是倒数第四位执行
// 而AutowiredAnnotationBeanPostProcessor将排序值默认为(最低-2),也就是倒数第三位执行
// 说明CommonAnnotationBeanPostProcessor相关的生命周期方法将会优先于AutowiredAnnotationBeanPostProcessor执行
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
// 可以通过替换以下两个注解来自定义扩展,但是不推荐
// 因为这个类是专为Java通用注解做的适配,想自定义推荐使用AutowiredAnnotationBeanPostProcessor进行扩展
// 设置初始化周期的注解为@PostConstruct
setInitAnnotationType(PostConstruct.class);
// 设置销毁周期的注解为@PreDestroy
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
}
/**
* CommonAnnotationBeanPostProcessor继承了这个生命周期类
* 可以从这里看到相关方法定义与设计的细节
*/
public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
/**
* CommonAnnotationBeanPostProcessor构造器里设置的初始化生命周期注解将会存在这里
*/
@Nullable
private Class<? extends Annotation> initAnnotationType;
/**
* CommonAnnotationBeanPostProcessor构造器里设置的销毁生命周期注解将会存在这里
*/
@Nullable
private Class<? extends Annotation> destroyAnnotationType;
/**
* 生命周期排序值默认最低,放在最后处理
* 但是CommonAnnotationBeanPostProcessor将这个值改成了Ordered.LOWEST_PRECEDENCE - 3
*/
private int order = Ordered.LOWEST_PRECEDENCE;
/**
* 处理合并BeanDefinition的地方
* 通用注解使用LifecycleMetadata存储注入元素信息
* 而@Autowired使用的InjectionMetadata存储元素信息
* 通用注解比@Autowrite多了生命周期相关的逻辑,详细看下方
*/
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = findLifecycleMetadata(beanType);
metadata.checkConfigMembers(beanDefinition);
}
/**
* 这是一个内部类
* LifecycleMetadata相比InjectionMetadata,增加了生命周期相关的东西
*/
private class LifecycleMetadata {
/**
* 目标Class信息
*/
private final Class<?> targetClass;
/**
* 初始化方法
*/
private final Collection<LifecycleElement> initMethods;
/**
* 销毁方法
*/
private final Collection<LifecycleElement> destroyMethods;
/**
* 经过checkConfigMembers方法的调用
* checkedInitMethods会等于initMethods
* 暂不明白为什么这么设计,待研究
*/
@Nullable
private volatile Set<LifecycleElement> checkedInitMethods;
/**
* 经过checkConfigMembers方法的调用
* checkedDestroyMethods会等于destroyMethods
* 暂不明白为什么这么设计,待研究
*/
@Nullable
private volatile Set<LifecycleElement> checkedDestroyMethods;
}
/**
* 继续看InitDestroyAnnotationBeanPostProcessor相关的方法细节
* 现在看一个和{@link AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata}很类似的方法{@link InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata}
* <b>buildAutowiringMetadata</b>是为了构建依赖注入时的元信息
* <b>buildLifecycleMetadata</b>是为了构建依赖注入时的生命周期信息
*
* 再次提示:CommonAnnotationBeanPostProcessor继承于InitDestroyAnnotationBeanPostProcessor
* 于此同时:CommonAnnotationBeanPostProcessor并没有对InitDestroyAnnotationBeanPostProcessor的方法进行很多的重写
* 所以现在研究InitDestroyAnnotationBeanPostProcessor等同于分析CommonAnnotationBeanPostProcessor
*/
private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
/**
* 判断方法上是否有指定的注解
*/
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
}
// 整体的,最终会返回的初始化和销毁方法
List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> initMethods = new ArrayList<>();
List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> destroyMethods = new ArrayList<>();
// 由于涉及到循环寻找父类,所以targetClass代表当前循环时判断的类信息
Class<?> targetClass = clazz;
do {
final List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currInitMethods = new ArrayList<>();
final List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currDestroyMethods = new ArrayList<>();
// 由于生命周期回调是针对方法的,所以和`buildAutowiringMetadata`不同
// 这里使用反射,只查看方法上是否有指定注解
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// 如果携带了初始化注解
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
// 使用反射得到的方法构造LifecycleElement存储回调函数
InitDestroyAnnotationBeanPostProcessor.LifecycleElement element = new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method);
// 将回调函数放入当前循环的列表中
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
// 这里有一个细节点,当判断方法携带了初始化注解时,不会直接continue,而是会继续看是否有销毁注解
// 所以可以对同一个方法同时标注初始化与销毁注解
}
// 如果携带了销毁注解
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
// 使用反射得到的方法构造LifecycleElement存储回调函数
currDestroyMethods.add(new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
// 这里又是一个细节点,代表父类的回调函数会优先于子类的执行
// ==> 调用的是addAll(int index, Collection<? extends E> c);会从index位置开始插入
// ==> 而不是addAll(Collection<? extends E> c);会添加到列表尾部
initMethods.addAll(0, currInitMethods);
// 销毁方法则不同,是添加到了尾部
// 最终的调用的流程就会呈现为父类初始化 -> 子类初始化 -> 子类销毁 -> 父类销毁
// 这么一想很有道理了,父类包着子类,像两个同心圆一样
destroyMethods.addAll(currDestroyMethods);
// 切换判断的class
targetClass = targetClass.getSuperclass();
}
// 当类为Object时,停止循环
while (targetClass != null && targetClass != Object.class);
// 没有数据就返回空的默认实现,有就合成LifecycleMetadata返回出去
return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata : new InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata(clazz, initMethods, destroyMethods));
}
}
CommonAnnotationBeanPostProcessor
与AutowiredAnnotationBeanPostProcessor
整体的设计思路是一致的,代码复用性极强,并且还做了生命周期的扩展。
最简化自定义依赖注入注解
如何使用自定义注解,实现依赖注入?
方向一:基于AutowiredAnnotationBeanPostProcessor
实现
- 方案一:元标注
@Autowired
- 方案二:扩展容器内的
AutowiredAnnotationBeanPostProcessor
方向二:自定义类实现生命周期接口
需要实现以下接口并在Bean实例化之前,注册到AbstractBeanFactory
中
- 生命周期
- InstantiationAwareBeanPostProcessor
- MergedBeanDefinitionPostProcessor
- 元数据
- InjectedElement
- InjectionMetadata
方案一:元标注@Autowired
/**
* 通过对自定义注解进行元标注@Autowired的方式实现自定义注解
* 其实在限定注入内容里,就介绍了@Qualifer和@LoadBalance的实现原理,也是因为元标注了@Autowired
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Autowired
public @interface MateInject {
/**
* 因为注解不能继承,所以这里显示定义一个required
* 当然,不显示定义也可以,在上面的梳理中解释了
* 在{@link AutowiredAnnotationBeanPostProcessor#determineRequiredStatus}的判断中,如果没有这个字段,就代表为true
*/
boolean required() default true;
}
这时候直接使用这个注解,就能实现依赖注入了,就那么简单~
方案二:扩展容器内的AutowiredAnnotationBeanPostProcessor
/**
* 首先创建一个自定义的注解
* 和@Autowired没什么关系
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomInject {
}
public class Demo {
/**
* 使用静态方法,注入一个`AutowiredAnnotationBeanPostProcessor`当做生命周期流程Bean
* 这时候@Bean的name字段有两种选择
* ==> 选择一:使用{@link AnnotationConfigUtils#AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME}
* ==> 这时候Spring默认的`AutowiredAnnotationBeanPostProcessor`将不会注入,只能处理方法内定义的注解
* ==> 选择二:使用自定义名称(不等于上方特殊字段的值),这时将只做扩展,不会影响Spring默认的注入规则
* 通常使用选择二,只对Spring做扩展
*/
@Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME) // 选择一
@Bean(name = "InjectUserBeanPostProcessor") // 选择二
/**
* 使用@order,可以控制注入流程的执行顺序
*/
@Order(Ordered.LOWEST_PRECEDENCE - 4)
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
// 可以单独设置一个注解为注入注解
beanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
// 也可以通过传入一个Set设置多个注解为注入注解,是否需要有序看自己需求了
Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(asList(CustomInject.class));
beanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
// 返回自定义依赖注入流程
return beanPostProcessor;
}
}
一点问题
有多少种依赖注入的方式
- 构造器注入
- 字段注入
- Setter注入
- 方法注入
- 接口回调注入
偏好构造器注入还是字段注入?
- 没有最好,只有相对合理
- 两种都可以,强制依赖推荐构造器注入,可选依赖推荐字段注入
为什么有的Bean无法通过依赖查找获取,但能通过依赖注入获取?
- Spring 注入来源问题
- 突破点:依赖查找使用
getBean
操作,依赖注入使用resolveDependency
操作 - 待续…
评论区