Spring注解源码解析六

上一篇中,我们了解了@Autowire注解的底层原理,Spring会通过Bean的后处理器AutowiredAnnotationBeanPostProcessor,解析bean实例中的字段和方法上的注解@Autowired,最后会将对应的注解信息注入到属性或者方法参数上。今天我们看下另外的两个注解@PostConstruct和@PreDestroy。

我们要分析注解@PostConstruct和注解@PreDestory的底层源码,我们得要先找到源码的入口在哪,那Spring到底是在什么时候解析这两个注解的呢?和之前一样,我们先到这两个注解类中先看下:
在这里插入图片描述
在这里插入图片描述
在这两个注解中,我们没有找到相关的信息。那会不会和解析注解@Autowired的方式类似,毕竟注解@PostConstruct和注解@PreDestory有一点是和注解@Autowired类似的,也就是注解是可以添加在方法上的,而前面我们分析注解@Autowired的底层源码时,发现最终是通过Bean的工厂后处理器来处理的。那在什么地方会用到这两个注解呢?就是在bean实例初始化的时候,我们可以来看下:
在这里插入图片描述
我们发现方法applyBeanPostProcessorsBeforeInitialization和方法applyBeanPostProcessorsAfterInitialization,通过前面的分析我们也知道,这两个方法分别是在执行BeanPostProcessor中的前置和后置处理方法。我们可以先到方法applyBeanPostProcessorsBeforeInitialization中看下:
在这里插入图片描述
可以看到,这里会执行Bean后处理器中的前置处理方法,我们可以看下这个里面有哪些Bean的后处理器:
在这里插入图片描述
可以看到这里的后处理器还是挺多的,不过从这个名称上来看,后处理器中InitDestroyAnnotationBeanPostProcessor应该和我们本次的两个注解有关,通过名称我们可以知道,这个Bean的后处理器,应该可以同时处理初始化方法和销毁方法相关的注解信息。我们可以到InitDestroyAnnotationBeanPostProcessor类中看下:
在这里插入图片描述
可以看到,InitDestroyAnnotationBeanPostProcessor类中的前置和后置处理方法中,只有前置处理方法postProcessBeforeInitialization是有具体的逻辑实现的。在方法postProcessBeforeInitialization中,我们可以看到通过metadata调用方法invokeInitMethods,很明显方法invokeInitMethods就是在执行初始化相关的方法,这也符合我们前面看到的先执行初始化方法的逻辑,初始化方法的确应也该在这里被执行。我们可以断定Bean后处理器InitDestroyAnnotationBeanPostProcessor,就是用来处理注解@PostConstruct和注解@PreDestory的。们回到方法postProcessBeforeInitialization中看下:
在这里插入图片描述
我们到方法findLifecycleMetadata中看下:
在这里插入图片描述
可以看到,方法findLifecycleMetadata的结构,首先是去缓存中获取注解的信息,如果没有的话就要重新去解析了。这里面最关键的方法还是buildLifecycleMetadata方法,我们跟进去看下:

private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
		// 看下当前类是否符合候选的类型
		if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
			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, method -> {
				// 方法method中是否存在注解this.initAnnotationType 类型,也就是 注解@PostConstruct
				if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
					// 将方法封装到 LifecycleElement 中,最后添加到集合 currInitMethods
					LifecycleElement element = new LifecycleElement(method);
					currInitMethods.add(element);
					if (logger.isTraceEnabled()) {
						logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
					}
				}
				// 方法method 中是否存在注解 this.destroyAnnotationType 也就是注解 @PreDestroy
				if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
					// 将方法封装到 lifecycleElement 中, 最后添加到集合 currDestroyMethods
					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的父类, 在下一轮 while 循环进行同样的解析处理
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		// 最后 ,如何初始化 或 销毁方法相应的注解存在, 最终会封装到组件 LifecycleMetadata 中
		return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
				new LifecycleMetadata(clazz, initMethods, destroyMethods));
	}

在这里插入图片描述
方法findLifecycleMetadata一开始先调用AnnotationUtils类中的方法isCandidateClass,判断下当前的类是否符合候选条件。就是有没有注解 @PostConstruct 和 注解 @PreDestroy。如果添加了这两个注解,就将方法method封装到LifecycleElement中,然后分别添加到集合currInitMethods和currDestroyMethods中。我们可以看下,在LifecycleElement的构造方法中会如何处理:
在这里插入图片描述
我们再看下剩下的一些逻辑:
在这里插入图片描述
可以看到,接下来会将targetClass的父类赋值给targetClass,也就是说接下来在下一轮while循环中,会解析当前类的父类中的注解,最后将解析到的所有信息封装到组件LifecycleMetadata中并返回。我们看下 LifecycleMetadata的构造方法中看一下:
在这里插入图片描述
将注解@PostConstruct对应的元数据信息,赋值给成员变量this.initMethods,而注解@PreDestory对应的元数据信息,则赋值给成员变量this.destroyMethods,我们再回到方法postProcessBeforeInitialization:
在这里插入图片描述
我们再到方法invokeInitMethods中看下:
在这里插入图片描述
在方法invokeInitMethods其实就是在遍历注解@PostConstruct相关的信息了,我们可以到element的invoke方法中看下:
在这里插入图片描述
底层其实就是在执行注解@PostConstruct对应的方法,而且是通过反射执行的。
而我们执行@PreDestroy对应的销毁方法在哪里呢?大家还记得bean在实例化最后面,还注册了一个实现了DisposableBean 接口的实现类DisposableBeanAdapter我们可以再到它的destroy方法中看下:
在这里插入图片描述
我们通过在这个Destroy 方法中,执行了Bean的后处理器。Bean后处理器InitDestroyAnnotationBeanPostProcessor,它同样也是接口DestructionAwareBeanPostProcessor的实现类。我们可以到InitDestroyAnnotationBeanPostProcessor中的方法postProcessBeforeDestruction看下:
在这里插入图片描述
这里又重新调用方法findLifecycleMetadata,到bean的类中解析注解@PostConstruct和注解@PreDestory的元数据信息,然后再调用方法invokeDestroyMethods执行注解@PreDestory对应的销毁方法。总的来说从执行顺序上,注解指定的方法都是先执行的,接着执行如接口InitializingBean和接口DisposableBean中指定的方法,最后才执行属性init-method和属性destroy-method指定的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youngerone123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值