Spring-源码-如何处理@Autowired、@Resource注解及区别

一、引子

疑问:String如何处理带有@Autowired的方法或者带有@Autowired的属性
在Spring实例化Bean的过程中有个填充属性的操作,这里就包含依赖注入,也就是@Autowired注解。以下是Spring在实例化过程中的一段代码,该代码主要是处理Bean里面有属性或者方法带有@Autowired注解的处理逻辑。

//BeanWrapper instanceWrapper = xxx
//RootBeanDefinition mbd = xx
populateBean(beanName, mbd, instanceWrapper);
//BeanWrapper是做什么的?因为此时Bean对象已经生成,但是没有完全实例化完,因为Bean里面的属性还没有赋值,那么就需要去修改这个对象里面的属性,BeanWrapper就是做这个事情的。关于BeanWrapper介绍可以看我的另一偏文章

上面代码主要对只是实例化部分的Bean进一步处理,对他里面的属性进行赋值的过程,主要是对Bean里面的属性或者方法标有@Autowired进行处理

看下populateBean方法,如何对Bean里面的属性和方法进行处理,主要是包含两块

在这里插入图片描述
第一块是关于通过ByType或者ByName的处理方式
比如我们在开发中使用xml配置

<bean id="user" class="com.kuang.pojo.User" autowire="byName">
</bean>
<bean id="user" class="com.kuang.pojo.User" autowire="byType">
	。。。。。User里面很多属性,那么这些属性赋值就和autowire配的值有关系了。
</bean>

DependencyDescriptor来给属性赋值或者方法赋值,关于DependencyDescriptor可以看我的另一偏文章:

第二块是通过AutowiredAnnotationBeanPostProcessor

关于AutowiredAnnotationBeanPostProcessor我们重点说下处理流程

1、拿到Bean里面带有@Autowired注解的属性和带有@Autowired注解的方法。
2、通过反射去设置属性的值,或者通过反射调用目标方法

这种方式就好比Spring在实例化Mapper类的时候,里面就有带@Autowired注解的属性和带有@Autowired注解的方法,比如setSqlSessionFactory方法,处理逻辑都是一样的。下面说下针对使用了@Autowired修饰方法或者属性,Spring是怎么赋值的。

//这是对populateBean精简后的伪代码,里面包含2个重要类PropertyValues、BeanWrapper
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	//遍历所有的BeanPostProcessors
    Iterator var9 = this.getBeanPostProcessors().iterator();
    while (var9.hasNext()) {
        BeanPostProcessor bp = (BeanPostProcessor) var9.next();
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            //找到AutowiredAnnotationBeanPostProcessor
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            
            //从Bean里面找到带有@Autowired的属性和方法,然后给其赋值,最后得到PropertyValues,PropertyValues就包含了属性所需要赋值的value。关于PropertyValues我下文会介绍
            PropertyValues pvs = ibp.postProcessProperties((PropertyValues) pvs, bw.getWrappedInstance(), beanName);
            //这里主要是把上面得到的PropertyValues设置到BeanWrapper里面去。
            this.applyPropertyValues(beanName, mbd, bw, (PropertyValues) pvs);
        }
    }
}

//主要是把得到的PropertyValues设置到BeanWrapper里面去。
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
	bw.setPropertyValues(pvs);
}

上面2个重要的类这里说下,PropertyValues、BeanWrapper

PropertyValues是什么?
PropertyValues的实现类是MutablePropertyValues,可以理解他是一个集合,里面包含如下几个属性

id:Bean 唯一标识名称。
beanClass:类全限定名(包名+类名)。
MultablePropertyValues:用于封装类属性的集合,里面是一个List容器,包装了很多 PropertyValue。一个PropertyValue封装了一个属性及其对应的值,可以说一个属性及其值就是一个 PropertyValue,当我们需要再 BeanDefinition 中修改某个类里面的属性时就可以使用该类。
…省略属性

那么这个类有什么作用呢?当一个Bean里面有很多个属性需要设置值的时候,这些属性的name和value就会被封装成PropertyValue对象。多个属性组和成一个PropertyValue集合。

BeanWrapper 是什么?

Spring在对Bean封装打包得到BeanWrapper对象之后,我们就可以通过BeanWrapper访问Bean的属性和方法,在Spring需要反射获取(设置)Bean的字段或者方法时(比如@Autowired注入字段时),就可以直接通过BeanWrapper来操作。

BeanWrapper实现了很多接口,每个接口都有特殊的功能
1、属性编辑器PropertyEditor,有了它,你可以用String给一个Bean非字符串类型属性设置值(当然只支持几种内置的类型)
2、类型转换服务ConversionService
3、类型转换逻辑TypeConverter

接下来看上面postProcessProperties方法做了什么操作

//通过类名生成InjectionMetadata,关于InjectionMetadata我下面会介绍这个做什么用的,很重要。
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	//通过类型生成InjectionMetadata
    InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);
    //给InjectionMetadata里面的属性设置值,InjectionMetadata主要是Method、Field这2种东西,然后通过反射给其设置值。
    metadata.inject(bean, beanName, pvs);
    return pvs;
}

//通过缓存获取InjectionMetadata,如果没有就通过类名转成InjectionMetadata,
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
	//先从缓存里面拿
    InjectionMetadata metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);
    if(metadata==null){
		InjectionMetadata metadata = this.buildAutowiringMetadata(clazz);//没拿到就通过类来生成新的InjectionMetadata,在存到缓存里面去。
    	this.injectionMetadataCache.put(cacheKey, metadata);
    }
    return metadata;
}

InjectionMetadata介绍

public class InjectionMetadata {
	private final Class<?> targetClass;
	//当一个方法有多个属性有@Autowired时,那么这里面就是一个集合,@Autowired修饰的方法也是一样
	private final Collection<InjectionMetadata.InjectedElement> injectedElements;	

}
//伪代码
public abstract static class InjectedElement {
    protected final Method或者Field类型 member;
    protected final boolean isField;
}

通过上面的结构我们不难看出带有@Autowired修饰的字段或者@Autowired修饰的方法,
都是通过member来完成赋值和调用。
//一层层解析Bean里面带有@Autowired属性和方法,包括其父类。最终得到InjectionMetadata对象。
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
    List<InjectedElement> elements = new ArrayList();
    Class targetClass = clazz;

    do {
        List<InjectedElement> currElements = new ArrayList();
        ReflectionUtils.doWithLocalFields(targetClass, (field) -> {
            MergedAnnotation<?> ann = this.findAutowiredAnnotation(field);//判断字段是否带了@Autowired注解
            if (ann != null) {
                if (Modifier.isStatic(field.getModifiers())) {
                    return;
                }

                boolean required = this.determineRequiredStatus(ann);
                currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
            }

        });
        ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                MergedAnnotation<?> ann = this.findAutowiredAnnotation(bridgedMethod);//判断方法是否带了@Autowired注解
                if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                    if (Modifier.isStatic(method.getModifiers())) {
                        return;
                    }

                    if (method.getParameterCount() == 0 && this.logger.isInfoEnabled()) {//参数个数是0个
                        this.logger.info("Autowired annotation should only be used on methods with parameters: " + method);
                    }

                    boolean required = this.determineRequiredStatus(ann);
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));
                }

            }
        });
        elements.addAll(0, currElements);
        targetClass = targetClass.getSuperclass();//一层层往父类里面找。
    } while(targetClass != null && targetClass != Object.class);

    //最终拿到所有的带有@Autowired注解的属性和方法生成InjectionMetadata对象。
    return InjectionMetadata.forElements(elements, clazz);
}

最后通过metadata.inject(bean, beanName, pvs)来完成赋值,下面看下metadata.inject做了什么

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    if (!((Collection)elementsToIterate).isEmpty()) {
		//遍历所有的InjectedElement出发inject方法
        Iterator var6 = ((Collection)injectedElements).iterator();
        while(var6.hasNext()) {
            InjectionMetadata.InjectedElement element = (InjectionMetadata.InjectedElement)var6.next();
            element.inject(target, beanName, pvs);//完成赋值或者调用。
        }
    }

}

//根据element的类型,是Field还是Method

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Field field = (Field)this.member;
    Object value = AutowiredAnnotationBeanPostProcessor.this.resolvedCachedArgument(beanName, this.cachedFieldValue);
    field.set(bean, value);//给字段赋值,到这带有@Autowired注解的字段值已经填充好了。
}

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Method method = (Method)this.member;
    Object[] arguments = this.resolveCachedArguments(beanName);//拿到参数
    method.invoke(bean, arguments);//触发目标方法,到这带有@Autowired的方法已经得到执行了。
}

二、@Resource

其实@Resource和@Autowired处理有点类似,下面从源码上介绍下处理的区别,关于@Autowired的处理使用的后置处理器是AutowiredAnnotationBeanPostProcessor,那么@Resource的后置处理器是CommonAnnotationBeanPostProcessor,下面看下处理的区别。
CommonAnnotationBeanPostProcessor

1、区别一、CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor

同样也是在populateBean方法里面处理,下面精简了一下代码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    Iterator var9 = this.getBeanPostProcessors().iterator();

    while(var9.hasNext()) {
        BeanPostProcessor bp = (BeanPostProcessor)var9.next();
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
            //区别在于当前的后置处理器ibp=CommonAnnotationBeanPostProcessor,只不过处理@Autowired时,ibp=AutowiredAnnotationBeanPostProcessor
            PropertyValues pvsToUse = ibp.postProcessProperties((PropertyValues)pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                if (filteredPds == null) {
                    filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                }

                pvsToUse = ibp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    return;
                }
            }

            pvs = pvsToUse;
        }
    }
    
    this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
}

2、区别二:InjectedElement的实现类不同

首先是通过目标类Bean找到里面带有@Resource注解的属性或者方法,来生成元数据也就是InjectionMetadata。
此时的元数据的实现类型是ResourceElement,而我们在分析@Autowired时实现的类型是AutowiredFieldElement、AutowiredMethodElement

private InjectionMetadata buildResourceMetadata(Class<?> clazz) {
   
    List<InjectedElement> elements = new ArrayList();
    Class targetClass = clazz;

    //通过循环,一层层遍历,通过父类往上找
    do {
        //查找带有@Resource的字段
        List<InjectedElement> currElements = new ArrayList();
        ReflectionUtils.doWithLocalFields(targetClass, (field) -> {
            if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
                }

                currElements.add(new CommonAnnotationBeanPostProcessor.WebServiceRefElement(field, field, (PropertyDescriptor)null));
            } else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException("@EJB annotation is not supported on static fields");
                }

                currElements.add(new CommonAnnotationBeanPostProcessor.EjbRefElement(field, field, (PropertyDescriptor)null));
            } else if (field.isAnnotationPresent(Resource.class)) {
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException("@Resource annotation is not supported on static fields");
                }
				//注意currElements添加进去的数据类型是ResourceElement
                if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
                    currElements.add(new CommonAnnotationBeanPostProcessor.ResourceElement(field, field, (PropertyDescriptor)null));
                }
            }

        });

        //查找带有@Resource的方法
        ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                    PropertyDescriptor pdx;
                    if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
                        if (Modifier.isStatic(method.getModifiers())) {
                            throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
                        }

                        if (method.getParameterCount() != 1) {
                            throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
                        }

                        pdx = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        currElements.add(new CommonAnnotationBeanPostProcessor.WebServiceRefElement(method, bridgedMethod, pdx));
                    } else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
                        if (Modifier.isStatic(method.getModifiers())) {
                            throw new IllegalStateException("@EJB annotation is not supported on static methods");
                        }

                        if (method.getParameterCount() != 1) {
                            throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
                        }

                        pdx = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        currElements.add(new CommonAnnotationBeanPostProcessor.EjbRefElement(method, bridgedMethod, pdx));
                    } else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
                        if (Modifier.isStatic(method.getModifiers())) {
                            throw new IllegalStateException("@Resource annotation is not supported on static methods");
                        }

                        Class<?>[] paramTypes = method.getParameterTypes();
                        if (paramTypes.length != 1) {
                            throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
                        }
						//实现类型用的是ResourceElement
                        if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
                            PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                            currElements.add(new CommonAnnotationBeanPostProcessor.ResourceElement(method, bridgedMethod, pd));
                        }
                    }
                }

            }
        });
        elements.addAll(0, currElements);
        targetClass = targetClass.getSuperclass();
    } while(targetClass != null && targetClass != Object.class);

    return InjectionMetadata.forElements(elements, clazz);
}

基于上面的InjectedElement类型不同,必然导致inject方法的处理逻辑不一样

//下面看下ResourceElement的处理逻辑
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, this.getResourceToInject(target, requestingBeanName));
    } else {
      	//走到说明@Resource修饰的方法
        try {
            Method method = (Method)this.member;
            ReflectionUtils.makeAccessible(method);
            method.invoke(target, this.getResourceToInject(target, requestingBeanName));
        } catch (InvocationTargetException var5) {
            throw var5.getTargetException();
        }
    }

}

3、区别点三:获取Bean的方法不同,resolveDependency和resolveBeanByName

Autowired是调用resolveDependency方法,来获取需要注入的属性,底层是通过Type来拿到BeanName,在通过Name来获取实例,如果Name存在多个,在通过BeanName进行匹配。

Resource是调用resolveBeanByName方法,在获取Bean的时候,优先通过factory里面是否包含name判断,如果没有则通过Type尝试去获取,通过Type去获取也就变成了调用resolveDependency方法一个意思,这里需要注意在@Autowired获取Bean的时候,也是用resolveDependency方法

protected Object autowireResource(BeanFactory factory, CommonAnnotationBeanPostProcessor.LookupElement element, @Nullable String requestingBeanName){
    String name = element.name;
    Object resource;
    Object autowiredBeanNames;
    if (factory instanceof AutowireCapableBeanFactory) {
        AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory)factory;
        DependencyDescriptor descriptor = element.getDependencyDescriptor();
        //最终进到这里,先尝试判断factory中是否包含该name,如果不包含则通过Type场景去获取。
        if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
            autowiredBeanNames = new LinkedHashSet();
            //流程1
            resource = beanFactory.resolveDependency(descriptor, requestingBeanName, (Set)autowiredBeanNames, (TypeConverter)null);
            if (resource == null) {
                throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
            }
        } else {
            //流程2、进到这里说明Bean中包含name,则通过name来获取
            resource = beanFactory.resolveBeanByName(name, descriptor);
            autowiredBeanNames = Collections.singleton(name);
        }
    }
    return resource;
}

注:DependencyDescriptor对象存的就是被@Autowired或者@Resource修饰的属性或者方法信息如下

@Nullable
protected Field field; 字段Field,这也包含了字段名称字段类型,通过这个我们也可以知道需要注入什么类型进去。
@Nullable
protected MethodParameter methodParameter;  方法参数
@Nullable
private volatile Annotation[] fieldAnnotations;  注解

@Nullable
private String fieldName; 被修饰的字段名称
@Nullable
private String methodName;  被修饰的方法名称
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信仰_273993243

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值