spring--5--spring之CommonAnnotationBeanPostProcessor源码

spring之CommonAnnotationBeanPostProcessor源码

1 作用

首先来说一下这个BeanPostProcessor的作用

(1)处理@Resource注解,实现ByName的自动注入功能。

(2)处理@PostConstruct@PreDestroy注解,指定初始化方法和销毁方法,使用注解的方法相比于实现接口可以降低spring的耦合。

接下来我们看一下这个BeanPostProcessor的类图,从类图上我们就能知道上述功能的处理方法是哪个

在这里插入图片描述

(1) InstantiationAwareBeanPostProcessor这个接口有三个方法,执行时机分别如下所示

​ 1)postProcessBeforeInstantiation 实例化前。空方法

​ 2)postProcessAfterInstantiation 属性赋值前,即实例化后。空方法

​ 3)postProcessProperties 属性赋值前,但在postProcessAfterInstantiation 执行之后。实现自动注入功能。

进入CommonAnnotationBeanPostProcessor源码,我们可以发现postProcessBeforeInstantiationpostProcessAfterInstantiation 方法都是空的。重要的方法就是postProcessProperties 这一个,我们稍后看源码。

(2)MergedBeanDefinitionPostProcessor这个接口有两个方法,执行时机分别如下所示

​ 1)postProcessMergedBeanDefinition 实例化后,但在postProcessAfterInstantiation 执行之前。解析@Resource@PostConstruct@PreDestroy的注解信息。

​ 2)resetBeanDefinition

经过上面分析,我们知道最先执行的方法是MergedBeanDefinitionPostProcessorpostProcessMergedBeanDefinition 方法,我们先看这个方法源码。

2 自动注入功能实现

首先看CommonAnnotationBeanPostProcessor的构造方法

public CommonAnnotationBeanPostProcessor() {
    //设置优先级
   setOrder(Ordered.LOWEST_PRECEDENCE - 3);
    //下面这两个类不就是我们常用的设置初始化方法和销毁方法的注解吗
   setInitAnnotationType(PostConstruct.class);
   setDestroyAnnotationType(PreDestroy.class);
   ignoreResourceType("javax.xml.ws.WebServiceContext");
}

2.1 postProcessMergedBeanDefinition

这个方法在bean实例化后首先被执行

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    //2.1.1处理生命周期注解(@PostConstruct、@PreDestroy)
   super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
    //2.1.2处理自动注入注解(@Resource)
   InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}
2.1.1处理生命周期注解(@PostConstruct、@PreDestroy)

去父类的postProcessMergedBeanDefinition方法

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    //(1)找到beanType类的生命周期元数据
   LifecycleMetadata metadata = findLifecycleMetadata(beanType);
    //(2)将生命周期元数据保存到beanDefinition中
   metadata.checkConfigMembers(beanDefinition);
}
(1)找到beanType类的生命周期元数据

这个方法的套路(逻辑)和我们分析AutowiredAnnotationBeanPostProcessor@Autowired注入原理差不多啊,所以说学习spring源码,你只要咬牙坚持下来,后面你会发现越来越容易。

private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
    /**
     * 先查缓存中有没有生命周期元数据
     * this.lifecycleMetadataCache是一个map集合,它的key就是当前类的clazz
     * value是当前类的生命周期元数据
     */
   if (this.lifecycleMetadataCache == null) {
      // Happens after deserialization, during destruction...
       //直接去获取生命周期元数据,重点方法
      return buildLifecycleMetadata(clazz);
   }
   // Quick check on the concurrent map first, with minimal locking.
   LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
   if (metadata == null) {
      synchronized (this.lifecycleMetadataCache) {
         metadata = this.lifecycleMetadataCache.get(clazz);
         if (metadata == null) {
             //直接去获取生命周期元数据
            metadata = buildLifecycleMetadata(clazz);
             //缓存,key就是当前类的clazz
            this.lifecycleMetadataCache.put(clazz, metadata);
         }
         return metadata;
      }
   }
   return metadata;
}

直接去获取生命周期元数据

private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
     /**
      * this.initAnnotationType为PostConstruct.class
      * this.destroyAnnotationType为PreDestroy.class
      * 在CommonAnnotationBeanPostProcessor默认的构造方法中赋值
      * AnnotationUtils.isCandidateClass()是判断clazz中是否存在PostConstruct和PreDestroy注解
      */
   if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
       //不存在PostConstruct和PreDestroy注解,直接返回一个空的生命周期元数据
      return this.emptyLifecycleMetadata;
   }

   List<LifecycleElement> initMethods = new ArrayList<>();
   List<LifecycleElement> destroyMethods = new ArrayList<>();
   Class<?> targetClass = clazz;

   do {
      final List<LifecycleElement> currInitMethods = new ArrayList<>();
      final List<LifecycleElement> currDestroyMethods = new ArrayList<>();

       
     /**
      * ReflectionUtils.doWithLocalMethods()方法很简单,其实就是遍历targetClass所有的
      * 方法,将它作为参数回调接口方法。这个方法我在说@Autowired原理的时候已经详细解释过了,这里
      * 不在多费唇舌
      * 真正的处理逻辑在参数2的lamada表达式中
      */
      ReflectionUtils.doWithLocalMethods(targetClass, method -> {
/****************************处理@PostConstruct注解******************************/         
          //method.isAnnotationPresent()判断方法上有没有指定的注解(反射的知识)
         if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
             //(1)构建LifecycleElement
            LifecycleElement element = new LifecycleElement(method);
             //加入到初始化方法集合中
            currInitMethods.add(element);
            if (logger.isTraceEnabled()) {
               logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
            }
         }
/****************************处理@PreDestroy注解******************************/             
         if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
            currDestroyMethods.add(new LifecycleElement(method));
            if (logger.isTraceEnabled()) {
               logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
            }
         }
      });

       //
      initMethods.addAll(0, currInitMethods);
      destroyMethods.addAll(currDestroyMethods);
       //获取父类,因为父类中也有可能指定了生命周期方法
      targetClass = targetClass.getSuperclass();
   }
   while (targetClass != null && targetClass != Object.class);

    //返回声明周期元数据
   return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
           //(2)构建LifecycleMetadata
         new LifecycleMetadata(clazz, initMethods, destroyMethods));
}

(1) 构建LifecycleElement

public LifecycleElement(Method method) {
 //生命周期方法不能有参数
 if (method.getParameterCount() != 0) {
     throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method);
 }
 this.method = method;
 /**
     * 如果生命周期方法是私有的,identifier就是类或接口的完全限定名+"."+方法名
     * 否则identifier就是方法名
     */
    this.identifier = (Modifier.isPrivate(method.getModifiers()) ?
                       ClassUtils.getQualifiedMethodName(method) : method.getName());
}

(2)构建LifecycleMetadata

public LifecycleMetadata(Class<?> targetClass, Collection<LifecycleElement> initMethods,
                         Collection<LifecycleElement> destroyMethods) {

    //指定当前生命周期元数据所属的类
    this.targetClass = targetClass;
    //指定当前生命周期元数据中类的初始化方法
    this.initMethods = initMethods;
    //指定当前生命周期元数据中类的销毁方法
    this.destroyMethods = destroyMethods;
}
(2)将生命周期元数据保存到beanDefinition中
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
    
/****************************缓存初始化方法******************************/     
    Set<LifecycleElement> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size());
   
    for (LifecycleElement element : this.initMethods) {
        //要么是完全限定名,要么是方法名
        String methodIdentifier = element.getIdentifier();
        //(1)判断methodIdentifier是否已经被指定为初始化方法
        if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
            //(2)没有就将该方法注册为初始化方法
            beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
            //添加到已检查的方法集合中
            checkedInitMethods.add(element);
            if (logger.isTraceEnabled()) {
                logger.trace("Registered init method on class [" + this.targetClass.getName() + "]: " + element);
            }
        }
    }
    
/****************************缓存初销毁方法******************************/   
    //流程都差不多
    Set<LifecycleElement> checkedDestroyMethods = new LinkedHashSet<>(this.destroyMethods.size());
    for (LifecycleElement element : this.destroyMethods) {
        String methodIdentifier = element.getIdentifier();
        if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) {
            beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier);
            checkedDestroyMethods.add(element);
            if (logger.isTraceEnabled()) {
                logger.trace("Registered destroy method on class [" + this.targetClass.getName() + "]: " + element);
            }
        }
    }
    
    this.checkedInitMethods = checkedInitMethods;
    this.checkedDestroyMethods = checkedDestroyMethods;
}

(1)判断methodIdentifier是否已经被指定为生命周期初始化方法

public boolean isExternallyManagedInitMethod(String initMethod) {
synchronized (this.postProcessingLock) {
   return (this.externallyManagedInitMethods != null &&
         this.externallyManagedInitMethods.contains(initMethod));
}
}

(2)将该方法注册为生命周期初始化方法

public void registerExternallyManagedInitMethod(String initMethod) {
synchronized (this.postProcessingLock) {
   if (this.externallyManagedInitMethods == null) {
      this.externallyManagedInitMethods = new HashSet<>(1);
   }
    //set集合,初始化方法不只一个
   this.externallyManagedInitMethods.add(initMethod);
}
}
(3) 生命周期注解方法执行

方法执行是在CommonAnnotationBeanPostProcessorpostProcessBeforeInitialization方法完成的,即bean初始化方法(xml中init-method="xxx",@Bean(initMethod = "xxxx"))调用前执行。

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    //获取所有生命周期元数据
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    try {
        //执行生命周期初始化方法
        metadata.invokeInitMethods(bean, beanName);
    }
    catch (InvocationTargetException ex) {
        throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
    }
    return bean;
}

执行生命周期初始化方法

public void invokeInitMethods(Object target, String beanName) throws Throwable {
    Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
    Collection<LifecycleElement> initMethodsToIterate =
        (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
    if (!initMethodsToIterate.isEmpty()) {
        for (LifecycleElement element : initMethodsToIterate) {
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
            }
            //执行LifecycleElement的invoke方法
            element.invoke(target);
        }
    }
}

执行LifecycleElement的invoke方法

public void invoke(Object target) throws Throwable {
    //反射执行生命周期初始化方法
    ReflectionUtils.makeAccessible(this.method);
    this.method.invoke(target, (Object[]) null);
}

到此有关生命周期注解就处理完成了

2.1.2处理自动注入注解(@Resource)
(1)找到beanType类的注入(注解)元数据
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
    // Fall back to class name as cache key, for backwards compatibility with custom callers.
    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    // Quick check on the concurrent map first, with minimal locking.
    InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    //判断是否需要重新解析clazz
    if (InjectionMetadata.needsRefresh(metadata, clazz)) {
        synchronized (this.injectionMetadataCache) {
            metadata = this.injectionMetadataCache.get(cacheKey);
            if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                if (metadata != null) {
                    metadata.clear(pvs);
                }
                //解析clazz,获取注入(注解)元数据
                metadata = buildResourceMetadata(clazz);
                this.injectionMetadataCache.put(cacheKey, metadata);
            }
        }
    }
    return metadata;
}

解析clazz,获取注入(注解)元数据

在看这个方法之前,必须补充一段代码。这个是CommonAnnotationBeanPostProcessor的类静态代码块,每次创建对象的时候都会执行

static {
    webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");
    ejbClass = loadAnnotationType("javax.ejb.EJB");

    //我们只看这一行代码,他向resourceAnnotationTypes这个集合中添加了Resource的clazz对象
    //实际上就是@Resource注解
    resourceAnnotationTypes.add(Resource.class);
    if (webServiceRefClass != null) {
        resourceAnnotationTypes.add(webServiceRefClass);
    }
    if (ejbClass != null) {
        resourceAnnotationTypes.add(ejbClass);
    }
}
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
    //判断clazz是否包含resourceAnnotationTypes中的注解
    if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
        return InjectionMetadata.EMPTY;
    }

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

    do {
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
        
/********************************处理属性*********************************/
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            //webServiceRef相关,不用管
            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 WebServiceRefElement(field, field, null));
            }
            //ejb相关,不用管
            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 EjbRefElement(field, field, null));
            }
            //这里开始处理有@Resource注解的属性了
            else if (field.isAnnotationPresent(Resource.class)) {
                //@Resource不能加载静态属性上
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException("@Resource annotation is not supported on static fields");
                }
                //默认构造方法上初始化了ignoredResourceTypes="javax.xml.ws.WebServiceContext"
                if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
                    //构建ResourceElement对象加入到currElements集合中
                    //我们看一下ResourceElement的构造方法
                    currElements.add(new ResourceElement(field, field, null));
                }
            }
        });
        
/********************************处理方法*********************************/
        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            //获取桥接方法,你就把它当成一个普通的方法对象
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                return;
            }
            //webServiceRef相关,不用管
            if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                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);
                    }
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
                }
                //ejb相关,不用管
                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);
                    }
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new EjbRefElement(method, bridgedMethod, pd));
                }
                 //这里开始处理有@Resource注解的方法了
                else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
                    //@Resource不能加载静态方法上
                    if (Modifier.isStatic(method.getModifiers())) {
                        throw new IllegalStateException("@Resource annotation is not supported on static methods");
                    }
                    //获取方法所有参数的类型
                    Class<?>[] paramTypes = method.getParameterTypes();
                    //@Resource注解只能加载单参数的方法上
                    if (paramTypes.length != 1) {
                        throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
                    }
                    //忽略参数名字为javax.xml.ws.WebServiceContext的方法
                    if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
                        /**
                         * 该方法在@Autowired注解原理的时候已经说过了
                         * 就是判断当前方法是不是clazz类某个属性的get或set方法,如果是,就
                         * 返回这个属性的属性描述
                         */
                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        //构建ResourceElement对象加入到currElements集合中
                        currElements.add(new ResourceElement(method, bridgedMethod, pd));
                    }
                }
            }
        });

        elements.addAll(0, currElements);
        //接着去找父类的@Resource注解
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);

    //构建InjectionMetadata
    return InjectionMetadata.forElements(elements, clazz);
}

ResourceElement的构造方法

这个构造方法不简单,它做了很重要的事,解析了类成员上面@Resource@Lazy注解信息。不看这个构造方法, 你就不知道后面使用的各种值的来源。

public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
 super(member, pd);
 //获取@Resource注解信息
 Resource resource = ae.getAnnotation(Resource.class);
 //获取注解name属性值
 String resourceName = resource.name();
 //获取注解type属性值
 Class<?> resourceType = resource.type();
 /**
     * this.isDefaultName表示是否使用默认名
     * 注解name属性值为空的时候,就表示使用默认名
     * 属性的名字或者方法名截取后的值
     */
    this.isDefaultName = !StringUtils.hasLength(resourceName);
    //使用默认名
    if (this.isDefaultName) {
        //获取属性名或方法名
        resourceName = this.member.getName();
        //以set开头的方法
        if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
            //实际上就是截取方法名,去掉set,然后将首字母转小写
            resourceName = Introspector.decapitalize(resourceName.substring(3));
        }
    }
    /**
     * CommonAnnotationBeanPostProcessor实现了BeanFactoryAware接口
     * 在这个BeanPostProcessor对象创建过程中会自动调用接口的setBeanFactory()方法
     * 注入BeanFactory对象,
     * 此时会使用BeanFactory创建一个新的EmbeddedValueResolver
     * new EmbeddedValueResolver((ConfigurableBeanFactory) beanFactory);
     *
     * 不使用默认值就调用EmbeddedValueResolver对指定的名字解析一下
     */
    else if (embeddedValueResolver != null) {
        resourceName = embeddedValueResolver.resolveStringValue(resourceName);
    }
    //resourceType的默认值为Object.class
    //此时在@Resource上指定注入类型
    if (Object.class != resourceType) {
        //(1)检查指定的类型resourceType是否匹配属性或方法参数
        checkResourceType(resourceType);
    }
    else {
        // No resource type specified... check field/method.
        //(2)获取注入类型
        resourceType = getResourceType();
    }
    this.name = (resourceName != null ? resourceName : "");
    this.lookupType = resourceType;
    //这个忽略,没用过
    String lookupValue = resource.lookup();
    this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());
    //@Lazy注解处理
    Lazy lazy = ae.getAnnotation(Lazy.class);
    this.lazyLookup = (lazy != null && lazy.value());
}

(1)检查指定的类型resourceType是否匹配属性或方法参数

protected final void checkResourceType(Class<?> resourceType) {
    
/*******************************属性**********************************/    
    if (this.isField) {
        Class<?> fieldType = ((Field) this.member).getType();
        //指定的类型和属性类型必须包含继承关系,否则抛异常
        if (!(resourceType.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(resourceType))) {
            throw new IllegalStateException("Specified field type [" + fieldType +
                                            "] is incompatible with resource type [" + resourceType.getName() + "]");
        }
    }

/*******************************方法**********************************/       
    else {
        /**
     	 * this.pd就是PropertyDescriptor,在上面提到过
     	 * 当有@Resource注解的方法是当前类某个属性的get或set方法时,
     	 * 就返回这个属性的属性描述PropertyDescriptor,然后设置到ResourceElement中
     	 * 所以:
     	 * 如果该方法是某个属性的get或set方法,就检查这个属性的类型和指定类型的继承关系
     	 * 否则就检查方法第一个参数的类型和指定类型的继承关系
     	 */
        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() + "]");
        }
    }
}

(2)获取注入类型

protected final Class<?> getResourceType() {
    //获取属性类型
    if (this.isField) {
        return ((Field) this.member).getType();
    }
    //方法是对应属性的get或set方法,此时获取属性类型
    else if (this.pd != null) {
        return this.pd.getPropertyType();
    }
    //获取方法第一个参数类型
    else {
        return ((Method) this.member).getParameterTypes()[0];
    }
}
(2)将注入(注解)元数据保存到beanDefinition中
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
    Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
    //遍历
    for (InjectedElement element : this.injectedElements) {
        Member member = element.getMember();
        //将当前需要自动注入的属性或方法保存到BeanDefinition中
        if (!beanDefinition.isExternallyManagedConfigMember(member)) {
            beanDefinition.registerExternallyManagedConfigMember(member);
            checkedElements.add(element);
        }
    }
    this.checkedElements = checkedElements;
}
(3)执行自动注入

首先你得明白一点,spring中注解方式的自动注入都是在InstantiationAwareBeanPostProcessorpostProcessProperties方法完成的

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    //获取@Resource注解的注入元数据,前面已经讲过了
    InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
    try {
        //执行注入
        metadata.inject(bean, beanName, pvs);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
    }
    return pvs;
}

执行注入

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) {
            //无论是属性或方法都封装为ResourceElement
            element.inject(target, beanName, pvs);
        }
    }
}

调用ResourceElementinject方法,实现byName自动注入

/**
 * Either this or {@link #getResourceToInject} needs to be overridden.
 */
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
    throws Throwable {

/*********************************属性******************************/    
    if (this.isField) {
        Field field = (Field) this.member;
        //不需要set方法,直接强行赋值
        ReflectionUtils.makeAccessible(field);
   
        //getResourceToInject(target, requestingBeanName)重点是这个方法
        field.set(target, getResourceToInject(target, requestingBeanName));
    }
    
/*********************************方法******************************/        
    else {
        if (checkPropertySkipping(pvs)) {
            return;
        }
        try {
            Method method = (Method) this.member;
            //不管方法的修饰符,强行执行方法
            ReflectionUtils.makeAccessible(method);
            method.invoke(target, getResourceToInject(target, requestingBeanName));
        }
        catch (InvocationTargetException ex) {
            throw ex.getTargetException();
        }
    }
}

getResourceToInject(target, requestingBeanName), 它会去spring容器中获取requestingBeanName对应的bean对象。

protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
    /**
	 * (1)懒加载自动注入,创建一个代理对象返回
	 * (2)否则直接去spring容器中获取requestingBeanName对应的bean对象
 	 */
    return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
            getResource(this, requestingBeanName));
}

(1)懒加载自动注入,获取代理对象

/**
 * Obtain a lazily resolving resource proxy for the given name and type,
 * delegating to {@link #getResource} on demand once a method call comes in.
 * @param element the descriptor for the annotated field/method
 * @param requestingBeanName the name of the requesting bean
 * @return the resource object (never {@code null})
 * @since 4.2
 * @see #getResource
 * @see Lazy
 */
protected Object buildLazyResourceProxy(final LookupElement element, final @Nullable String requestingBeanName) {
    //创建一个目标资源
    TargetSource ts = new TargetSource() {
        @Override
        public Class<?> getTargetClass() {
            return element.lookupType;
        }
        @Override
        public boolean isStatic() {
            return false;
        }
        @Override
        public Object getTarget() {
            //代理类的目标对象也是getResource方法获取的
            return getResource(element, requestingBeanName);
        }
        @Override
        public void releaseTarget(Object target) {
        }
    };
    //代理工厂
    ProxyFactory pf = new ProxyFactory();
    pf.setTargetSource(ts);
    //设置接口
    if (element.lookupType.isInterface()) {
        pf.addInterface(element.lookupType);
    }
    //类加载器
    ClassLoader classLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
                               ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() : null);
    //获取代理对象
    return pf.getProxy(classLoader);
}

获取代理对象的流程还是比较简单的,我这里不再深究。

(2)非懒加载自动注入,获取原对象

/**
 * Obtain the resource object for the given name and type.
 * @param element the descriptor for the annotated field/method
 * @param requestingBeanName the name of the requesting bean
 * @return the resource object (never {@code null})
 * @throws NoSuchBeanDefinitionException if no corresponding target resource found
 */
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);
    }
    //上面两个不用管,jndi相关,没用过
    if (this.resourceFactory == null) {
        throw new NoSuchBeanDefinitionException(element.lookupType,
                                                "No resource factory configured - specify the 'resourceFactory' property");
    }
    //获取匹配的依赖对象
    return autowireResource(this.resourceFactory, element, requestingBeanName);
}

获取匹配的依赖对象

/**
 * Obtain a resource object for the given name and type through autowiring
 * based on the given factory.
 * @param factory the factory to autowire against
 * @param element the descriptor for the annotated field/method
 * @param requestingBeanName the name of the requesting bean 
 * requestingBeanName就是postProcessProperties方法的beanName参数,代表当前赋值阶段bean的名字
 * @return the resource object (never {@code null})
 * @throws NoSuchBeanDefinitionException if no corresponding target resource found
 */
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;
        /**
         * 获取依赖描述
         * 实际上就是
         * new LookupDependencyDescriptor((Field) this.member, this.lookupType);
         * new LookupDependencyDescriptor((Method) this.member, this.lookupType);
         */
        DependencyDescriptor descriptor = element.getDependencyDescriptor();
        /**
         * 按类型获取依赖对象
         * 此时!factory.containsBean(name)成立,容器中没有默认名对应的bean
         */
        if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
            autowiredBeanNames = new LinkedHashSet<>();
            //使用beanFactory解析依赖描述,获取依赖bean对象
            //该方法上篇文章已经讲过,此处不再赘述,这个方法是核心重点方法,一定要看懂
            resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
            if (resource == null) {
                throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
            }
        }
        //按指定名name获取依赖对象
        else {
            //本质上就是factory.getBean(name, element.lookupType);
            resource = beanFactory.resolveBeanByName(name, descriptor);
            autowiredBeanNames = Collections.singleton(name);
        }
    }
    //按指定名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;
}

总结:(1)没有指定@Resource注解中的name属性时,先判断容器中是否包含默认名对应的bean,不包含就按类型注入,否则就按默认名获取依赖对象。

(2)指定@Resource注解中的name属性时,直接按照指定的name获取依赖对象。

至此,@Resource注解的注入流程就已经讲完了。

3 总结

(1)@PostConstruct@PreDestroy@Resource均在MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition被解析。除此之外,这个方法还会将这几个注解标注的成员记录到BeanDefinition中。

(2)@Resource的自动注入功能是在InstantiationAwareBeanPostProcessor接口的postProcessProperties方法中完成的。

(3)@Resource的自动注入不单是ByName,当我们手动指定@Resource注解中的name属性时,直接按照指定的name获取依赖对象。否则会先判断容器中有没有默认名(属性名或方法名截取set或第一个参数名)对应的bean,有就注入该bean,无就按类型注入。

(4)@Resource标注在方法上,方法有且只能有一个参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值