前言
之前我写过一篇关于BeanDefinition的文章,讲述了各个属性的作用,其中有一个属性我没有提到,因为这个属性比较重要,所以这里单独开一篇文章来说明
上一篇博文链接Spring之BeanDefinitionhttps://blog.csdn.net/qq_38257958/article/details/134823169?spm=1001.2014.3001.5501
再探AbstractBeanDefinition源码
通过源码我们得出结论,注入类型有四种
- AUTOWIRE_NO (0)
- AUTOWIRE_BY_NAME (1)
- AUTOWIRE_BY_TYPE (2)
- AUTOWIRE_CONSTRUCTOR (3)
PS : 实际有五种,AUTOWIRE_AUTODETECT已过期,我们暂不讨论
默认情况下的注入模型
代码准备
创建配置类AppConfig
package com.test.model.config;import org.springframework.context.annotation.ComponentScan;@ComponentScan("com.test.model")
public class AppConfig {}
创建一个普通bean
package com.test.model.component;import org.springframework.stereotype.Component;@Component
public class MixComponent {}
创建一个BeanFactoryPostProcessor(后面简称bfpp)
package com.test.model.bfpp;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;@Component
public class AutowireBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) registry.getBeanDefinition("mixComponent");int autowireMode = beanDefinition.getAutowireMode();System.out.println(autowireMode);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}
创建启动类
package com.test.model;import com.test.model.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);}
}
运行main方法,查看运行结果
结论 : 默认的注入模型是0 (AUTOWIRE_NO)
默认情况下的依赖注入
创建三个普通bean
@Component
public class ComponentA {
}@Component
public class ComponentB {
}@Component
public class ComponentC {
}
依赖注入
package com.test.model.component;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class MixComponent {@Autowiredprivate ComponentA componentA;private ComponentB componentB;private ComponentC componentC;@Autowiredpublic void setComponentB(ComponentB componentB) {this.componentB = componentB;}public MixComponent() {}@Autowiredpublic MixComponent(ComponentC componentC) {this.componentC = componentC;}
}
默认情况下的依赖注入的三种方式
- 属性注入
- setter注入
- 构造器注入
运行main方法,查看运行结果
byName情况下的依赖注入
通过bfpp修改注入模型
package com.test.model.bfpp;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;@Component
public class AutowireBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) registry.getBeanDefinition("mixComponent");// 将注入模型改为byNamebeanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}
改造MixComponent
package com.test.model.component;import org.springframework.stereotype.Component;@Component
public class MixComponent {// 没有Autowired注解private ComponentA componentA;// 没有Autowired注解private ComponentB componentB;// 没有Autowired注解private ComponentC componentC;public void setComponentA(ComponentA componentA) {this.componentA = componentA;}public void setComponentB(ComponentB componentB) {this.componentB = componentB;}public void setComponentC(ComponentC componentC) {this.componentC = componentC;}
}
运行main方法,查看运行结果
源码解析
AbstractAutowireCapableBeanFactory#populateBean
AbstractAutowireCapableBeanFactory#autowireByName
AbstractAutowireCapableBeanFactory#unsatisfiedNonSimpleProperties
unsatisfiedNonSimpleProperties方法大概分为两个步骤
- 利用Spring的内省机制获取pds
- 判断这个pd是否符合条件
- 判断pd是否存在writeMethod
- 判断pd的propertyType是不是需要忽略的类
- pvs是否已存在相同name的值
- propertyType是不是普通类
我来解释一下pd需要满足的四个条件
条件1
package com.test.model.component;import org.springframework.stereotype.Component;@Component
public class Demo1 {public Object getAbc() {return null;}public void setAbc(Object abc) {}public Object getXyz() {return null;}public void setXyz(Object xyz) {}
}
不管我们是不是真实存在abc、xyz这样的属性,只要类中存在setXxx或者getXxx这样的方法,我们就认为类中存在一个名称为xxx的属性
PS : 我测试了一下,setXxx方法只能存在一个参数
条件2
比如bean实现了xxxAware接口,其相应的实现方法会被过滤掉
相关源码
AbstractApplicationContext#prepareBeanFactory
PS : 可能还有其他地方也添加了相关接口,debug的时候不止这几个
条件3
package com.test.model.bfpp;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;@Component
public class Demo1FactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {AbstractBeanDefinition b2 = (AbstractBeanDefinition) registry.getBeanDefinition("demo1");b2.getPropertyValues().add("abc", new Object());}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}
我们可以手动给指定bean的属性设置值,那样就不会在Spring容器中查找符合条件的bean了。
条件4
Spring定义的普通类
byType情况下的依赖注入
byType和byName类似 主要就是根据参数类型从Spring中查找符合条件的bean,主要关注unsatisfiedNonSimpleProperties方法
测试发现一个有意思的情况,下方代码在byName的情况下会错,在byType的情况下会正确注入
package com.test.model.component;import org.springframework.stereotype.Component;@Component
public class Demo2 {private ComponentC componentC;public void setComponentA(ComponentC componentC) {this.componentC = componentC;}
}
构造器注入
相关源码AbstractAutowireCapableBeanFactory#createBeanInstance
构造器注入并非只有注入模型是AUTOWIRE_CONSTRUCTOR才会执行构造器注入的逻辑,另外三个条件如果满足其一也会执行构造器注入,这里我用代码演示其他三种情况
具体细节可以看我之前写的博文Spring之推断构造方法https://blog.csdn.net/qq_38257958/article/details/134957631?spm=1001.2014.3001.5501
ctors != null的几种情况
package com.test.model.component;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class Demo3 {/*** case1:有且仅有一个有参构造方法*/private ComponentA componentA;public Demo3(ComponentA componentA) {this.componentA = componentA;}/*** case2:有且仅有一个@Autowired(required = true)标注的构造方法*/private ComponentB componentB;private ComponentC componentC;@Autowired(required = true)public Demo3(ComponentB componentB) {this.componentB = componentB;}public Demo3(ComponentC componentC) {this.componentC = componentC;}/*** case3:有多个@Autowired(required = false)标注的构造方法*/@Autowired(required = false)public Demo3(ComponentB componentB) {this.componentB = componentB;}@Autowired(required = false)public Demo3(ComponentC componentC) {this.componentC = componentC;}
}
mbd.hasConstructorArgumentValues()
package com.test.model.component;import org.springframework.stereotype.Component;@Component
public class Demo4 {private ComponentB componentB;private ComponentC componentC;public Demo4(ComponentB componentB) {this.componentB = componentB;}public Demo4(ComponentC componentC) {this.componentC = componentC;}
}
package com.test.model.bfpp;import com.test.model.component.ComponentB;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;@Component
public class Demo4FactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) registry.getBeanDefinition("demo4");// 指定构造器Demo4(ComponentB componentB)beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,new ComponentB());}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}
!ObjectUtils.isEmpty(args)
package com.test.model.component;import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;@Component
@Lazy
public class Demo5 {private ComponentB componentB;private ComponentC componentC;public Demo5(ComponentB componentB) {this.componentB = componentB;}public Demo5(ComponentC componentC) {this.componentC = componentC;}
}