init-method,@postcontruct,afterPropertiesSet的先後順序

在牛客面經上遇到的一個面試題。突然想嘗試下
然後就開始做了

測試

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		TestDao testDao = applicationContext.getBean(TestDao.class);
		((ClassPathXmlApplicationContext) applicationContext).close();

測試的bean

@Component
public class TestDao  implements InitializingBean, DisposableBean {
	public TestDao() {
		System.out.println("constructor");
	}

	@Async
	public void query(){
		System.out.println("Hello Spring!");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("afterPropertiesSet");
	}
	@PostConstruct
	public void PostConstruct(){
		System.out.println("PostConstruct");
	}

	public void InitMethod(){
		System.out.println("InitMethod");
	}

	@Override
	public void destroy() throws Exception {
		System.out.println("destroy");
	}
	@PreDestroy
	public void PreDestroy(){
		System.out.println("PreDestroy");
	}
	public void destroyMethod(){
		System.out.println("destroyMethod");
	}
}

xml

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

        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<context:annotation-config/>
	<bean id="testDao" class="com.test.dao.TestDao" init-method="InitMethod" destroy-method="destroyMethod"></bean>

</beans>

執行之後打印的結果
file
總的來說就是打印的結果是構造方法->註解@PostConstruct方法->InitializingBean接口的afterPropertiesSet方法->xml中配置的init-method方法
同理銷燬也是一樣註解@PreDestroy方法->DisposableBean接口的destroy方法->xml中配置的destroy-method方法

源碼

通過斷點調試發現幾個初始化方法都定位到了AbstractAutowireCapableBeanFactory的initializeBean方法中

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
		//此處執行的是@PostConstruct註解的方法 InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
		//執行的是afterPropertiesSet和init-method方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

後面執行的兩個方法
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {

	boolean isInitializingBean = (bean instanceof InitializingBean);
	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
		if (logger.isTraceEnabled()) {
			logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
		}
		if (System.getSecurityManager() != null) {
			try {
				AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
					((InitializingBean) bean).afterPropertiesSet();
					return null;
				}, getAccessControlContext());
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
		//執行afterPropertiesSet方法
			((InitializingBean) bean).afterPropertiesSet();
		}
	}

	if (mbd != null && bean.getClass() != NullBean.class) {
		String initMethodName = mbd.getInitMethodName();
		if (StringUtils.hasLength(initMethodName) &&
				!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
				!mbd.isExternallyManagedInitMethod(initMethodName)) {
				//執行的是xml中自定義的init-method方法
			invokeCustomInitMethod(beanName, bean, mbd);
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章