Spring IOC(八)CommonAnnotationBeanPostProcessor 原理分析

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 {

它实现了 DestructionAwareBeanPostProcessorMergedBeanDefinitionPostProcessor
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 被注入到 容器中哦你缓存起来,而 一旦 容器关闭:

  1. ConfigurableBeanFactorydestroySingletons
  2. ConfigurableApplicationContextclose
    则会执行 destory 方法。

而对于 MergedBeanDefinitionPostProcessor,前面分析 AutowiredAnnotationBeanPostProcessor 时候知道,会在 doCreateBean 时候,将 所有MergedBeanDefinitionPostProcessorpostProcessMergedBeanDefinition 调用。
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);
	}

父类 InitDestroyAnnotationBeanPostProcessorpostProcessMergedBeanDefinition 方法:

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		LifecycleMetadata metadata = findLifecycleMetadata(beanType);
		metadata.checkConfigMembers(beanDefinition);
	}
  1. 找到该类型的 LifecycleMetadata 数据,如果没有则会新增一份放到 类的 lifecycleMetadataCache
  2. 从找到的 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);
	}

该方法有以下几个逻辑:

  1. 遍历该bean的所有方法
  2. 找到所有本类及父类的 @PostConstruct注解 和 PreDestroy ,并用他们构造 LifecycleMetadata 并返回。

下面看子类的逻辑:

  1. InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
    子类方法则主要是对 java 自带的注解 @WebServiceRef@EJB@Resource 进行分析。
    与上面对方法分析类似,如果在CommonAnnotationBeanPostProcessorinjectionMetadataCache 中没有找到相关记录,则会调用 buildResourceMetadata 构建一份数据。
    buildResourceMetadata 原理有以下三个:
  • 找到所有 @WebServiceRef@EJB@Resource 的字段
  • 找到所有 方法中有 @WebServiceRef@EJB@Resource 注解的
  • 将上面两步找到的metadata数据,构造一个InjectionMetadata 返回并最终存到 injectionMetadataCache 中。
  1. checkConfigMembers
    checkConfigMembers 中,则类似于其父类行为的检查,将其放入 自生的(InjectMetadata) 的checkedElements,以及冗余一份到 BeanDefinitionexternallyManagedConfigMembers 中。

@PostConstruct

开始在前面文章分析getBean时候,有提到初始化一个bean的三个步骤:

  1. 实例化,构造初该bean
  2. 初始化,执行 populateBean执行 @Autowired等操作
  3. 执行init等方法,即执行initializeBean 方法。

而 第三步周的 initializeBean 方法则有分为几步:

  1. 对内部有实现 Aware 相关类进行字段设值。
  2. 执行所有BeanPostProcessorpostProcessBeforeInitialization 方法
  3. 执行InitializingBean 类逻辑 和 init-method方法

@PostConstruct 注解的方法则会在 上面第二步中执行:
最终调用了 InitDestroyAnnotationBeanPostProcessorpostProcessBeforeInitialization方法:

	@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);
		}
  1. 获取 LifecycleMetadata 数据
  2. 调用反射,依次先将其设为可见,而后执行 所有 @PostConstruct 方法

@PreDestroy

从本文开篇 了解到 DestructionAwareBeanPostProcessor 调用时间点,所以这里就直接分析父类 InitDestroyAnnotationBeanProcessorpostProcessBeforeDestruction 方法:

	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 进行注入:
CommonAnnotationBeanBeanPostProcessorpostProcessProperties 方法:

	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));
		}
  1. 如果是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 区别如下:

  1. @Resource 是Java 注解诶,@Autowired 是Spring 的注解,通过 AutowiredAnnotationBeanPostProcessor 驱动。
  2. @Autowired@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
  3. @Resource默认是按照名称来装配注入的,所用的名字默认为字段名字,只有当找不到与名称匹配的bean才会按照类型来装配注入;
  4. @Autowired默认是按照类型装配注入的,如果想按照名称来转配注入,则需要结合@Qualifier一起使用;

觉得博主写的有用,不妨关注博主公众号: 六点A君。
哈哈哈,一起研究Spring:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值