全方位解析Spring IoC:(八)源码分析——Bean的注解解析

由于掘金文章存在字数限制,本文拆开了各个章节分开发布,全文可点击以下链接进行阅读:blog.omghaowan.com/archives/sp...

Spring中,对于声明式注解的解析基本上离不开BeanFactoryPostProcessorBeanPostProcessor两大后置处理器,因此对于bean注解的解析下文将分别通过BeanFactoryPostProcessorBeanPostProcessor两大后置处理器为切入点详细展开。

CommonAnnotationBeanPostProcessor

对于@Resource注解、@PostConstruct注解和@PreDestroy注解的解析与处理Spring都是通过CommonAnnotationBeanPostProcessor来完成。也就是说,如果我们要让@Resource注解、@PostConstruct注解和@PreDestroy注解生效,就需要将CommonAnnotationBeanPostProcessor注册到Spring容器中。

java 复制代码
/**
 * ...
 *
 * <p>This post-processor includes support for the {@link javax.annotation.PostConstruct}
 * and {@link javax.annotation.PreDestroy} annotations - as init annotation
 * and destroy annotation, respectively - through inheriting from
 * {@link InitDestroyAnnotationBeanPostProcessor} with pre-configured annotation types.
 *
 * <p>The central element is the {@link javax.annotation.Resource} annotation
 * for annotation-driven injection of named beans, by default from the containing
 * Spring BeanFactory, with only {@code mappedName} references resolved in JNDI.
 * The {@link #setAlwaysUseJndiLookup "alwaysUseJndiLookup" flag} enforces JNDI lookups
 * equivalent to standard Java EE 5 resource injection for {@code name} references
 * and default names as well. The target beans can be simple POJOs, with no special
 * requirements other than the type having to match.
 *
 * ...
 *
 * <p><b>NOTE:</b> A default CommonAnnotationBeanPostProcessor will be registered
 * by the "context:annotation-config" and "context:component-scan" XML tags.
 * Remove or turn off the default annotation configuration there if you intend
 * to specify a custom CommonAnnotationBeanPostProcessor bean definition!
 * <p><b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection; thus
 * the latter configuration will override the former for properties wired through
 * both approaches.
 * 
 */
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, ... {
    ...
}

虽说@Resource注解、@PostConstruct注解和@PreDestroy注解都是通过CommonAnnotationBeanPostProcessor来使其生效,但实际上它们之间的实现原理确是有所不同,因此针对每个注解各自的生效原理下面将分点进行阐述(@PreDestroy注解暂不分析)。

解析@Resource

对于@Resource注解的解析,CommonAnnotationBeanPostProcessor在初始化时首先会将Resource注解类添加到resourceAnnotationTypes属性上。

java 复制代码
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, ... {

    private static final Set<Class<? extends Annotation>> resourceAnnotationTypes = new LinkedHashSet<>(4);

    static {
        resourceAnnotationTypes.add(Resource.class);
        
        // ...
    }
    
}

然后,在bean属性加载的后置处理postProcessProperties方法(具体可阅读上文《源码分析:Bean的创建》章节)中,Spring会完成对被@Resource注解标记字段和方法的依赖加载和依赖注入。

java 复制代码
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
    // 忽略异常处理
    metadata.inject(bean, beanName, pvs);
    return pvs;
}

postProcessProperties方法的实现上,Spring会按照以下2个步骤执行:

  1. 通过findResourceMetadata方法查询/构建出标记了注解的字段/方法。
  2. 通过InjectedElement#inject方法完成对被标记字段/方法的依赖加载与依赖注入。
  • 1、查询/构建出标记了注解的字段/方法。

    findResourceMetadata方法中,Spring会通过反射机制将bean中被标注了@Resource的字段/方法封装为ResourceElement对象。

    java 复制代码
    private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
        // 忽略缓存处理
        InjectionMetadata metadata = buildResourceMetadata(clazz);
        return metadata;
    }
    
    private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
        // ...
        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;
    
        do {
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
    
            // 通过反射机制获取标注了注解的字段,并将他封装为ResourceElement并添加到currElements中
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                // ...
                if (field.isAnnotationPresent(Resource.class)) {
                    // 假设field为非静态字段
                    currElements.add(new ResourceElement(field, field, null));
                }
            });
    
            // 通过反射机制获取标注了注解的方法,并将他封装为ResourceElement添加到currElements中
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                // 可简单理解为method
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                // ...
                if (bridgedMethod.isAnnotationPresent(Resource.class)) {
                    // 假设method为非静态方法
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new ResourceElement(method, bridgedMethod, pd));
                }
            });
    
            elements.addAll(0, currElements);
            // 由下至上遍历父类
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);
    
        return InjectionMetadata.forElements(elements, clazz);
    }

    在实现上findResourceMetadata会将真正构建ResourceElement对象的逻辑委托给buildResourceMetadata来完成。在buildResourceMetadata中会分别通过反射机制获取并封装bean中被@Resource注解标注的字段和方法,并最终返回InjectionMetadata对象(含InjectionMetadata.InjectedElement列表)。

    关于Bridge method,源自Java泛型擦除的解决方案。在编译继承了泛型的类或者接口时,由于泛型擦除导致了方法覆盖失效,Java会特地生成的与其泛型擦除后对应的方法,这个方法我们就称之为Bridge method

    更多详情我们可以阅读以下链接:

  • 2、完成对被标记字段/方法的依赖加载与依赖注入。

    ResourceElement封装完成后,紧接着就是执行InjectedElement#inject方法完成对bean的加载与注入。而由于ResourceElement并没有对其进行方法覆盖,因此执行的是InjectedElement基类中定义的InjectedElement#inject逻辑,即:

    java 复制代码
    /**
     * A single injected element.
     */
    public abstract static class InjectedElement {
    
        protected final Member member;
    
        protected final boolean isField;
    
        @Nullable
        protected final PropertyDescriptor pd;
    
        protected InjectedElement(Member member, @Nullable PropertyDescriptor pd) {
            this.member = member;
            this.isField = (member instanceof Field);
            this.pd = pd;
        }
    
        /**
         * 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;
                ReflectionUtils.makeAccessible(field);
                field.set(target, getResourceToInject(target, requestingBeanName));
            
            }
            else {
                
                Method method = (Method) this.member;
                ReflectionUtils.makeAccessible(method);
                method.invoke(target, getResourceToInject(target, requestingBeanName));
            
            }
        }
    
        /**
         * Either this or {@link #inject} needs to be overridden.
         */
        @Nullable
        protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
            return null;
        }
    
    }

    显然,在InjectedElement#inject中会通过Java反射机制对字段属性进行赋值或者对方法进行调用。其中,对于属性值的获取和解析Spring在这里是通过可继承的getResourceToInject方法来完成,这就需要回到ResourceElement#getResourceToInject的定义上了。

    java 复制代码
    public class CommonAnnotationBeanPostProcessor extends ... implements ... {
        
        private class ResourceElement extends LookupElement {
    
            @Override
            protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
                // 忽略Lazy的处理
                return getResource(this, requestingBeanName);
            }
        }
        
        /**
         * Obtain the resource object for the given name and type.
         */
        protected Object getResource(LookupElement element, @Nullable String requestingBeanName) ... {
            // 忽略JNDI的处理
            // 通过BeanFactory获取和解析参数指定的依赖
            return autowireResource(this.resourceFactory, element, requestingBeanName);
        }
    
    
        /**
         * Obtain a resource object for the given name and type through autowiring
         * based on the given factory.
         * @return the resource object (never {@code null})
         */
        protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName) ... {
            // ...
            Object resource = BeanFactory#getBean(...);
            return resource;
        }
    }

    最终,Spring经过层层委托执行BeanFactory#getBean获取和解析参数所指定的依赖并返回到InjectedElement#inject进行注入。

至此,在CommonAnnotationBeanPostProcessor中完成了对@Resource注解的解析与处理。

解析@PostConstruct

对于@PostConstruct注解,表面上Spring是通过CommonAnnotationBeanPostProcessor来使其生效,但实际上是CommonAnnotationBeanPostProcessor通过继承的InitDestroyAnnotationBeanPostProcessor来使其最终发挥作用的。

在实现上,InitDestroyAnnotationBeanPostProcessor并没有特殊指定@PostConstruct注解作为标记初始化方法的注解,而是提供了InitDestroyAnnotationBeanPostProcessor#setInitAnnotationType方法让客户端可以进行自定义设置。根据这个设定不难猜出,CommonAnnotationBeanPostProcessor在继承InitDestroyAnnotationBeanPostProcessor类的时候就向InitDestroyAnnotationBeanPostProcessor设置了@PostConstruct注解作为标记初始化方法的注解,具体如下所示:

java 复制代码
/**
 * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
 * that supports common Java annotations out of the box, in particular the common
 * annotations in the {@code jakarta.annotation} package. These common Java
 * annotations are supported in many Jakarta EE technologies (e.g. JSF and JAX-RS).
 *
 * <p>This post-processor includes support for the {@link jakarta.annotation.PostConstruct}
 * and {@link jakarta.annotation.PreDestroy} annotations - as init annotation
 * and destroy annotation, respectively - through inheriting from
 * {@link InitDestroyAnnotationBeanPostProcessor} with pre-configured annotation types.
 * 
 * ... 
 */
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, ... {
    /**
     * Create a new CommonAnnotationBeanPostProcessor,
     * with the init and destroy annotation types set to
     * {@link jakarta.annotation.PostConstruct} and {@link jakarta.annotation.PreDestroy},
     * respectively.
     */
    public CommonAnnotationBeanPostProcessor() {
        setInitAnnotationType(PostConstruct.class);
        // ...
    }   
}

public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, ... {

    @Nullable
    private Class<? extends Annotation> initAnnotationType;

    /**
     * Specify the init annotation to check for, indicating initialization
     * methods to call after configuration of a bean.
     * <p>Any custom annotation can be used, since there are no required
     * annotation attributes. There is no default, although a typical choice
     * is the {@link jakarta.annotation.PostConstruct} annotation.
     */
    public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
        this.initAnnotationType = initAnnotationType;
    }
}

在上述代码中我们可以看到,Spring在构造CommonAnnotationBeanPostProcessor时就将@PostConstruct注解类设置到InitDestroyAnnotationBeanPostProcessorinitAnnotationType属性上了。

在完成了initAnnotationType属性的初始化后,顺着bean的创建流程执行到BeanPostProcessor的前置处理方法postProcessBeforeInitialization时,Spring会通过InitDestroyAnnotationBeanPostProcessor#findLifecycleMetadata方法查找出对应的生命周期方法,然后调用LifecycleMetadata#invokeInitMethods进行初始化。

java 复制代码
/**
 * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
 * that invokes annotated init and destroy methods. Allows for an annotation
 * alternative to Spring's {@link org.springframework.beans.factory.InitializingBean}
 * and {@link org.springframework.beans.factory.DisposableBean} callback interfaces.
 *
 * <p>The actual annotation types that this post-processor checks for can be
 * configured through the {@link #setInitAnnotationType "initAnnotationType"}
 * and {@link #setDestroyAnnotationType "destroyAnnotationType"} properties.
 * Any custom annotation can be used, since there are no required annotation
 * attributes.
 *
 * <p>Init and destroy annotations may be applied to methods of any visibility:
 * public, package-protected, protected, or private. Multiple such methods
 * may be annotated, but it is recommended to only annotate one single
 * init method and destroy method, respectively.
 *
 * <p>Spring's {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor}
 * supports the {@link jakarta.annotation.PostConstruct} and {@link jakarta.annotation.PreDestroy}
 * annotations out of the box, as init annotation and destroy annotation, respectively.
 * 
 * ...
 */
public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, ... {

    @Nullable
    private Class<? extends Annotation> initAnnotationType;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
        metadata.invokeInitMethods(bean, beanName);
        return bean;
    }
}

其中,在findLifecycleMetadata方法会通过反射遍历类及其父类中标记了@PostConstruct注解的方法,并将其封装为LifecycleMetadata对象返回。

java 复制代码
public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, ... {

    private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
        // 忽略缓存的处理
        return buildLifecycleMetadata(clazz);
    }

    private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
        // ...

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

        // 通过反射遍历类及其父类中标记了`@PostConstruct`注解的方法
        do {
            final List<LifecycleElement> currInitMethods = new ArrayList<>();

            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
                    LifecycleElement element = new LifecycleElement(method);
                    currInitMethods.add(element);
                }
            });

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

        // 假设存在
        return new LifecycleMetadata(clazz, initMethods, destroyMethods));
    }


    /**
     * Class representing information about annotated init and destroy methods.
     */
    private class LifecycleMetadata {

        private final Class<?> targetClass;

        private final Collection<LifecycleElement> initMethods;

        private volatile Set<LifecycleElement> checkedInitMethods;

        public LifecycleMetadata(Class<?> targetClass, Collection<LifecycleElement> initMethods, ...) {
            this.targetClass = targetClass;
            this.initMethods = initMethods;
        }
    }

    /**
     * Class representing injection information about an annotated method.
     */
    private static class LifecycleElement {

        private final Method method;

        public LifecycleElement(Method method) {
            // 假设method符合条件
            this.method = method;
        }

        // ...
    }

}

在完成了LifecycleMetadata对象(含标记有@PostConstruct注解的方法)后,Spring就会通过LifecycleMetadata#invokeInitMethods方法完成对初始化方法的调用了(通过反射的方式完成方法的调用)。

java 复制代码
public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, ... {
    /**
     * Class representing information about annotated init and destroy methods.
     */
    private class LifecycleMetadata {

        private final Class<?> targetClass;

        private final Collection<LifecycleElement> initMethods;

        private volatile Set<LifecycleElement> checkedInitMethods;

        public void invokeInitMethods(Object target, String beanName) throws Throwable {
            Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
            Collection<LifecycleElement> initMethodsToIterate =
                    (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
            // 假设initMethodsToIterate不为空
            for (LifecycleElement element : initMethodsToIterate) {
                element.invoke(target);
            }
        }
    }

    /**
     * Class representing injection information about an annotated method.
     */
    private static class LifecycleElement {

        private final Method method;

        // ...

        public void invoke(Object target) throws Throwable {
            ReflectionUtils.makeAccessible(this.method);
            this.method.invoke(target, (Object[]) null);
        }
    }

}

至此,SpringBeanPostProcessor的前置处理方法postProcessBeforeInitialization上完成了对被外部管理的initMethod的调用(使用@PostConstruct注解所标注的initMethod方法)。

那对于externallyManagedInitMethods属性,Spring是在什么时候对它进行修改来避免在invokeInitMethods方法中被同时调用了呢?

对于externallyManagedInitMethods属性的变更,实际上是InitDestroyAnnotationBeanPostProcessor使用了MergedBeanDefinitionPostProcessor提供的扩展点提前完成的(相对于BeanPostProcessor),下面我们可以看到MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法:

java 复制代码
public class InitDestroyAnnotationBeanPostProcessor implements MergedBeanDefinitionPostProcessor, ... {

    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        findInjectionMetadata(beanDefinition, beanType);
    }

    private LifecycleMetadata findInjectionMetadata(RootBeanDefinition beanDefinition, Class<?> beanType) {
        LifecycleMetadata metadata = findLifecycleMetadata(beanType);
        metadata.checkConfigMembers(beanDefinition);
        return metadata;
    }

    /**
     * Class representing information about annotated init and destroy methods.
     */
    private class LifecycleMetadata {

        private final Collection<LifecycleElement> initMethods;

        private volatile Set<LifecycleElement> checkedInitMethods;

        public void checkConfigMembers(RootBeanDefinition beanDefinition) {
            Set<LifecycleElement> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size());
            for (LifecycleElement element : this.initMethods) {
                String methodIdentifier = element.getIdentifier();
                if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
                    // 注册到externallyManagedInitMethods属性
                    beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
                    checkedInitMethods.add(element);
                }
            }

            // ...忽略destroyMethod的处理

            this.checkedInitMethods = checkedInitMethods;
        }
    }

}

postProcessMergedBeanDefinition方法首先会将处理委托给了findInjectionMetadata方法,接着findInjectionMetadata方法会提前完成findLifecycleMetadata方法的调用,最后使用LifecycleMetadata对象的checkConfigMembers方法完成了externallyManagedInitMethods属性的变更。需要注意,为了能够更清晰的理解初始化的逻辑,笔者贴出的上述代码是简化后的(例如,对于findLifecycleMetadata方法由于存在多次的调用,实际上Spring是做了缓存处理的),有兴趣的读者可以再去阅读Spring的完整版源码。

最后,结合上文《源码分析:Bean的创建》章节中提到Spring使用激活bean初始化的invokeInitMethods方法中执行的顺序,即:

  1. InitializingBean#afterPropertiesSet()方法
  2. init()方法(自定义配置)

在添加@PostConstruct注解标记初始化方法后(Spring将这种类型的init方法称之为被外部管理的initMethod),bean整体的初始化方法执行顺序演变如下:

  1. @PostConstruct注解方法(被外部管理的initMethod
  2. InitializingBean#afterPropertiesSet()方法
  3. init()方法(自定义配置)

AutowiredAnnotationBeanPostProcessor

对于@Autowired注解、@Inject注解和@Value注解的解析与处理Spring都是通过AutowiredAnnotationBeanPostProcessor来完成。也就是说,如果我们要让@Autowired注解、@Inject注解和@Value注解生效,就需要将AutowiredAnnotationBeanPostProcessor注册到Spring容器中。

java 复制代码
/**
 * {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}
 * implementation that autowires annotated fields, setter methods, and arbitrary
 * config methods. Such members to be injected are detected through annotations:
 * by default, Spring's {@link Autowired @Autowired} and {@link Value @Value}
 * annotations.
 * 
 * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
 * if available, as a direct alternative to Spring's own {@code @Autowired}.
 * 
 * ...
 *
 * <h3>Annotation Config vs. XML Config</h3>
 * <p>A default {@code AutowiredAnnotationBeanPostProcessor} will be registered
 * by the "context:annotation-config" and "context:component-scan" XML tags.
 * Remove or turn off the default annotation configuration there if you intend
 * to specify a custom {@code AutowiredAnnotationBeanPostProcessor} bean definition.
 *
 * ...
 * 
 */
public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, ... {
    
    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);

    public AutowiredAnnotationBeanPostProcessor() {
        this.autowiredAnnotationTypes.add(Autowired.class);
        this.autowiredAnnotationTypes.add(Value.class);
        // 忽略异常处理
        this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
                ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
    }

}

首先,在AutowiredAnnotationBeanPostProcessor构造器中就会将@Autowired注解、@Inject注解和@Value注解的Class类型添加到autowiredAnnotationTypes中,然后在bean属性加载的后置处理postProcessProperties方法(具体可阅读上文《源码分析:Bean的创建》章节)中,Spring会完成对被标记字段和方法的依赖加载和依赖注入。

java 复制代码
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    // 假设没有异常
    metadata.inject(bean, beanName, pvs);
    return pvs;
}

postProcessProperties方法中,Spring会按照以下2个步骤执行:

  1. 通过findAutowiringMetadata方法查询/构建出标记了注解的字段/方法。
  2. 通过InjectionMetadata.InjectedElement#inject方法完成对被标记字段/方法的依赖加载与依赖注入。
  • 1、查询/构建出标记了注解的字段/方法。

    findAutowiringMetadata方法中,Spring会通过反射机制获取并封装bean中字段/方法为InjectionMetadata.InjectedElement对象。

    java 复制代码
    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
        // 忽略对缓存的处理
        InjectionMetadata metadata = buildAutowiringMetadata(clazz);
        return metadata;
    }
    
    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        // ...
        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;
    
        do {
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
    
            // 通过反射机制获取标注了注解的字段,并将他封装为InjectionMetadata.InjectedElement添加到currElements中
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                // 查找并过滤出标注了注解的字段
                MergedAnnotation<?> ann = findAutowiredAnnotation(field);
                if (ann != null) {
                    // 假设field为非静态字段
                    boolean required = ...;
                    currElements.add(new AutowiredFieldElement(field, required));
                }
            });
    
            // 通过反射机制获取标注了注解的方法,并将他封装为InjectionMetadata.InjectedElement添加到currElements中
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                // 可简单理解为method
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                // ...
                // 查找并过滤出标注了注解的方法
                MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
                if (ann != null && ...) {
                    // 假设method为非静态方法
                    boolean required = ...;
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new AutowiredMethodElement(method, required, pd));
                }
            });
    
            elements.addAll(0, currElements);
            // 由下至上遍历父类
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);
    
        return InjectionMetadata.forElements(elements, clazz);
    }
    
    @Nullable
    private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
        MergedAnnotations annotations = MergedAnnotations.from(ao);
        // 在AutowiredAnnotationBeanPostProcessor的构造器中@Autowired注解类、@Inject注解类和@Value注解类添加到autowiredAnnotationTypes属性中
        for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
            MergedAnnotation<?> annotation = annotations.get(type);
            if (annotation.isPresent()) {
                return annotation;
            }
        }
        return null;
    }

    在实现上findAutowiringMetadata会将真正构建InjectionMetadata.InjectedElement对象的逻辑委托给buildAutowiringMetadata来完成。在buildAutowiringMetadata中会分别通过反射机制获取并封装bean中被注解标注的字段和方法,并最终返回InjectionMetadata对象(含InjectionMetadata.InjectedElement列表)。

    关于Bridge method,源自Java泛型擦除的解决方案。在编译继承了泛型的类或者接口时,由于泛型擦除导致了方法覆盖失效,Java会特地生成的与其泛型擦除后对应的方法,这个方法我们就称之为Bridge method

    更多详情我们可以阅读以下链接:

  • 2、完成对被标记字段/方法的依赖加载与依赖注入。

    在完成对bean中字段/方法的封装后,Spring接着会执行其中的InjectedElement#inject方法完成对bean的加载与注入。而封装字段的AutowiredFieldElement类和封装方法的AutowiredMethodElement类都对inject方法进行了覆盖,下面我们来看看它是如何实现的:

    AutowiredFieldElement中,Spring首先会使用BeanFactory来获取和解析字段中的依赖属性(如有),然后在使用反射机制完成属性值的注入。

    java 复制代码
    /**
     * Class representing injection information about an annotated field.
     */
    private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
    
        private final boolean required;
    
        public AutowiredFieldElement(Field field, boolean required) {
            super(field, null);
            this.required = required;
        }
    
        @Override
        protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
            Field field = (Field) this.member;
            // 解析属性值
            Object value = resolveFieldValue(field, bean, beanName);
            if (value != null) {
                // 设置属性值
                ReflectionUtils.makeAccessible(field);
                field.set(bean, value);
            }
        }
    
        @Nullable
        private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
            DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
            desc.setContainingClass(bean.getClass());
            // ...
            // 通过BeanFactory获取和解析指定的依赖
            Object value = beanFactory.resolveDependency(desc, beanName, ...);
            return value;
        }
    }

    AutowiredFieldElement相似的,在AutowiredMethodElementSpring会使用BeanFactory对方法参数中依赖的属性(如有)逐个进行获取和解析,然后在使用反射机制将属性值传入方法中进行调用。

    java 复制代码
    /**
     * Class representing injection information about an annotated method.
     */
    private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {
    
        private final boolean required;
    
        public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {
            super(method, pd);
            this.required = required;
        }
    
        @Override
        protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
            // 忽略缓存和异常的处理
            Method method = (Method) this.member;
            // 解析方法参数
            Object[] arguments = resolveMethodArguments(method, bean, beanName);
            if (arguments != null) {
                // 使用方法参数调用方法
                ReflectionUtils.makeAccessible(method);
                method.invoke(bean, arguments);
            }
        }
    
        @Nullable
        private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
            int argumentCount = method.getParameterCount();
            Object[] arguments = new Object[argumentCount];
    
            // ...
            for (int i = 0; i < arguments.length; i++) {
                MethodParameter methodParam = new MethodParameter(method, i);
                DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
                currDesc.setContainingClass(bean.getClass());
                // 通过BeanFactory获取和解析指定的依赖
                Object arg = beanFactory.resolveDependency(currDesc, beanName, ...);
                if (arg == null && !this.required) {
                    arguments = null;
                    break;
                }
                arguments[i] = arg;
            
            }
            return arguments;
        }
    }

除此之外,在AutowiredAnnotationBeanPostProcessor中还对标注在方法中的@Lookup注解完成了解析。在实现上,Spring会在determineCandidateConstructors方法中通过反射机制获取标注了Lookup注解的方法,然后将它添加到BeanFactory中对应RootBeanDefinitionmethodOverrides属性上。

java 复制代码
/*
 * <h3>{@literal @}Lookup Methods</h3>
 * <p>In addition to regular injection points as discussed above, this post-processor
 * also handles Spring's {@link Lookup @Lookup} annotation which identifies lookup
 * methods to be replaced by the container at runtime. This is essentially a type-safe
 * version of {@code getBean(Class, args)} and {@code getBean(String, args)}.
 * See {@link Lookup @Lookup's javadoc} for details.
 */
public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, ... {

    @Override
    @Nullable
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
            throws BeanCreationException {
    
        // 忽略重复处理等判断
        Class<?> targetClass = beanClass;
        do {
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                Lookup lookup = method.getAnnotation(Lookup.class);
                if (lookup != null) {
                    LookupOverride override = new LookupOverride(method, lookup.value());
                    RootBeanDefinition mbd = (RootBeanDefinition)this.beanFactory.getMergedBeanDefinition(beanName);
                    mbd.getMethodOverrides().addOverride(override);
                }
            });
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);
         
    
        // ...处理构造器解析
    }
}

至此,在AutowiredAnnotationBeanPostProcessor中完成了对@Inject注解和@Value注解的解析与处理。

相关推荐
qq_441996053 分钟前
Mybatis官方生成器使用示例
java·mybatis
巨大八爪鱼10 分钟前
XP系统下用mod_jk 1.2.40整合apache2.2.16和tomcat 6.0.29,让apache可以同时访问php和jsp页面
java·tomcat·apache·mod_jk
码上一元2 小时前
SpringBoot自动装配原理解析
java·spring boot·后端
计算机-秋大田2 小时前
基于微信小程序的养老院管理系统的设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
魔道不误砍柴功4 小时前
简单叙述 Spring Boot 启动过程
java·数据库·spring boot
失落的香蕉4 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
枫叶_v4 小时前
【SpringBoot】22 Txt、Csv文件的读取和写入
java·spring boot·后端
wclass-zhengge4 小时前
SpringCloud篇(配置中心 - Nacos)
java·spring·spring cloud
路在脚下@4 小时前
Springboot 的Servlet Web 应用、响应式 Web 应用(Reactive)以及非 Web 应用(None)的特点和适用场景
java·spring boot·servlet
黑马师兄4 小时前
SpringBoot
java·spring