CommonAnnotationBeanPostProcessor 注解主要是来实现 @PostConstruct
、@PreDestroy
、@Resource
、@WebServiceRef
等注解相关功能的。
注入
前面分析过,在 AnnotationConfigApplicationContext
初始化时候,会注入一些BeanPostProcessor
:
在初始化 `AnnotationConfigApplicationContext` 时候,会网beanDefs中加入一些默认配置bean:
- `org.springframework.context.annotation.internalConfigurationAnnotationProcessor`:对应 `ConfigurationClassPostProcessor`
- `org.springframework.context.annotation.internalAutowiredAnnotationProcessor` 对应 `AutowiredAnnotationBeanPostProcessor`
- `org.springframework.context.annotation.internalCommonAnnotationProcessor"` 对应 `CommonAnnotationBeanPostProcessor`
- `org.springframework.context.annotation.internalPersistenceAnnotationProcessor` 对应 `org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor`
- `org.springframework.context.event.internalEventListenerProcessor` 对应 `EventListenerMethodProcessor`
- `org.springframework.context.event.internalEventListenerFactory` 对应 `DefaultEventListenerFactory`
CommonAnnotationBeanPostProcessor
则在此时被注入容器中。
CommonAnnotationBeanPostProcessor
先看看 CommonAnnotationBeanPostProcessor
类结构:
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
...
}
它继承自 InitDestroyAnnotationBeanPostProcessor
:
public class InitDestroyAnnotationBeanPostProcessor
implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
它实现了 DestructionAwareBeanPostProcessor
和 MergedBeanDefinitionPostProcessor
。
而 DestructionAwareBeanPostProcessor
则主要为实例销毁之前执行的操作:
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
/**
* 销毁前执行
*/
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
/**
* 判断是否要执行
*/
default boolean requiresDestruction(Object bean) {
return true;
}
}
对于 DestructionAwareBeanPostProcessor
,它主要用于 DisposableBeanAdapter
,而DisposableBeanAdapter
则实现了 DisposableBean
。前面文章分析可知, DisposableBean
被注入到 容器中哦你缓存起来,而 一旦 容器关闭:
ConfigurableBeanFactory
的destroySingletons
ConfigurableApplicationContext
的close
则会执行destory
方法。
而对于 MergedBeanDefinitionPostProcessor
,前面分析 AutowiredAnnotationBeanPostProcessor
时候知道,会在 doCreateBean
时候,将 所有MergedBeanDefinitionPostProcessor
的 postProcessMergedBeanDefinition
调用。
而 AutowiredAnnotationBeanPostProcessor
中则主要为解析 @Autowired
和 @Value
注解会被调用。
注解解析
从 CommonAnnotationBeanPostProcessor
开始分析:
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
父类 InitDestroyAnnotationBeanPostProcessor
的 postProcessMergedBeanDefinition
方法:
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
metadata.checkConfigMembers(beanDefinition);
}
- 找到该类型的
LifecycleMetadata
数据,如果没有则会新增一份放到 类的lifecycleMetadataCache
。 - 从找到的
LifecycleMetadata
,执行其checkConfigMembers
进行类型检查,将上一步找到的符合条件的 方法,冗余一份到BeanDefinition
中。
下面看构建LifecycleMetadata
过程:
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
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, method -> {
// 如果有 @PostConstruct注解,则加入 currInitMethods 中
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
// 如果有 @PreDestory注解,则加入 currDestroyMethods
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 new LifecycleMetadata(clazz, initMethods, destroyMethods);
}
该方法有以下几个逻辑:
- 遍历该bean的所有方法
- 找到所有本类及父类的
@PostConstruct
注解 和PreDestroy
,并用他们构造LifecycleMetadata
并返回。
下面看子类的逻辑:
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
子类方法则主要是对java
自带的注解@WebServiceRef
、@EJB
、@Resource
进行分析。
与上面对方法分析类似,如果在CommonAnnotationBeanPostProcessor
的injectionMetadataCache
中没有找到相关记录,则会调用buildResourceMetadata
构建一份数据。
而buildResourceMetadata
原理有以下三个:
- 找到所有
@WebServiceRef
、@EJB
、@Resource
的字段 - 找到所有 方法中有
@WebServiceRef
、@EJB
、@Resource
注解的 - 将上面两步找到的metadata数据,构造一个
InjectionMetadata
返回并最终存到injectionMetadataCache
中。
checkConfigMembers
在checkConfigMembers
中,则类似于其父类行为的检查,将其放入 自生的(InjectMetadata
) 的checkedElements
,以及冗余一份到BeanDefinition
的externallyManagedConfigMembers
中。
@PostConstruct
开始在前面文章分析getBean
时候,有提到初始化一个bean的三个步骤:
- 实例化,构造初该bean
- 初始化,执行
populateBean
执行@Autowired
等操作 - 执行init等方法,即执行
initializeBean
方法。
而 第三步周的 initializeBean
方法则有分为几步:
- 对内部有实现 Aware 相关类进行字段设值。
- 执行所有
BeanPostProcessor
的postProcessBeforeInitialization
方法 - 执行
InitializingBean
类逻辑 和init-method
方法
@PostConstruct
注解的方法则会在 上面第二步中执行:
最终调用了 InitDestroyAnnotationBeanPostProcessor
的 postProcessBeforeInitialization
方法:
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 获取当前bean的 LifecycleMetadata
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
// 反射依次调用 @PostConstruct 注解方法
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;
}
invokeInitMethods:
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) {
// 依次调用所有 @PostConstruct 方法
if (logger.isTraceEnabled()) {
logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
}
element.invoke(target);
}
}
}
具体invoke方法
public void invoke(Object target) throws Throwable {
ReflectionUtils.makeAccessible(this.method);
this.method.invoke(target, (Object[]) null);
}
- 获取
LifecycleMetadata
数据 - 调用反射,依次先将其设为可见,而后执行 所有
@PostConstruct
方法
@PreDestroy
从本文开篇 了解到 DestructionAwareBeanPostProcessor
调用时间点,所以这里就直接分析父类 InitDestroyAnnotationBeanProcessor
的 postProcessBeforeDestruction
方法:
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
// 获取 metadata
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
// 执行destoryMethod方法
metadata.invokeDestroyMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
String msg = "Destroy method on bean with name '" + beanName + "' threw an exception";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex.getTargetException());
}
else {
logger.warn(msg + ": " + ex.getTargetException());
}
}
catch (Throwable ex) {
logger.warn("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);
}
}
上面则为获取 LifecycleMetadata
方法,而后执行对应的 destroy
方法,具体原理和 @PostConstruct
一致,这里不细分析。
@Resource
同@AutowiredAnnotationBeanPostProcessor
类似,也是在构造后,调用init-method
方法前调用,即在 populateBean
总,对搜有的 InstantiationAwareBeanPostProcessor
进行注入:
看 CommonAnnotationBeanBeanPostProcessor
的 postProcessProperties
方法:
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 获取 InjectionMetadata
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;
}
具体 inject
方法:
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
// 执行 element的inject 方法
element.inject(target, beanName, pvs);
}
}
}
看具体的inject
方法
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) {
// 字段
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
// 方法
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();
}
}
}
上面inject 方法,主要区分了是字段还是方法,最终都是执行字段的 set
或者method.invoke
方法进行注入,而具体的值则是调用 getResourceToInject
方法进行调用:
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
- 如果是
Lazy
注解类型的,则是通过构造一个动态代理对象进行返回,否则是直接调用getResource
方法:
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
if (StringUtils.hasLength(element.mappedName)) {
return this.jndiFactory.getBean(element.mappedName, element.lookupType);
}
// 如果是JNDI类型
if (this.alwaysUseJndiLookup) {
return this.jndiFactory.getBean(element.name, element.lookupType);
}
if (this.resourceFactory == null) {
throw new NoSuchBeanDefinitionException(element.lookupType,
"No resource factory configured - specify the 'resourceFactory' property");
}
return autowireResource(this.resourceFactory, element, requestingBeanName);
}
autowireResource(this.resourceFactory, element, requestingBeanName)
整个过程为获取相应bean的过程,this.resourceFactory
则为当前容器的BeanFactory
。即是从 BeanFactory
中获取。这里和 前面 的 AutowiredAnnotationBeanPostProcessor
类似,就不继续往下贴代码分析。
@Resource 和 @Autowired
@Resource
和 @Autowired
区别如下:
@Resource
是Java 注解诶,@Autowired
是Spring 的注解,通过AutowiredAnnotationBeanPostProcessor
驱动。@Autowired
与@Resource
都可以用来装配bean. 都可以写在字段上,或写在setter方法上。@Resource
默认是按照名称来装配注入的,所用的名字默认为字段名字,只有当找不到与名称匹配的bean才会按照类型来装配注入;@Autowired
默认是按照类型装配注入的,如果想按照名称来转配注入,则需要结合@Qualifier
一起使用;
觉得博主写的有用,不妨关注博主公众号: 六点A君。
哈哈哈,一起研究Spring: