Spring源码-解析@PostConstruct和@PreDestroy

一、例子
A.java

public class A {

@PostConstruct
public void init(){
	System.out.println("执行init");
}

@PreDestroy
public void destroy(){
	System.out.println("执行destroy");
}

public void print() {
	System.out.println("This is A");
}
}

init.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:mvc="http://www.springframework.org/schema/mvc"
	   xmlns:p="http://www.springframework.org/schema/p"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">


	<bean id="a" class="init.A"/>

	<context:component-scan base-package="init"/>
</beans>

Main.java

public class Main {
public static void main(String[] args) {
	ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("init.xml");
	A a = applicationContext.getBean(A.class);
	a.print();
	applicationContext.close();
}
}

必须调用applicationContext.close才能看到destroy方法的输出。

二、Spring源码解析@PostConstruct和@PreDestroy
在构造CommonAnnotationBeanPostProcessor时:

public CommonAnnotationBeanPostProcessor() {
	setOrder(Ordered.LOWEST_PRECEDENCE - 3);
	setInitAnnotationType(PostConstruct.class);
	setDestroyAnnotationType(PreDestroy.class);
	ignoreResourceType("javax.xml.ws.WebServiceContext");
}

调用了setInitAnnotationType设置了initAnnotationType类型为PostConstruct,调用了setDestroyAnnotationType设置destroyAnnotationType为PreDestroy。

CommonAnnotationBeanPostProcessor在调用postProcessMergedBeanDefinition时调用了父类的postProcessMergedBeanDefinition,即InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition:

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
	LifecycleMetadata metadata = findLifecycleMetadata(beanType);
	metadata.checkConfigMembers(beanDefinition);
}

	private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
	if (this.lifecycleMetadataCache == null) {
		// Happens after deserialization, during destruction...
		return buildLifecycleMetadata(clazz);
	}
	// Quick check on the concurrent map first, with minimal locking.
	LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
	if (metadata == null) {
		synchronized (this.lifecycleMetadataCache) {
			metadata = this.lifecycleMetadataCache.get(clazz);
			if (metadata == null) {
				metadata = buildLifecycleMetadata(clazz);
				this.lifecycleMetadataCache.put(clazz, metadata);
			}
			return metadata;
		}
	}
	return metadata;
}

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 -> {
			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);
				}
			}
			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 (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
			new LifecycleMetadata(clazz, initMethods, destroyMethods));
}

buildLifecycleMetadata解析Class对象的方法,选择出PostConstruct和PreDestroy注解标注的方法。并封装到LifecycleMetadata的initMethods和destroyMethods集合中。

InitDestroyAnnotationBeanPostProcessor间接实现了BeanPostProcessor接口,在调用init方法之前调用postProcessBeforeInitialization方法,InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization方法的实现是:

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
	try {
		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;
}

调用了PostConstruct注解标注的方法。

InitDestroyAnnotationBeanPostProcessor实现了DestructionAwareBeanPostProcessor接口,会在销毁bean之前调用DestructionAwareBeanPostProcessor的postProcessBeforeDestruction方法,InitDestroyAnnotationBeanPostProcessor的postProcessBeforeDestruction实现是:

@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
	LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
	try {
		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);
	}
}

调用了PreDestroy注解标注的方法。

posted @   shigp1  阅读(96)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示