在項目中經常會在容器啟動時,完成特定的初始化操作,如資源文件的加載等。
一 實現的方式有三種:
1.使用@PostConstruct注解,該注解作用於void方法上
2.在配置文件中配置init-method方法
<bean id="student" class="com.demo.spring.entity.Student" init-method="init2">
<property name="name" value="景甜"></property>
<property name="age" value="28"></property>
<property name="school" ref="school"></property>
</bean>
3.將類實現InitializingBean接口
package com.demo.spring.entity; import javax.annotation.PostConstruct; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; /** * @author chenyk * @date 2018年5月8日 */ @Component("student") public class Student implements InitializingBean{ private String name; private int age; private School school; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public School getSchool() { return school; } public void setSchool(School school) { this.school = school; } //1.使用postconstrtct注解 @PostConstruct public void init(){ System.out.println("執行 init方法"); } //2.在xml配置文件中配置init-method方法 public void init2(){ System.out.println("執行init2方法 "); } //3.實現InitializingBean接口 public void afterPropertiesSet() throws Exception { System.out.println("執行init3方法"); } }
執行結果:
執行 init方法
2018-06-11 10:09:16,195 DEBUG [AbstractAutowireCapableBeanFactory.java:1671] : Invoking afterPropertiesSet() on bean with name 'student'
執行init3方法
2018-06-11 10:09:36,459 DEBUG [AbstractAutowireCapableBeanFactory.java:1731] : Invoking init method 'init2' on bean with name 'student'
執行init2 方法
二 實現原理:
由以上執行結果可知:先執行@PostConstruct注解的方法,然后是實現了InitializingBean接口的afterPropertiesSet方法,最后執行在配置文件中配置的init-method方法。至於為什么是這個順序,可以看源碼:
在 AbstractAutowireCapableBeanFactory 類中
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try {
//調用初始化方法 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; }
然后進入到 invokeInitMethods 方法中
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else {
//直接調用 InitializingBean 接口中的 afterPropertiesSet 方法 ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null) { String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) {
//進入該方法可知通過反射的方式調用init-method方法 invokeCustomInitMethod(beanName, bean, mbd); } } }
所以,初始化方法的執行順序 afterPropertiesSet() > init-method()
博客園的第一篇文章。感覺博客園很干凈,文章排版特別是插入代碼格式看起來很舒服。就不吐槽csdn了。
