1. 程式人生 > >Spring中的初始化InitializingBean介面和DisposableBean介面

Spring中的初始化InitializingBean介面和DisposableBean介面

     最近在看關於redis整合的程式碼的時候,配置jedis的擴充套件操作RedisTemplate類,其中有屬性設定jedis連線,忍不住好奇,看了看RedisTemplate的實現。發現RedisTemplate類繼承了RedisAccessor,而RedisAccessor提供了redis庫的連線方法,還實現了InitializingBean。InitializingBean有什麼用?為什麼要實現這個介面?

  度娘了一下,原來InitializingBean提供了afterPropertiesSet方法,凡是繼承該介面的類,在初始化bean的時候會執行該方法。也就是說只有類繼承InitializingBean,我們就可以在afterPropertiesSet方法中新增一下自己的操作,一旦bean初始化,就會自動執行afterPropertiesSet方法。比如,判斷redis連線是不是能取到。

實現InitializingBean介面與在配置檔案中指定init-method有什麼不同?

     檢視spring的載入bean的原始碼類(AbstractAutowireCapableBeanFactory)可看出,AbstractAutowireCapableBeanFactory類中的invokeInitMethods實現

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
<span style="white-space:pre">	</span>//判斷該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的方式,實現InitializingBean介面中的afterPropertiesSet方法,或者在配置檔案中設定init-method。
2、實現InitializingBean介面是直接呼叫afterPropertiesSet方法,而init-method是通過反射來實現,效率較低,但是init-method方式消除了對spring的依賴。
3、InitializingBean介面實現先於init-method方法,如果呼叫afterPropertiesSet方法時出錯,則不呼叫init-method指定的方法。

同樣,對於DisposableBean介面,它也只提供一個方法destroy()。如果實現了DisposebleBean介面,那麼Spring將自動呼叫bean中的

Destory方法進行銷燬,與在配置檔案中配置destory-method的情況與上面相同。