由于掘金文章存在字数限制,本文拆开了各个章节分开发布,全文可点击以下链接进行阅读:blog.omghaowan.com/archives/sp...
在Spring
中,对于声明式注解的解析基本上离不开BeanFactoryPostProcessor
和BeanPostProcessor
两大后置处理器,因此对于bean
注解的解析下文将分别通过BeanFactoryPostProcessor
和BeanPostProcessor
两大后置处理器为切入点详细展开。
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
个步骤执行:
- 通过
findResourceMetadata
方法查询/构建出标记了注解的字段/方法。 - 通过
InjectedElement#inject
方法完成对被标记字段/方法的依赖加载与依赖注入。
-
1、查询/构建出标记了注解的字段/方法。
在
findResourceMetadata
方法中,Spring
会通过反射机制将bean
中被标注了@Resource
的字段/方法封装为ResourceElement
对象。javaprivate 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
的定义上了。javapublic 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
注解类设置到InitDestroyAnnotationBeanPostProcessor
的initAnnotationType
属性上了。
在完成了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);
}
}
}
至此,Spring
在BeanPostProcessor
的前置处理方法postProcessBeforeInitialization
上完成了对被外部管理的initMethod
的调用(使用@PostConstruct
注解所标注的initMethod
方法)。
那对于
externallyManagedInitMethods
属性,Spring
是在什么时候对它进行修改来避免在invokeInitMethods
方法中被同时调用了呢?对于
externallyManagedInitMethods
属性的变更,实际上是InitDestroyAnnotationBeanPostProcessor
使用了MergedBeanDefinitionPostProcessor
提供的扩展点提前完成的(相对于BeanPostProcessor
),下面我们可以看到MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
方法:
javapublic 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
方法中执行的顺序,即:
InitializingBean#afterPropertiesSet()
方法init()
方法(自定义配置)
在添加@PostConstruct
注解标记初始化方法后(Spring
将这种类型的init
方法称之为被外部管理的initMethod
),bean
整体的初始化方法执行顺序演变如下:
@PostConstruct
注解方法(被外部管理的initMethod
)InitializingBean#afterPropertiesSet()
方法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
个步骤执行:
- 通过
findAutowiringMetadata
方法查询/构建出标记了注解的字段/方法。 - 通过
InjectionMetadata.InjectedElement#inject
方法完成对被标记字段/方法的依赖加载与依赖注入。
-
1、查询/构建出标记了注解的字段/方法。
在
findAutowiringMetadata
方法中,Spring
会通过反射机制获取并封装bean
中字段/方法为InjectionMetadata.InjectedElement
对象。javaprivate 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
相似的,在AutowiredMethodElement
中Spring
会使用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
中对应RootBeanDefinition
的methodOverrides
属性上。
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
注解的解析与处理。