spring容器:InitializingBean接口的使用

    首先咱們來看一下InitializingBean接口,發現它只有一個方法,因此實現該接口只需實現這個方法就能夠了。java

package org.springframework.beans.factory;

public interface InitializingBean {

	void afterPropertiesSet() throws Exception;

}

    咱們來定義一個service實現該接口,測試一下該接口提供的初始化功能,同時與init-method配置的初始化方法進行比較。web

public class PlatformxService implements InitializingBean{

	
	@Override
	public void afterPropertiesSet() throws Exception {	
		System.out.println("初始化執行:afterPropertiesSet");
	}
	
	public void initMethod(){
		System.out.println("初始化執行:initMethod");
	}
}

    在配置文件中進行該service配置spring

<bean id="platformxService" class="com.sfpay.platformx.service.PlatformxService" init-method="initMethod" />

    由於我搭建的是web工程,這裏啓動容器觀察初始化方法執行順序apache

初始化執行:afterPropertiesSet
初始化執行:initMethod

    這裏咱們能夠看到在spring初始化bean的時候,afterPropertiesSet方法執行再前,initMethod方法執行在後,爲何會出現這種狀況呢?咱們就進一步看一下spring加載bean時候的源碼。在AbstractAutowireCapableBeanFactory中咱們能夠找到spring調用bean初始化方法的代碼。框架

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
			throws Throwable {
        //判斷bean是否實現InitializingBean接口
		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 {
                            //直接經過bean調用afterPropertiesSet方法
							((InitializingBean) bean).afterPropertiesSet();
							return null;
						}
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
                 ////直接經過bean調用afterPropertiesSet方法
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		if (mbd != null) {
            //判斷是否有配置init-method方法
			String initMethodName = mbd.getInitMethodName();
			if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
                //在該方法中調用init-method配置方法
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

    咱們再進入到invokeCustomInitMethod方法中查看,init-method配置初始化方法調用過程ide

protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
		String initMethodName = mbd.getInitMethodName();
		final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
				BeanUtils.findMethod(bean.getClass(), initMethodName) :
				ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
		if (initMethod == null) {
			if (mbd.isEnforceInitMethod()) {
				throw new BeanDefinitionValidationException("Couldn't find an init method named '" +
						initMethodName + "' on bean with name '" + beanName + "'");
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("No default init method named '" + initMethodName +
							"' found on bean with name '" + beanName + "'");
				}
				// Ignore non-existent default lifecycle methods.
				return;
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Invoking init method  '" + initMethodName + "' on bean with name '" + beanName + "'");
		}

		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
				public Object run() throws Exception {
					ReflectionUtils.makeAccessible(initMethod);
					return null;
				}
			});
			try {
				AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
					public Object run() throws Exception {
                        //經過反射調用初始化方法
						initMethod.invoke(bean);
						return null;
					}
				}, getAccessControlContext());
			}
			catch (PrivilegedActionException pae) {
				InvocationTargetException ex = (InvocationTargetException) pae.getException();
				throw ex.getTargetException();
			}
		}
		else {
			try {
				ReflectionUtils.makeAccessible(initMethod);
                //經過反射調用初始化方法
				initMethod.invoke(bean);
			}
			catch (InvocationTargetException ex) {
				throw ex.getTargetException();
			}
		}
	}

    由上代碼咱們知道爲何會出現上面執行順序的結果了吧!同時咱們還發現afterPropertiesSet方法不只先執行,也是直接調用bean的afterPropertiesSet方法進行調用,而init-method初始方法是經過反射方式調用的。測試

    經過上面實現及代碼咱們能夠得出結果:1.spring爲咱們提供兩種初始化bean方法,實現InitializingBean接口和配置init-method。2.實現InitializingBean接口的方式由於是直接對bean調用afterPropertiesSet方法因此比init-method配置反射方式調用效率上面會高一點,可是也增長了跟spring框架的耦合度。debug

相關文章
相關標籤/搜索