第一種:通過注解@PostConstruct 和 @PreDestroy 方法 實現初始化和銷毀bean之前進行的操作
- import javax.annotation.PostConstruct;
- import javax.annotation.PreDestroy;
- public class DataInitializer{
- @PostConstruct
- public void initMethod() throws Exception {
- System.out.println("initMethod 被執行");
- }
- @PreDestroy
- public void destroyMethod() throws Exception {
- System.out.println("destroyMethod 被執行");
- }
- }
第二種是:通過 在xml中定義init-method 和 destory-method方法
- public class DataInitializer{
- public void initMethod() throws Exception {
- System.out.println("initMethod 被執行");
- }
- public void destroyMethod() throws Exception {
- System.out.println("destroyMethod 被執行");
- }
- }
- <bean id="dataInitializer" class="com.somnus.demo.DataInitializer" init-method="initMethod" destory-method="destroyMethod"/>
第三種是: 通過bean實現InitializingBean和 DisposableBean接口
- import org.springframework.beans.factory.DisposableBean;
- public class DataInitializer implements InitializingBean,DisposableBean{
- @Override
- public void afterPropertiesSet() throws Exception {
- System.out.println("afterPropertiesSet 被執行");
- }
- @Override
- public void destroy() throws Exception {
- System.out.println("destroy 被執行");
- }
- }
其中第一種和第二種是同一種形式,只不過一種xml配置,另外一種采用注解形式罷了,有很大區別的是第三種,
如果同一個bean同時采用兩種方式初始化的時候執行某個方法,首先在執行順序上就會體現出來。
先執行afterPropertiesSet(),
后執行initMethod()
這里我們看下源碼
這方式在spring中是怎么實現的?
通過查看spring的加載bean的源碼類(AbstractAutowireCapableBeanFactory)可看出其中奧妙
AbstractAutowireCapableBeanFactory類中的invokeInitMethods講解的非常清楚,源碼如下:
- protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
- throws Throwable {
- //判斷該bean是否實現了實現了InitializingBean接口,如果實現了InitializingBean接口,則只掉調用bean的afterPropertiesSet方法
- 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>() {
- public Object run() throws Exception {
- //直接調用afterPropertiesSet
- ((InitializingBean) bean).afterPropertiesSet();
- return null;
- }
- },getAccessControlContext());
- } catch (PrivilegedActionException pae) {
- throw pae.getException();
- }
- }
- else {
- //直接調用afterPropertiesSet
- ((InitializingBean) bean).afterPropertiesSet();
- }
- }
- if (mbd != null) {
- String initMethodName = mbd.getInitMethodName();
- //判斷是否指定了init-method方法,如果指定了init-method方法,則再調用制定的init-method
- if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
- !mbd.isExternallyManagedInitMethod(initMethodName)) {
- //進一步查看該方法的源碼,可以發現init-method方法中指定的方法是通過反射實現
- invokeCustomInitMethod(beanName, bean, mbd);
- }
- }
總結:
1:spring為bean提供了兩種初始化bean的方式,實現InitializingBean接口,實現afterPropertiesSet方法,或者在配置文件中同過
init-method指定,兩種方式可以同時使用
2:實現InitializingBean接口是直接調用afterPropertiesSet方法,比通過反射調用init-method指定的方法效率相對來說要高點。但是
init-method方式消除了對spring的依賴
3:如果調用afterPropertiesSet方法時出錯,則不調用init-method指定的方法。