一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 5 天,点击查看活动详情
日积月累,水滴石穿 😄
前言
我们前面几篇已经将 bean的实例化、寻找 bean 注入点分析完了。可以知道如果不是通过构造方法进行属性赋值的话,那实例化的对象中的属性的值都是 null ,所以这篇我们来看看 Spring是如何给对象中的属性赋值的。
populateBean
方法位于 AbstractAutowireCapableBeanFactory类。
populateBean 方法传入三个参数:
- beanName:bean名称
- mdb:当前bean的定义
- bw:当前实例的包装对象
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 没有实例化对象
if(bw == null) {
// 如果有为此bean定义属性值,则抛出异常
if(mbd.hasPropertyValues()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Cannot apply property values to null instance");
} else {
//直接返回,结束该方法
return;
}
}
// 可以提供InstantiationAwareBeanPostProcessor,控制对象的属性注入
// 我们可以自己写一个InstantiationAwareBeanPostProcessor,然后重写
// postProcessAfterInstantiation方法返回false
// 那么则不会进行属性填充了,直接返回
//isSynthetic():bena 不是"合成"的,即未由应用程序本身定义
// 是否持有 InstantiationAwareBeanPostProcessor
if(!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for(BeanPostProcessor bp: getBeanPostProcessors()) {
if(bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (
InstantiationAwareBeanPostProcessor) bp;
// postProcessAfterInstantiation:实例化后,该方法默认返回true
// 如果我们实现InstantiationAwareBeanPostProcessor,
// 然后重写postProcessAfterInstantiation方法返回false
// 将会阻止 Bean 的属性填充
if(!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(),
beanName)) {
return;
}
}
}
}
// 是否在BeanDefinition中设置了属性值
// xml中 property 属性的解析
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() :
null);
// autowire属性
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 这里取的是xml中 autowire 属性配置的值 如果是byType(2)、byName(1),就会进入这段逻辑
// 如果是使用 @Autowired,resolvedAutowireMode的值为 0
if(resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode ==
AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// byName
if(resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
//byType
if(resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
// by_name是根据set方法名字找bean
// by_type是根据所对应的set方法的参数类型找bean
// 找到bean之后都要调用set方法进行注入
// 注意,执行完这里的代码之后,这是把属性以及找到的值存在了pvs里面,并没有完成反射赋值
}
// 执行完了Spring的自动注入之后,就开始解析@Autowired、@Resource、@Value 等等注解
// 是否有InstantiationAwareBeanPostProcessor
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否进行依赖检查,默认不进行依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition
.DEPENDENCY_CHECK_NONE);
// @Autowired、@Value注解被AutowiredAnnotationBeanPostProcessor处理解析
// @Resource 注解被CommonAnnotationBeanPostProcessor处理解析
//这个两个类都是 InstantiationAwareBeanPostProcessor 接口的具体实现
PropertyDescriptor[] filteredPds = null;
if(hasInstAwareBpps) {
if(pvs == null) {
pvs = mbd.getPropertyValues();
}
for(BeanPostProcessor bp: getBeanPostProcessors()) {
if(bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (
InstantiationAwareBeanPostProcessor) bp;
// 调用BeanPostProcessor分别解析@Autowired、@Resource、@Value 等等注解,得到属性值
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(),
beanName);
if(pvsToUse == null) {
if(filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd
.allowCaching);
}
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) {
// pvs存的就是属性已经对应的值
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
我们先来看一下autowireByName方法,根据byName寻找 Bean。
autowireByName 装配
准备一个 B 类,类中提供 setOrder方法、setORder方法还有一个OrderService属性。
public class B {
OrderService orderService;
public void setOrder(OrderService order){
System.out.println("setOrder = " +order);
}
public void setORder(OrderService order){
System.out.println("setORder = " + order);
}
}
public class OrderService {
}
//配置
<bean class="com.gongj.populateBean.OrderService" id="order"/>
// 根据byName 注入属性
<bean class="com.gongj.populateBean.B" id="b" autowire="byName"/>
启动类 main 方法:
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("spring-config2.xml");
打印结果:setOrder = com.gongj.populateBean.OrderService@6bf2d08e
根据 byName自动注入,执行的是 setOrder方法,而不是 setORder方法。Spring 是如何去寻找的呢?跟着小杰一起来揭开这神秘的面纱吧!
autowireByName 源码解析
protected void autowireByName(String beanName, AbstractBeanDefinition mbd,
BeanWrapper bw, MutablePropertyValues pvs) {
// 获得当前实例作用域为 public 的 set方法名称(去掉set)
//比如 setOrder -》 order
//setORder -》 ORder
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
//循环得到的名称
for(String propertyName: propertyNames) {
//判断名称在单例池(singletonObjects)中是否存在 或者 在beanDefinitionMap中是否存在
if(containsBean(propertyName)) {
// 根据名称直接去找bean,这就是byName
Object bean = getBean(propertyName);
// 将属性名称、属性值添加到pvs中
pvs.add(propertyName, bean);
//注册依赖Bean
registerDependentBean(propertyName, beanName);
if(logger.isTraceEnabled()) {
logger.trace("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" +
propertyName + "'");
}
} else {
if(logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName +
"' of bean '" + beanName + "' by name: no matching bean found");
}
}
}
}
可以看到
setOrder方法被去掉了 set 之后变为了 order,O由大写变为了小写 o;而setORder方法被去掉了 set 之后变为了ORder,原样返回了。
处理流程
autowireByName 的处理流程:
1、获得所有公开的 set 方法(也会获取到父类的)。如果 set 方法的名称是 setOrder,返回的就是order,如果 set 方法的名称是 setORder,返回就是ORder。
2、循环获得的名称,先判断在容器中是否已经存在,存在就调用 getBean 方法,可以进行创建也可能直接获取。
3、将获得的对象赋值给 pvs,key 为 获得的名称,value为找到的对象。
4、注册依赖
下面就分别简单的分析一下各个流程:
1、unsatisfiedNonSimpleProperties
获得当前实例所有公开的(包括父类) set 方法,有如下几种情况:
1、无返回值的set有参方法(只能是一个参数),示例:
public void setOrderService(OrderService order){}
2、无参有返回值的get方法(返回类型不能是void),示例:
public String getba(){ return null;}
3、返回值为boolean类型的is无参方法,示例:
public boolean isDel(){return false;}
OK,继续往下看。。。
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd,
BeanWrapper bw) {
Set <String> result = new TreeSet < > ();
// 获得在BeanDefinition中添加的属性值
PropertyValues pvs = mbd.getPropertyValues();
// 获得当前实例的所有公开的(包括父类) get、set 方法
// 一个方法就是一个 PropertyDescriptor 对象
// PropertyDescriptor 这个类已经不是 Spring 的类,它属于java.beans包下
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
// 对找到的属性进行过滤,确定哪些属性是需要进行自动装配的
for(PropertyDescriptor pd: pds) {
// 属性有set方法,getWriteMethod就不会为 null
// 并且没有通过DependencyCheck排除
// 并且没有在BeanDefinition中给该属性赋值
// 并且属性的类型不是简单类型
if(pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !
pvs.contains(pd.getName()) && !BeanUtils.isSimpleProperty(pd.getPropertyType())
) {
result.add(pd.getName());
}
}
// 将集合转换为数组
// 返回过滤之后的结果,后续只对这些属性进行自动装配
return StringUtils.toStringArray(result);
}
getPropertyDescriptors方法所返回的 PropertyDescriptor是 java 的对象。这已经不是 Spring 的了。
这里也简单的贴一下吧!如果一直DEBUG会进入到 Introspector类的 getBeanInfo方法。这个类是java的类。
public static BeanInfo getBeanInfo(Class<?> beanClass)
throws IntrospectionException
{
if (!ReflectUtil.isPackageAccessible(beanClass)) {
return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
}
ThreadGroupContext context = ThreadGroupContext.getContext();
BeanInfo beanInfo;
synchronized (declaredMethodCache) {
beanInfo = context.getBeanInfo(beanClass);
}
if (beanInfo == null) {
// 看这里 new Introspector(beanClass, null, USE_ALL_BEANINFO) 这个构造方法里就有获取父类的逻辑,构造方法执行完毕之后,调用 getBeanInfo 方法
beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
synchronized (declaredMethodCache) {
context.putBeanInfo(beanClass, beanInfo);
}
}
return beanInfo;
}
getBeanInfo
private BeanInfo getBeanInfo() throws IntrospectionException {
BeanDescriptor bd = getTargetBeanDescriptor();
MethodDescriptor mds[] = getTargetMethodInfo();
EventSetDescriptor esds[] = getTargetEventInfo();
//这里我们只看这个方法,很熟悉了吧
PropertyDescriptor pds[] = getTargetPropertyInfo();
int defaultEvent = getTargetDefaultEventIndex();
int defaultProperty = getTargetDefaultPropertyIndex();
return new GenericBeanInfo(bd, esds, defaultEvent, pds,
defaultProperty, mds, explicitBeanInfo);
}
getTargetPropertyInfo
private PropertyDescriptor[] getTargetPropertyInfo() {
PropertyDescriptor[] explicitProperties = null;
if(explicitBeanInfo != null) {
explicitProperties = getPropertyDescriptors(this.explicitBeanInfo);
}
if(explicitProperties == null && superBeanInfo != null) {
// We have no explicit BeanInfo properties. Check with our parent.
addPropertyDescriptors(getPropertyDescriptors(this.superBeanInfo));
}
for(int i = 0; i < additionalBeanInfo.length; i++) {
addPropertyDescriptors(additionalBeanInfo[i].getPropertyDescriptors());
}
if(explicitProperties != null) {
// Add the explicit BeanInfo data to our results.
addPropertyDescriptors(explicitProperties);
} else {
// 看这里
// 获得当前类所有公开的方法
Method methodList[] = getPublicDeclaredMethods(beanClass);
for(int i = 0; i < methodList.length; i++) {
Method method = methodList[i];
if(method == null) {
continue;
}
//如果当前方法是 static 的,则跳过
int mods = method.getModifiers();
if(Modifier.isStatic(mods)) {
continue;
}
// 方法名称
String name = method.getName();
// 方法的参数类型
Class <? > [] argTypes = method.getParameterTypes();
// 方法的返回类型
Class <? > resultType = method.getReturnType();
// 方法的参数个数
int argCount = argTypes.length;
PropertyDescriptor pd = null;
// 如果方法名称的长度小于等于3,也就是说你的方法名称叫 set() get()
// 并且你的方法名不是以 is 开头的 则跳过当前方法
if(name.length() <= 3 && !name.startsWith(IS_PREFIX)) {
// Optimization. Don't bother with invalid propertyNames.
continue;
}
try {
// 如果参数个数为 0 ,也就是无参
if(argCount == 0) {
// 方法名称以 get 开头
if(name.startsWith(GET_PREFIX)) {
// 构建一个 PropertyDescriptor 对象
// name.substring(3) 这里截取了 get 这个三个字
pd = new PropertyDescriptor(this.beanClass, name.substring(3),
method, null);
}
// 如果返回类型是 boolean 并且 方法名称以 is 开头
else if(resultType == boolean.class && name.startsWith(IS_PREFIX)) {
// 构建一个 PropertyDescriptor 对象
// name.substring(2) 这里截取了 is 这个两个字
pd = new PropertyDescriptor(this.beanClass, name.substring(2),
method, null);
}
}
// 如果参数个数为1
else if(argCount == 1) {
if(int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {
// 不管,这是 PropertyDescriptor 的子类
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(
3), null, null, method, null);
}
// 如果返回类型是 void 并且 方法名称以 set 开头
else if(void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {
// 构建一个 PropertyDescriptor 对象
// name.substring(3) 这里截取了 set 这个三个字
pd = new PropertyDescriptor(this.beanClass, name.substring(3),
null, method);
if(throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
}
// 如果参数个数为2
else if(argCount == 2) {
if(void.class.equals(resultType) && int.class.equals(argTypes[0]) &&
name.startsWith(SET_PREFIX)) {
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(
3), null, null, null, method);
if(throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
}
} catch(IntrospectionException ex) {
pd = null;
}
if(pd != null) {
if(propertyChangeSource) {
pd.setBound(true);
}
addPropertyDescriptor(pd);
}
}
}
processPropertyDescriptors();
PropertyDescriptor result[] = properties.values().toArray(new PropertyDescriptor[
properties.size()]);
if(defaultPropertyName != null) {
for(int i = 0; i < result.length; i++) {
if(defaultPropertyName.equals(result[i].getName())) {
defaultPropertyIndex = i;
}
}
}
return result;
}
看完上面这个方法,可以知道 PropertyDescriptor存的可以是 get 方法,也可以是 set 方法。然后再看一个方法:PropertyDescriptor 的构造方法。
PropertyDescriptor
PropertyDescriptor(Class <?> bean, String base, Method read, Method write) throws IntrospectionException {
if(bean == null) {
throw new IntrospectionException("Target Bean class is null");
}
setClass0(bean);
// 将名称再次进行转换 比如我们所熟知的:类名首字母小写
setName(Introspector.decapitalize(base));
// read 就是get方法
setReadMethod(read);
// write 就是 set 方法 (重点:会根据这个属性是否为空判断是否有set方法)
setWriteMethod(write);
// 去掉get或者set的名称 示例:setOrder,base = Order
this.baseName = base;
}
decapitalize
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
// 如果名称长度大于 1 并且 第二个字母是大写的 并且 第一个字母是大写的
// 则原样返回
// 示例:ORder -》 ORder
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
// 将第一个字母转换为小写
// 示例:Order -》 order
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
实例
准备一个 A 类,并准备其他配置。
public class A {
//无参set方法
public void seta() {}
//无参set方法
public boolean isBoolean() {
return false;
}
//有参set方法
public void seta2(ProductService productService) {}
public void seta3(OrderService orderService, OrderService orderService2) {}
//无参无返回get方法
public void getb() {}
//无参有返回get方法
public String getbb() {
return "fefe";
}
//有参无返回get方法
public void getb2(OrderService orderService) {}
public void getb3(OrderService orderService, ProductService productService) {}
//有参有返回get方法
public String getb4(OrderService orderService) {
return "DDF";
}
public String getb5(OrderService orderService, ProductService productService) {
return "DDefeF";
}
}
//其他类
@Component
public class OrderService {}
@Service
public class ProductService {}
配置
<bean class="com.gongj.populateBean.A" id="a" autowire="byName"></bean>
<!--扫描包路径-->
<context:component-scan base-package="com.gongj.populateBean"/>
启动启动类,getPropertyDescriptors()方法响应如下:
a2也就是 seta2(),bb也就是getbb(),boolean是isBoolean(),class是属于父类Object的getClass()。
2、containsBean
@Override
public boolean containsBean(String name) {
String beanName = transformedBeanName(name);
// 单例池(singletonObjects)中是否存在 或者 beanDefinitionMap中是否存在
if(containsSingleton(beanName) || containsBeanDefinition(beanName)) {
// 如果存在 先判断它是不是以 & 开头,如果是,则判断它是不是 FactoryBean
return(!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
}
// Not found -> check parent.
// 获得父BeanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
// 看父级中是否存在
return(parentBeanFactory != null && parentBeanFactory.containsBean(
originalBeanName(name)));
}
3、registerDependentBean
这个方法中的参数名各位可能会弄混淆,这里提一下。
registerDependentBean(String beanName, String dependentBeanName)
在调用方法的时候,它将找到的set方法的名称作为第一个参数,当前的bean名称作为第二个参数。
也就是上面举得例子,B类中有OrderServie属性,说明 B 依赖 OrderServie。所以 beanName = ORder或者为order,dependentBeanName = b。
public void registerDependentBean(String beanName, String dependentBeanName) {
//确定原始名称,根据 beanName 去 aliasMap 中寻找,获得真正的 beanName
String canonicalName = canonicalName(beanName);
// computeIfAbsent:如果 key 对应的 value 不存在,
// 则使用获取 remappingFunction 重新计算后的值,
// 并保存为该 key 的 newValue,否则返回 value
// dependentBeanMap:我被谁依赖 order 被 b 依赖 key为 order,value 为 b
synchronized(this.dependentBeanMap) {
Set < String > dependentBeans = this.dependentBeanMap.computeIfAbsent(
canonicalName, k - > new LinkedHashSet < > (8));
// 如果添加失败则返回,添加失败也就代表已经存在了
if(!dependentBeans.add(dependentBeanName)) {
return;
}
}
// dependenciesForBeanMap:我依赖谁 b 依赖 order,key为b,value 为 order
synchronized(this.dependenciesForBeanMap) {
Set < String > dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(
dependentBeanName, k - > new LinkedHashSet < > (8));
dependenciesForBean.add(canonicalName);
}
}
autowireByType 装配
将上面的 byName 修改为 byType
<bean class="com.gongj.populateBean.B" id="b" autowire="byType"/>
结果:
setORder = com.gongj.populateBean.OrderService@ea30797
setOrder = com.gongj.populateBean.OrderService@ea30797
autowireByType 源码解析
protected void autowireByType(String beanName, AbstractBeanDefinition mbd,
BeanWrapper bw, MutablePropertyValues pvs) {
// 获得类型转换器
TypeConverter converter = getCustomTypeConverter();
if(converter == null) {
converter = bw;
}
Set < String > autowiredBeanNames = new LinkedHashSet < > (4);
// 获得当前实例作用域为 public 的 set方法名称(去掉set)
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for(String propertyName: propertyNames) {
try {
// 获得属性描述对象
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// 当前set方法的参数属性的类型不是Object类
if(Object.class != pd.getPropertyType()) {
// methodParam:方法参数,包含set方法和set方法中的参数信息
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// 当前Bean是否实现了PriorityOrdered,没有实现:true 实现:false
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
//DependencyDescriptor:方法已经见名知意了哈 依赖描述
//示例:public void setOrderService(OrderService order){}
//就是 OrderService 的描述信息
// 这里指定了 DependencyDescriptor 的子类为 AutowireByTypeDependencyDescriptor
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(
methodParam, eager);
// 根据 desc 找bean
Object autowiredArgument = resolveDependency(desc, beanName,
autowiredBeanNames, converter);
if(autowiredArgument != null) {
// 将属性名称、属性值添加到pvs中
pvs.add(propertyName, autowiredArgument);
}
for(String autowiredBeanName: autowiredBeanNames) {
//注册依赖Bean
registerDependentBean(autowiredBeanName, beanName);
if(logger.isTraceEnabled()) {
logger.trace("Autowiring by type from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" +
autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
}
catch(BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(),
beanName, propertyName, ex);
}
}
}
这里先提一句,为什么要给 DependencyDescriptor指定子类 AutowireByTypeDependencyDescriptor呢?
private static class AutowireByTypeDependencyDescriptor extends DependencyDescriptor {
public AutowireByTypeDependencyDescriptor(MethodParameter methodParameter,
boolean eager) {
super(methodParameter, false, eager);
}
@Override
public String getDependencyName() {
return null;
}
}
可以看到 AutowireByTypeDependencyDescriptor是一个静态的内部类,里面就一个构造方法和一个getDependencyName方法,而且 getDependencyName方法返回 null。依赖的名称直接返回null,就是如果你根据类型找到多个了,你都没办法根据名称再去寻找了。这很byType。为什么需要如此控制呢?主要是由于resolveDependency是公用方法,所以就只能从入参控制了。resolveDependency 方法我们等下再讲。我们先来看下如果 autowire属性的值不为 byName 或者 byType 的情况。
@Autowired装配
@Autowired装配也就是不属于 byName、byType两种装配方式的其他方式,首先先将上述代码修改一下,去掉autowire="byType" 。
- xml修改
<bean class="com.gongj.populateBean.OrderService" id="order"/>
<!--autowire="byType" 去掉-->
<bean class="com.gongj.populateBean.B" id="b"/>
<!--扫描包路径-->
<context:component-scan base-package="com.gongj.populateBean"/>
- B 类中增加一个
test方法,并在orderService属性上增加@Autowired注解
public class B {
@Autowired
OrderService orderService;
public void test(){
System.out.println("orderService = " + orderService);
}
public void setOrder(OrderService order){
System.out.println("setOrder = " +order);
}
public void setORder(OrderService order){
System.out.println("setORder = " + order);
}
}
- 启动类增加调用方法
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("spring-config2.xml");
B bean = context.getBean(B.class);
bean.test();
}
结果:
orderService = com.gongj.populateBean.OrderService@5a39699c
从结果可以看出来,这时并没有再执行那两个 set 方法。
源码解析
// ==== 执行完了Spring的byName、byType自动注入之后,就开始解析@Autowired、@Resource等等注解 ====
//是否有InstantiationAwareBeanPostProcessor
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否进行依赖检查,默认不进行依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if(hasInstAwareBpps) {
if(pvs == null) {
pvs = mbd.getPropertyValues();
}
for(BeanPostProcessor bp: getBeanPostProcessors()) {
if(bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (
InstantiationAwareBeanPostProcessor) bp;
// 调用BeanPostProcessor分别解析@Autowired、@Resource、@Value等等,得到属性值
// @Autowired、@Value注解被AutowiredAnnotationBeanPostProcessor处理解析
// @Resource注解被CommonAnnotationBeanPostProcessor处理解析
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(),
beanName);
if(pvsToUse == null) {
if(filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(),
beanName);
if(pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
上述代码还是比较容易理解的,首先先判断是否有InstantiationAwareBeanPostProcessor这个BeanPostProcessor,有这个BeanPostProcessor才会去执行 postProcessProperties方法。
进入到 ``InstantiationAwareBeanPostProcessor的postProcessProperties`方法,该方法是没有具体实现逻辑的,具体实现在子类中。
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
本篇只介绍AutowiredAnnotationBeanPostProcessor与CommonAnnotationBeanPostProcessor,先来看下其中一个子类AutowiredAnnotationBeanPostProcessor。
1、AutowiredAnnotationBeanPostProcessor
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean,
String beanName) {
// InjectionMetadata中保存了所有被@Autowired,@Value,@Inject注解标注的属性、方法
// 在这里已经被解析过了 AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName),这里也就从缓存中拿一下(忘记了可以再看看上一篇)
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(),
pvs);
try {
//调用 inject
metadata.inject(bean, beanName, pvs);
}
catch(BeanCreationException ex) {
throw ex;
}
catch(Throwable ex) {
throw new BeanCreationException(beanName,
"Injection of autowired dependencies failed", ex);
}
return pvs;
}
进入到 inject方法
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection < InjectedElement > checkedElements = this.checkedElements;
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);
}
// element可能是Method,也可能是Field
element.inject(target, beanName, pvs);
}
}
}
然后调试进入element.inject
protected void inject(Object target, @Nullable String requestingBeanName, @
Nullable PropertyValues pvs)
throws Throwable {
// 如果是属性,则反射赋值
if(this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
// 检查当前的属性是不是通过by_name和by_type来注入的
if(checkPropertySkipping(pvs)) {
return;
}
try {
// 如果是方法,则通过方法赋值
// 这里的方法并不是一定要setXX方法
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch(InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
在解析AutowiredAnnotationBeanPostProcessor时,这个方法不会被执行,该方法有两个子类。直接上图。
各位还记得缓存里面存的值吧!分别是:
currElements.add(new AutowiredFieldElement(field,required));
currElements.add(new AutowiredMethodElement(method, required, pd));
两个私有的内部类,一个是
AutowiredFieldElement,用来解析字段。还有一个是 AutowiredMethodElement,用来解析方法。
AutowiredFieldElement.inject
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if(this.cached) {
// 当前注入点已经注入过了,有缓存了,则利用cachedFieldValue去找对应的bean
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
} else {
// Spring在真正查找属性对应的对象之前, 会先将该属性的描述封装成一个DependencyDescriptor对象,
// 里面保存了Filed、是否强制需要即required为true, 以及属性所在的类(即Field所在的类Class对象)
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set < String > autowiredBeanNames = new LinkedHashSet < > (1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
// 根据field去寻找合适的bean,调用 resolveDependency
// 这里也是调用 resolveDependency 方法,与在进行 byType 调用同一个方法。但是方法入参不一样
// 这里传入的类型是 DependencyDescriptor
value = beanFactory.resolveDependency(desc, beanName,
autowiredBeanNames, typeConverter);
} catch(BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(
field), ex);
}
synchronized(this) {
// 进行缓存
if(!this.cached) {
if(value != null || this.required) {
this.cachedFieldValue = desc;
// 注册依赖
registerDependentBeans(beanName, autowiredBeanNames);
if(autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
// beanFactory中存在该 autowiredBeanName 并且 该autowiredBeanName的Bean的类型与字段的类型匹配,对解析得到的对象进行缓存
if(beanFactory.containsBean(autowiredBeanName) && beanFactory.isTypeMatch(
autowiredBeanName, field.getType())) {
// ShortcutDependencyDescriptor 在后面会被使用到,这里是一个缓存
this.cachedFieldValue = new ShortcutDependencyDescriptor(desc,
autowiredBeanName, field.getType());
}
}
} else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
// 反射设值
if(value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
构建一个DependencyDescriptor 对象,然后调用 resolveDependency方法。如果解析完之后的值不为null,则进行反射设值。
AutowiredMethodElement.inject
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
if(checkPropertySkipping(pvs)) {
return;
}
Method method = (Method) this.member;
Object[] arguments;
if(this.cached) {
// 解析缓存好的参数
arguments = resolveCachedArguments(beanName);
} else {
// 参数个数
int argumentCount = method.getParameterCount();
arguments = new Object[argumentCount];
// 构建 DependencyDescriptor 对象(注:这里是一个数组)
DependencyDescriptor[] descriptors = new DependencyDescriptor[
argumentCount];
// 记录自动注入的beanName,多少个参数就有多少个自动注入的beanName
Set < String > autowiredBeans = new LinkedHashSet < > (argumentCount);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
// 循环当前方法中的每个参数
// 这里就解决了在xml中配置byType时,自动装配的方法参数只能为一个
for(int i = 0; i < arguments.length; i++) {
// 方法参数对象
MethodParameter methodParam = new MethodParameter(method, i);
// 将该属性的描述封装成一个DependencyDescriptor对象
// 里面保存了方法参数对象、是否强制需要即required为true, 以及方法所在的类
// 一个方法参数就是一个 DependencyDescriptor 对象
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam,
this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
// 调用 resolveDependency 方法
Object arg = beanFactory.resolveDependency(currDesc, beanName,
autowiredBeans, typeConverter);
if(arg == null && !this.required) {
arguments = null;
break;
}
arguments[i] = arg;
} catch(BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(
methodParam), ex);
}
}
// 循环结束======
// arguments中存储的就是所找到的bean对象,构造为ShortcutDependencyDescriptor对象进行缓存
// descriptors中存储的就是以方法参数构建的DependencyDescriptor对象
synchronized(this) {
// 进行缓存
if(!this.cached) {
if(arguments != null) {
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(
descriptors, arguments.length);
// 注册依赖
registerDependentBeans(beanName, autowiredBeans);
// 注入Bean的个数与参数个数一致
if(autowiredBeans.size() == argumentCount) {
Iterator < String > it = autowiredBeans.iterator();
// 方法的参数类型
Class <? > [] paramTypes = method.getParameterTypes();
for(int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
// beanFactory中存在该 autowiredBeanName 并且
// 该autowiredBeanName的Bean的类型与字段的类型匹配,对解析得到的对象进行缓存
if(beanFactory.containsBean(autowiredBeanName) && beanFactory
.isTypeMatch(autowiredBeanName, paramTypes[i])) {
// ShortcutDependencyDescriptor 在后面会被使用到,这里是一个缓存
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
this.cachedMethodArguments = cachedMethodArguments;
} else {
this.cachedMethodArguments = null;
}
this.cached = true;
}
}
}
// 反射设值
if(arguments != null) {
try {
ReflectionUtils.makeAccessible(method);
method.invoke(bean, arguments);
} catch(InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
获取方法中的每个参数构建一个DependencyDescriptor 对象,然后调用 resolveDependency方法。最终如果解析完之后的值不为null,则进行反射设值。
resolveDependency
我们最终来到了AutowireCapableBeanFactory.resolveDependency 方法,这个方法有几个参数:
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter);
- descriptor:依赖描述,可以是field(属性字段)、methodI(普通方法参数)、constructor(构造方法参数)
- requestingBeanName:当前正在进行依赖注入的 beanName,比如 b。
- autowiredBeanNames:记录注入给当前依赖的 beanName,比如 orderService。
- typeConverter:类型转换器
具体实现在 DefaultListableBeanFactor的resolveDependency中。
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @
Nullable Set < String > autowiredBeanNames, @Nullable TypeConverter typeConverter
) throws BeansException {
// DependencyDescriptor表示一个依赖,可以是一个属性字段,可能是一个构造方法参数,可能是普通方法参数
// 初始化ParameterNameDiscoverer,用于解析方法参数名称
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 如果依赖的类型是Optional
// 可以这么写 :Optional<OrderService> orderService;
// 获得具体类型:orderService.get()
if(Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
// 如果依赖的类型是ObjectFactory 或者是 ObjectProvider
// 可以这么写:ObjectFactory<OrderService> orderService;
// 获得具体类型: orderService.getObject()
// 这种写法解决了一个问题,具体前往博文:
else if(ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
// 如果依赖的类型是javaxInjectProviderClass
else if(javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor,
requestingBeanName);
} else {
// 通用处理逻辑
// 在使用@Autowired注解时,也可以使用@Lazy注解,到时候注入的会是一个代理对象
// 有 @Lazy 注解,result 才会有值
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if(result == null) {
// 通过解析descriptor找到bean对象
result = doResolveDependency(descriptor, requestingBeanName,
autowiredBeanNames, typeConverter);
}
return result;
}
}
这里我们关注通用处理逻辑:doResolveDependency(),其实不论是Optional方式或者ObjectFactory方式,都会调用到doResolveDependency()方法。
doResolveDependency
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @
Nullable Set < String > autowiredBeanNames, @Nullable TypeConverter typeConverter
) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(
descriptor);
try {
// 如果DependencyDescriptor是一个ShortcutDependencyDescriptor,
// 那么会直接根据beanName从beanFactory中获取bean,
// 在利用@Autowired注解来进行依赖注入时会利用ShortcutDependencyDescriptor来进行依赖注入的缓存,
// 表示当解析完某个依赖信息后,会把依赖的bean的beanName缓存起来
// 忘记了的话,可以看看之前的逻辑:
// AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement
// AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement
Object shortcut = descriptor.resolveShortcut(this);
if(shortcut != null) {
return shortcut;
}
// 获取descriptor具体的类型,可能是Filed、普通方法参数、构造方法参数
Class <? > type = descriptor.getDependencyType();
// 获取@Value注解中所配置的值
// 可以这么写:
//@Autowired
//@Value("xxx")
//OrderService orderService;
// 在@Autowired标注的字段或者方法上可以再加上@Value,所以如果有@Value,则需要先解析@Value的值
// 如果有值,并且类型转换成功,则直接返回
// getSuggestedValue方法具体在 QualifierAnnotationAutowireCandidateResolver 中被实现
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);
// 解析Spring EL表达式,解析"#"符号(可以进行运算,可以写某个bean的名字)
// 解析不了,原样返回
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter :
getTypeConverter());
try {
// 进行类型转换
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
return(descriptor.getField() != null ? converter.convertIfNecessary(
value, type, descriptor.getField()) : converter.convertIfNecessary(
value, type, descriptor.getMethodParameter()));
}
}
// 没有使用@Value注解 ===========
// 要注入的依赖的类型是不是一个Map、Array、Collection
// 注入的属性可以这样写:
// 1、List<OrderService> orderService;
// 2、Map<String,OrderService> maps;
// 3、OrderService[] a;
// resolveMultipleBeans 方法也就是了调用了下面的 findAutowireCandidates 方法
// 然后拿到 findAutowireCandidates 方法的返回值,进行了类型转换
// 这里就不在单独拎出来讲了,各位DEGUG一遍就了解了
Object multipleBeans = resolveMultipleBeans(descriptor, beanName,
autowiredBeanNames, typeConverter);
if(multipleBeans != null) {
return multipleBeans;
}
// 首先通过type找,可能找到多个
// 返回值为Map:key = 成功匹配的beanName,value = 可能是具体的实例对象,也有可能暂时只是Class对象
Map < String, Object > matchingBeans = findAutowireCandidates(beanName,
type, descriptor);
if(matchingBeans.isEmpty()) {
// 如果没有找到想要的 bean,则判断当前需要注入的依赖是否是必须的,即 required = true
if(isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(),
descriptor);
}
// 不是必须,返回 null
return null;
}
// 依赖的beanName
String autowiredBeanName;
// 确认好的对象
Object instanceCandidate;
// 根据type找到了多个
if(matchingBeans.size() > 1) {
// 找到多个,去尝试确定出唯一的一个
//有几种筛选方式:
//1、@Primary
//2、@Priority
//3、byName,也就属性名称,或者是方法参数名称
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if(autowiredBeanName == null) {
// 还是没有确认唯一需要的bean
if(isRequired(descriptor) || !indicatesMultipleBeans(type)) {
// 当前依赖是required,或者不是数组或Collection或Map ,抛异常
return descriptor.resolveNotUnique(descriptor.getResolvableType(),
matchingBeans);
} else {
return null;
}
}
//确认了唯一一个,根据 autowiredBeanName ,也就是 beanName获得 候选实例
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
// 就找到了一个
else {
Map.Entry < String, Object > entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if(autowiredBeanNames != null) {
// 将注入的 beanName 缓存起来
autowiredBeanNames.add(autowiredBeanName);
}
//如果候选实例还是 Class 对象
if(instanceCandidate instanceof Class) {
// 调用beanFactory.getBean(beanName); 创建bean对象
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type,
this);
}
Object result = instanceCandidate;
if(result instanceof NullBean) {
if(isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(),
descriptor);
}
result = null;
}
//
if(!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type,
instanceCandidate.getClass());
}
// 将找到结果返回
return result;
} finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
上面的流程比较复杂,直接上图,大致流程如下:
流程图来源于
图灵学院。看完流程图,对整个流程的理解应该会有很大的帮助!我们继续看源码。
findAutowireCandidates
该方法位于DefaultListableBeanFactory类,作用是寻找自动装配的候选者。
protected Map < String, Object > findAutowireCandidates(@Nullable String beanName,
Class <? > requiredType, DependencyDescriptor descriptor) {
// 根据requiredType找到candidateNames,表示根据type找到了候选beanNames
// Ancestors是祖先的意思,所以这个方法是去当前beanfactory以及父级beanfactory中
// 去找类型为requiredType的bean的名字
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map < String, Object > result = new LinkedHashMap < > (candidateNames.length);
// 先从resolvableDependencies中进行匹配
for(Map.Entry < Class <? > , Object > classObjectEntry: this.resolvableDependencies
.entrySet()) {
Class <? > autowiringType = classObjectEntry.getKey();
// requiredType类是不是继承或实现了autowiringType, autowiringType为父类或接口,子类对象可以赋值给父类属性
if(autowiringType.isAssignableFrom(requiredType)) {
// 是resolvableDependencies中的子类所存的对象
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue,
requiredType);
if(requiredType.isInstance(autowiringValue)) {
// 把resolvableDependencies中保存的对象作为当前属性的一个候选者
result.put(ObjectUtils.identityToString(autowiringValue),
autowiringValue);
break;
}
}
}
// 对候选bean进行过滤
// 1、候选者不是自己,自己注入自己
// 2、候选者是支持自动注入给其他bean的。可以在 xml 的属性设置为false。autowire-candidate="false",false:不作为候选者
for(String candidate: candidateNames) {
// isAutowireCandidate方法中会去判断候选者是否和descriptor匹配
// isAutowireCandidate 这个是重点方法
if(!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate,
descriptor)) {
// 类型匹配成功,将结果放入到 Map中
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
//下面这些代码可以忽略了 上面才是重点流程
if(result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for(String candidate: candidateNames) {
if(!isSelfReference(beanName, candidate) && isAutowireCandidate(
candidate, fallbackDescriptor) && (!multiple ||
getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if(result.isEmpty() && !multiple) {
for(String candidate: candidateNames) {
if(isSelfReference(beanName, candidate) && (!(descriptor instanceof MultiElementDescriptor) ||
!beanName.equals(candidate)) && isAutowireCandidate(candidate,
fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
//返回结果
return result;
}
isAutowireCandidate
继续往下看,这时候我们已经拿到了同类型的所有 beanName 了,还需要再判断一下。
@Override
public boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
throws NoSuchBeanDefinitionException {
// 继续往下
return isAutowireCandidate(beanName, descriptor, getAutowireCandidateResolver());
}
继续往下
protected boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor,
AutowireCandidateResolver resolver)
throws NoSuchBeanDefinitionException {
String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName);
// 判断候选者名称 在 beanDefinitionMap 是否存在
if(containsBeanDefinition(beanDefinitionName)) {
// 根据候选者名称获得BeanDefinition,判断是否和descriptor匹配
return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(
beanDefinitionName), descriptor, resolver);
} else if(containsSingleton(beanName)) {
// 如果没有BeanDefinition,则直接找bean对象,如果存在则和descriptor匹配
return isAutowireCandidate(beanName, new RootBeanDefinition(getType(
beanName)), descriptor, resolver);
}
// 去父BeanFactory中进行匹配
BeanFactory parent = getParentBeanFactory();
if(parent instanceof DefaultListableBeanFactory) {
return((DefaultListableBeanFactory) parent).isAutowireCandidate(beanName,
descriptor, resolver);
} else if(parent instanceof ConfigurableListableBeanFactory) {
return((ConfigurableListableBeanFactory) parent).isAutowireCandidate(
beanName, descriptor);
} else {
return true;
}
}
isAutowireCandidate
protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd,
DependencyDescriptor descriptor, AutowireCandidateResolver resolver) {
String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName);
// 加载mbd中所指定的类(之前讲过)
resolveBeanClass(mbd, beanDefinitionName);
// 这个判断不知道如何才能满足 所以就不管了
if(mbd.isFactoryMethodUnique && mbd.factoryMethodToIntrospect == null) {
new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
}
// 检查BeanDefinitionHolder和descriptor匹配
return resolver.isAutowireCandidate(new BeanDefinitionHolder(mbd, beanName,
getAliases(beanDefinitionName)), descriptor);
}
这里会调用 AutowireCandidateResolver.isAutowireCandidate方法。
default boolean isAutowireCandidate(BeanDefinitionHolder bdHolder,
DependencyDescriptor descriptor) {
return bdHolder.getBeanDefinition().isAutowireCandidate();
}
AutowireCandidateResolver.isAutowireCandidate是默认方法。该方法下有三个子类实现:SimpleAutowireCandidateResolver,GenericTypeAwareAutowireCandidateResolver,QualifierAnnotationAutowireCandidateResolver。
各位细心一点其实会发现:QualifierAnnotationAutowireCandidateResolver继承GenericTypeAwareAutowireCandidateResolver,GenericTypeAwareAutowireCandidateResolver 继承 SimpleAutowireCandidateResolver ,SimpleAutowireCandidateResolver 继承 AutowireCandidateResolver。
我们直接进入到
QualifierAnnotationAutowireCandidateResolver类中,进入最基层。
@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder,
DependencyDescriptor descriptor) {
// 先交给GenericTypeAwareAutowireCandidateResolver进行验证bd和descriptor是否匹配
// 先进行其他验证,再进行Qualifiers验证
boolean match = super.isAutowireCandidate(bdHolder, descriptor);
// 如果某个beanDefinition和descriptor匹配,那么再判断一下是否使用了@Qualifier注解或者 xml中的 qualifier 标签
// 如果使用了则要继续判断当前bd的beanName是否和@Qualifier注解或者 xml中的 qualifier 标签所指定的名字相等
if(match) {
match = checkQualifiers(bdHolder, descriptor.getAnnotations());
if(match) {
//如果匹配,尝试检查方法上的注解,因为可能加在方法上
MethodParameter methodParam = descriptor.getMethodParameter();
if(methodParam != null) {
Method method = methodParam.getMethod();
if(method == null || void.class == method.getReturnType()) {
match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
}
}
}
}
return match;
}
QualifierAnnotationAutowireCandidateResolver类的isAutowireCandidate方法首先调用父类的 super.isAutowireCandidate方法,也就是 ``GenericTypeAwareAutowireCandidateResolver 。
@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder,
DependencyDescriptor descriptor) {
// 先调用SimpleAutowireCandidateResolver进行验证是否匹配
if(!super.isAutowireCandidate(bdHolder, descriptor)) {
// If explicitly false, do not proceed with any other checks...
return false;
}
// 如果不匹配则进行泛型匹配
return checkGenericTypeMatch(bdHolder, descriptor);
}
在此调用父类(SimpleAutowireCandidateResolver)的 isAutowireCandidate方法。
@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder,
DependencyDescriptor descriptor) {
return bdHolder.getBeanDefinition().isAutowireCandidate();
}
如果 autowireCandidate属性为 false,这样容器在查找自动装配对象时,将不考虑该bean。当然也就不会再执行两个子类的逻辑了。如果为 true,就分别去依次执行子类的逻辑。
到这,findAutowireCandidates方法才正式结束!感觉很复杂,总结一下findAutowireCandidates的总体流程吧!
一、根据依赖描述的类型去寻找候选者的 beanName。循环 beanDefinitionNames与类型进行匹配,将类型匹配成功的名称进行返回,这也就是byType。
二、判断是否是候选者Bean,由autowireCandidate属性控制。
三、对其泛型类型进行匹配。
四、进行Qualifier验证。
五、得到Map,进行返回。
接下来就是对拿到的 Map 进行再一步的筛选。具体逻辑在 determineAutowireCandidate方法中。
determineAutowireCandidate
该方法位于DefaultListableBeanFactory类,作用是确定自动装配的候选者。
@Nullable
protected String determineAutowireCandidate(Map < String, Object > candidates,
DependencyDescriptor descriptor) {
Class <? > requiredType = descriptor.getDependencyType();
// 取@Primary的bean
String primaryCandidate = determinePrimaryCandidate(candidates,
requiredType);
if(primaryCandidate != null) {
return primaryCandidate;
}
// 取优先级最高的bean 通过@Priority来定义优先级,数字越小,优先级越高
String priorityCandidate = determineHighestPriorityCandidate(candidates,
requiredType);
if(priorityCandidate != null) {
return priorityCandidate;
}
// byName
for(Map.Entry < String, Object > entry: candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
if((beanInstance != null && this.resolvableDependencies.containsValue(
beanInstance)) ||
// 根据属性名确定
// descriptor.getDependencyName()
matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateName;
}
}
return null;
}
@Primary
@Primary可以理解被标注的bean为默认优先选择,不可以同时设置多个, 其实是 BeanDefinition的primary属性。
@Nullable
protected String determinePrimaryCandidate(Map < String, Object > candidates,
Class <? > requiredType) {
String primaryBeanName = null;
// 遍历找到的候选者
for(Map.Entry < String, Object > entry: candidates.entrySet()) {
// beanName
String candidateBeanName = entry.getKey();
// 实例或者是class
Object beanInstance = entry.getValue();
// 当前candidateBean是否包含@Primary注解
if(isPrimary(candidateBeanName, beanInstance)) {
if(primaryBeanName != null) {
// 如果多个候选者上都标注了 @Primary注解,则抛出异常
boolean candidateLocal = containsBeanDefinition(candidateBeanName);
boolean primaryLocal = containsBeanDefinition(primaryBeanName);
if(candidateLocal && primaryLocal) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"more than one 'primary' bean found among candidates: " +
candidates.keySet());
} else if(candidateLocal) {
primaryBeanName = candidateBeanName;
}
} else {
primaryBeanName = candidateBeanName;
}
}
}
return primaryBeanName;
}
isPrimary
protected boolean isPrimary(String beanName, Object beanInstance) {
String transformedBeanName = transformedBeanName(beanName);
// beanDefinitionMap 中是否存在 transformedBeanName
if(containsBeanDefinition(transformedBeanName)) {
// isPrimary 是 BeanDefinition中的一个方法
// primary为true,就代表使用了@Primary注解
return getMergedLocalBeanDefinition(transformedBeanName).isPrimary();
}
BeanFactory parent = getParentBeanFactory();
return(parent instanceof DefaultListableBeanFactory && ((
DefaultListableBeanFactory) parent).isPrimary(transformedBeanName,
beanInstance));
}
@Priority
@Priority它属于javax.annotation,JSR250规范。通过@Priority来定义优先级,数字越小,优先级越高。
@Nullable
protected String determineHighestPriorityCandidate(Map < String, Object >
candidates, Class <? > requiredType) {
String highestPriorityBeanName = null;
Integer highestPriority = null;
// 遍历找到的候选者
for(Map.Entry < String, Object > entry: candidates.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
if(beanInstance != null) {
// 获得 beanInstance 上 @Priority注解的值
Integer candidatePriority = getPriority(beanInstance); //@Priority(1)
if(candidatePriority != null) {
// 如果多个候选者上都标注了 @Priority注解,则进行比较
// 如果相等抛出异常
// 如果当前候选者的值小于之前候选者的值,则覆盖之前的值
if(highestPriorityBeanName != null) {
if(candidatePriority.equals(highestPriority)) {
throw new NoUniqueBeanDefinitionException(requiredType,
candidates.size(),
"Multiple beans found with the same priority ('" +
highestPriority + "') among candidates: " + candidates.keySet()
);
} else if(candidatePriority < highestPriority) {
highestPriorityBeanName = candidateBeanName;
highestPriority = candidatePriority;
}
} else {
highestPriorityBeanName = candidateBeanName;
// 将获取到的值先暂存起来,用于后续比较
highestPriority = candidatePriority;
}
}
}
}
return highestPriorityBeanName;
}
byName
至于byName,也就是以下这段代码,关注一下descriptor.getDependencyName()该方法返回的值。在讲byType的时候提到,AutowireByTypeDependencyDescriptor类中 getDependencyName方法返回 null。所以byType没办法根据byName筛选。
for(Map.Entry < String, Object > entry: candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
if((beanInstance != null && this.resolvableDependencies.containsValue(
beanInstance)) ||
// 根据属性名确定
// descriptor.getDependencyName()
matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateName;
}
}
实例
对于 @Autowired的具体使用方式可以前往小杰的另外一篇博文进行阅读。@Autowired的使用方式
2、CommonAnnotationBeanPostProcessor
上面分析完了 AutowiredAnnotationBeanPostProcessor类,为了完整性,就不拆分文章了,进入到CommonAnnotationBeanPostProcessor类的postProcessProperties方法。
@Override
public PropertyValues postProcessProperties(PropertyValues pvs,
Object bean, String beanName) {
//从缓存中获取 InjectionMetadata 对象
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(),
pvs);
try {
//调用 inject
metadata.inject(bean, beanName, pvs);
}
catch(Throwable ex) {
throw new BeanCreationException(beanName,
"Injection of resource dependencies failed", ex);
}
return pvs;
}
进入到 inject方法
public void inject(Object target, @Nullable String beanName, @
Nullable PropertyValues pvs) throws Throwable {
Collection < InjectedElement > checkedElements = this.checkedElements;
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);
}
// element可能是Method,也可能是Field
element.inject(target, beanName, pvs);
}
}
}
然后调试进入element.inject。在CommonAnnotationBeanPostProcessor类找到的注入点对象,WebServiceRefElement、EjbRefElement、ResourceElement并没有重写父类的inject方法,所以会使用父类的 inject逻辑。
protected void inject(Object target, @Nullable String requestingBeanName, @
Nullable PropertyValues pvs)
throws Throwable {
// 如果是属性,则反射赋值
if(this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
} else {
// 检查当前的属性是不是通过by_name和by_type来注入的
if(checkPropertySkipping(pvs)) {
return;
}
try {
// 如果是方法,则通过方法赋值
// 这里的方法并不是一定要setXX方法
//@Resource
//private void order1(OrderService order){
// this.order = order;
//}
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target,
requestingBeanName));
}
catch(InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
@Resource 注解逻辑放在getResourceToInject方法中,一起来看看吧!
该方法有两个参数,含义分别如下:
- target:bean的实例对象
- requestingBeanName:bean名称
@Nullable
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName){
return null;
}
该方法并没有具体的逻辑,但是它有四个子类,如下图
本篇只看ResourceElement中的实现。在看具体实现之前,我们先来看一下ResourceElement的构造方法。该构造方法被两个地方用到(ps:如果忘记了可以再去看看 Spring源码(十)-寻找注入点-MergedBeanDefinitionPostProcessor)。分别如下:
- new ResourceElement(field, field, null):构建基于字段的
ResourceElement的对象 - new ResourceElement(method, bridgedMethod, pd):构建基于方法的
ResourceElement的对象
ResourceElement
public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
super(member, pd);
//获得 Resource注解 对象
Resource resource = ae.getAnnotation(Resource.class);
String resourceName = resource.name();
Class <? > resourceType = resource.type();
// 如果@Resource注解中没有指定name,那么就使用默认生成的名字
this.isDefaultName = !StringUtils.hasLength(resourceName);
if(this.isDefaultName) {
//属性名称 或者 方法名称
resourceName = this.member.getName();
//对方法名称进行截取
if(this.member instanceof Method && resourceName.startsWith(
"set") && resourceName.length() > 3) {
resourceName = Introspector.decapitalize(resourceName.substring(
3));
}
} else if(embeddedValueResolver != null) {
// 占位符填充
resourceName = embeddedValueResolver.resolveStringValue(
resourceName);
}
//检查类型是否匹配。默认值就是 Object
if(Object.class != resourceType) {
checkResourceType(resourceType);
} else {
// No resource type specified... check field/method.
resourceType = getResourceType();
}
//进行赋值
this.name = (resourceName != null ? resourceName : "");
this.lookupType = resourceType;
String lookupValue = resource.lookup();
this.mappedName = (StringUtils.hasLength(lookupValue) ?
lookupValue : resource.mappedName());
//从这里看到 @Resource 是可以同 @Lazy 一起使用的
Lazy lazy = ae.getAnnotation(Lazy.class);
this.lazyLookup = (lazy != null && lazy.value());
}
- checkResourceType
protected final void checkResourceType(Class <? > resourceType) {
if(this.isField) {
//得到@Resourec注解标注字段的类型
Class <? > fieldType = ((Field) this.member).getType();
//isAssignableFrom:判断是否为某个类的父类
//resourceType值为 @Resource注解中 type 属性的值
//这里控制 @Resource 注解中 type 属性的值不能随便填
if(!(resourceType.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(
resourceType))) {
throw new IllegalStateException("Specified field type [" +
fieldType + "] is incompatible with resource type [" +
resourceType.getName() + "]");
}
} else {
//拿到方法参数 ,参数个数只能为一个
Class <? > paramType = (this.pd != null ? this.pd.getPropertyType() :
((Method) this.member).getParameterTypes()[0]);
//与上述逻辑一致
if(!(resourceType.isAssignableFrom(paramType) || paramType.isAssignableFrom(
resourceType))) {
throw new IllegalStateException("Specified parameter type [" +
paramType + "] is incompatible with resource type [" +
resourceType.getName() + "]");
}
}
}
上述逻辑在执行解析注入点的时候就会被执行。现在我们就来看看是如何进行属性注入的吧!
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName){
return(this.lazyLookup ? buildLazyResourceProxy(this,
requestingBeanName) : getResource(this, requestingBeanName));
}
三元运算表达式。如果 lazyLookup为 true 则执行 buildLazyResourceProxy方法,否则执行getResource方法。默认是 false,当然可以 @Reource可以配置@Lazy共同使用。不过无论是 lazyLookup为 true 还是为false, 都会调用 getResource方法。
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
if(StringUtils.hasLength(element.mappedName)) {
return this.jndiFactory.getBean(element.mappedName, element.lookupType);
}
if(this.alwaysUseJndiLookup) {
return this.jndiFactory.getBean(element.name, element.lookupType);
}
if(this.resourceFactory == null) {
throw new NoSuchBeanDefinitionException(element.lookupType,
"No resource factory configured - specify the 'resourceFactory' property"
);
}
return autowireResource(this.resourceFactory, element,
requestingBeanName);
}
如果@Resource注解配置了 lookup、mappedName的值,那么就会去 SimpleJndiBeanFactory 工厂里面去找Bean,没有配置,则调用autowireResource方法。对于 Jndi的相关写法、源码本文不再探讨,知道 @Resource注解是支持JNDI工厂就行。
protected Object autowireResource(BeanFactory factory, LookupElement element, @
Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Object resource;
Set < String > autowiredBeanNames;
String name = element.name;
if(factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (
AutowireCapableBeanFactory) factory;
//构建依赖描述信息
//可以是 属性字段、方法参数
DependencyDescriptor descriptor = element.getDependencyDescriptor();
// fallbackToDefaultTypeMatch 默认为 true
// 如果@Resource 没有配置 name 属性, isDefaultName为true
// 如果配置了 @Resource(name = "sfe") isDefaultName为false
// factory.containsBean 会进入到 AbstractBeanFactory 类的 containsBean 方法,这也就是 @Resource 的 byName
if(this.fallbackToDefaultTypeMatch && element.isDefaultName && !
factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet < > ();
//调用 resolveDependency 方法
resource = beanFactory.resolveDependency(descriptor,
requestingBeanName, autowiredBeanNames, null);
if(resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(),
"No resolvable resource object");
}
} else {
//内部调用 getBean 方法
resource = beanFactory.resolveBeanByName(name, descriptor);
autowiredBeanNames = Collections.singleton(name);
}
}
//以下逻辑忽略
else {
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
}
if(factory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
for(String autowiredBeanName: autowiredBeanNames) {
if(requestingBeanName != null && beanFactory.containsBean(
autowiredBeanName)) {
beanFactory.registerDependentBean(autowiredBeanName,
requestingBeanName);
}
}
}
return resource;
}
首先判断当前 factory是不是 AutowireCapableBeanFactory ,一般来说这个条件都是满足的。然后获得依赖描述信息(是不是有点熟悉了),然后有一个 if/else, 为 true 调用 resolveDependency方法。为 false调用resolveBeanByName方法。
哦豁,如果为 true 调用 resolveDependency方法 ,那么@Resource注解逻辑不就和@Autowired一样吗?
不知道各位小伙伴有没有注意 if()语句中有一个判断条件为: factory.containsBean(name),作用是判断当前容器中是否包含指定名称的 Bean。这就是 byName的逻辑。
如果``factory.containsBean(name)返回 true,也就是包含此名称的 Bean,则进入else块逻辑,调用 resolveBeanByName方法,内部调用 getBean`方法。
如果``factory.containsBean(name)返回 false,则调用 resolveDependency方法,进行 byType、@Qualifier、@Primary、@Priority`一系列吧啦吧啦的。
到这里完成了所有注入属性的获取,将获取的属性封装在 PropertyValues 的实例对象 pvs 中,但并没有应用到已经实例化的bean 中。注解方式除外,解析完之后被反射设值了。下面分析populateBean方法的最后一步:applyPropertyValues()。
applyPropertyValues
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
// pvs为空列表 ,直接返回(注解开发)
// 1、pvs的值来源于 在xml中配置了 property 属性
// 2、根据 byType、byName 自动注入,会将找到的对象添加到 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()) {
// 是否已经设置过值,如果设置过,直接获取
try {
// 设置属性值
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
} else {
// 如果 pvs 不是 MutablePropertyValues 类型,则直接使用原始类型
original = Arrays.asList(pvs.getPropertyValues());
}
// 获取 TypeConverter
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
// 获取对应的解析器
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
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) {
//获得指定名称的set方法
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);
}
//是否需要解析,获得Bean实例
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);
}
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) {
//converted 设置为 true,作为缓存
mpvs.setConverted();
}
try {
// 设置值 执行set方法
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
到此,Spring 的属性填充到此结束了。
- 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。