深入理解spring生命週期與BeanPostProcessor的實現原理

上面兩篇文章分別介紹了spring生命週期中初始化和銷燬的幾種方式以及統一後置BeanPostProcessor接口的使用,可以點擊以下鏈接查看:


  1. 三分鐘瞭解spring-bean生命週期之初始化和銷燬的三種方式

  2. 一分鐘學會spring-bean的統一前後置處理器BeanPostProcessor


今天我們就來一起看看spring底層是如何實現這些的,在看它的實現原理之前,我們再來把之前幾種方式結合放一個例子中演示下


新建一個User1對象如下:


/**
* 定義一個實現InitializingBean DisposableBean的bean
*
* @author zhangqh
* @date 2018年5月4日
*/

public class User1 implements InitializingBean,DisposableBean{
   public User1(){
       System.out.println("實例化User1的構造方法......");
   }
   public void destroy() throws Exception {
       System.out.println("調用實現DisposableBean的destroy方法....");
   }
   public void afterPropertiesSet() throws Exception {
       System.out.println("調用實現InitializingBean的afterPropertiesSet方法......");
   }
   public void initUser(){
       System.out.println("執行initMethod方法.....");
   }
   public void destroyUser(){
       System.out.println("執行destroyMethod方法......");
   }
}


新建一個MyBeanPostProcessor實現BeanPostProcessor如下:


/**
* 定義一個前置後置處理器
*
* @author zhangqh
* @date 2018年5月6日
*/

public class MyBeanPostProcessor implements BeanPostProcessor {
   public Object postProcessBeforeInitialization(Object bean, String beanName)
           throws BeansException
{
       // 這邊只做簡單打印   原樣返回bean
       System.out.println("postProcessBeforeInitialization===="+beanName);
       return bean;
   }
   public Object postProcessAfterInitialization(Object bean, String beanName)
           throws BeansException
{
       // 這邊只做簡單打印   原樣返回bean
       System.out.println("postProcessAfterInitialization===="+beanName);
       return bean;
   }
}


主配置文件如下:


/**
* 定義一個註解配置文件 必須要加上@Configuration註解
*
* @author zhangqh
* @date 2018年4月30日
*/

@Configuration
public class MainConfig {
   @Bean(initMethod="initUser",destroyMethod="destroyUser")
   public User1 getUser1(){
       return new User1();
   }
   @Bean
   public MyBeanPostProcessor getMyBeanPostProcessor(){
       return new MyBeanPostProcessor();
   }
}


測試代碼如下:


public static void main(String[] args) {
       // 使用AnnotationConfigApplicationContext獲取spring容器ApplicationContext2
       AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainConfig.class);
       applicationContext2.close();
}


運行結果如下:


實例化User1的構造方法......
postProcessBeforeInitialization====getUser1
調用實現InitializingBean的afterPropertiesSet方法......
執行initMethod方法.....
postProcessAfterInitialization====getUser1
調用實現DisposableBean的destroy方法....
執行destroyMethod方法......


從結果中可以看出他們之前執行的順序如下:注意其中的位置序號下邊文章會用到

1,首先執行bean的構造方法,
2,BeanPostProcessor的postProcessBeforeInitialization方法
3,InitializingBean的afterPropertiesSet方法
4,@Bean註解的initMethod方法
5,BeanPostProcessor的postProcessAfterInitialization方法
6,DisposableBean的destroy方法
7,@Bean註解的destroyMethod方法

接下來我們再來看看spring底層的實現,首先進入程序的啓動類AnnotationConfigApplicationContext方法如下:


public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
       this();
       register(annotatedClasses);
       refresh();
}


裏邊有兩個方法一個是register註冊對應的java配置類和另一個是refresh方法,我們重點來看這個refresh方法如下:


public void refresh() throws BeansException, IllegalStateException {
       synchronized (this.startupShutdownMonitor) {
           // Prepare this context for refreshing.
           prepareRefresh();
           // Tell the subclass to refresh the internal bean factory.
           ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
           // Prepare the bean factory for use in this context.
           prepareBeanFactory(beanFactory);
           try {
               // 省略大部分代碼
               // 實例化所有的不是延遲加載(延遲加載的只有在使用的時候纔會實例化)的bean實例
               finishBeanFactoryInitialization(beanFactory);
               // Last step: publish corresponding event.
               finishRefresh();
           }catch (BeansException ex) {
               // 省略部分代碼
           }finally {
               resetCommonCaches();
           }
       }
}


接下來我們重點來看下finishBeanFactoryInitialization實例化bean的方法,進去之後我們發現最後有一個preInstantiateSingletons方法如下:


protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
       // 省略大部分代碼
       // Instantiate all remaining (non-lazy-init) singletons.
       beanFactory.preInstantiateSingletons();
}


繼續查看preInstantiateSingletons對應實現如下:


@Override
   public void preInstantiateSingletons() throws BeansException {
       // Iterate over a copy to allow for init methods which in turn register new bean definitions.
       // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
       List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
       // 循環所有的bean實例化
       for (String beanName : beanNames) {
           RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
           if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
               if (isFactoryBean(beanName)) {
                   final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                   boolean isEagerInit;
                   if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                       isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                           @Override
                           public Boolean run() {
                               return ((SmartFactoryBean<?>) factory).isEagerInit();
                           }
                       }, getAccessControlContext());
                   }
                   else {
                       isEagerInit = (factory instanceof SmartFactoryBean &&
                               ((SmartFactoryBean<?>) factory).isEagerInit());
                   }
                   if (isEagerInit) {
                       // 獲取bean方法
                       getBean(beanName);
                   }
               }
               else {
                   getBean(beanName);
               }
           }
       }
       // 省略部分代碼
}


我們發現裏邊的關鍵方法getBean如下:


@Override
public Object getBean(String name) throws BeansException {
       return doGetBean(name, null, null, false);
}


繼續跟進去如下:


protected <T> T doGetBean(
           final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)

           throws BeansException
{
       final String beanName = transformedBeanName(name);
       Object bean;
       // 檢查緩存中是否已經存在了bean實例.
       Object sharedInstance = getSingleton(beanName);
       if (sharedInstance != null && args == null) {
           if (logger.isDebugEnabled()) {
               if (isSingletonCurrentlyInCreation(beanName)) {
                   logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                           "' that is not fully initialized yet - a consequence of a circular reference");
               }
               else {
                   logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
               }
           }
           bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
       }else {
           // 省略部分代碼。。。。。
           try {
               // 省略部分代碼。。。。。
               // 判斷bean是否配置的是單實例
               if (mbd.isSingleton()) {
                   sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                       @Override
                       public Object getObject() throws BeansException {
                           try {
                               return createBean(beanName, mbd, args);
                           }
                           catch (BeansException ex) {
                               destroySingleton(beanName);
                               throw ex;
                           }
                       }
                   });
                   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
               }// bean配置的是多實例
               else if (mbd.isPrototype()) {
                   // It's a prototype -> create a new instance.
                   Object prototypeInstance = null;
                   try {
                       beforePrototypeCreation(beanName);
                       prototypeInstance = createBean(beanName, mbd, args);
                   }
                   finally {
                       afterPrototypeCreation(beanName);
                   }
                   bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
               }
               else {// 既不是單實例也不是多實例的邏輯
                   // 省略部分代碼。。。。。
               }
           }
           catch (BeansException ex) {
               cleanupAfterBeanCreationFailure(beanName);
               throw ex;
           }
       }
       // 省略部分代碼。。。。。
       return (T) bean;
   }


接下來重點看一下其中創建bean的方法createBean如下:


protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
       RootBeanDefinition mbdToUse = mbd;
       // 省略部分代碼
       // 重點注意doCreateBean方法
       Object beanInstance = doCreateBean(beanName, mbdToUse, args);
       if (logger.isDebugEnabled()) {
           logger.debug("Finished creating instance of bean '" + beanName + "'");
       }
       return beanInstance;
}


繼續跟進可以看到doCreateBean方法如下:


protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
           throws BeanCreationException
{
       // 省略部分代碼
       // Initialize the bean instance.
       Object exposedObject = bean;
       try {
           populateBean(beanName, mbd, instanceWrapper);
           if (exposedObject != null) {
               exposedObject = initializeBean(beanName, exposedObject, mbd);
           }
       }
       catch (Throwable ex) {
           if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
               throw (BeanCreationException) ex;
           }
           else {
               throw new BeanCreationException(
                       mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
           }
       }
       // 省略部分代碼......
       // Register bean as disposable.
       // 注意這個地方  下面講銷燬的時候說講到
       try {
           registerDisposableBeanIfNecessary(beanName, bean, mbd);
       }
       catch (BeanDefinitionValidationException ex) {
           throw new BeanCreationException(
                   mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
       }
       return exposedObject;
}


可以發現其中有一個initializeBean方法如下:


protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
       // 省略部分代碼。。。。
       Object wrappedBean = bean;
       if (mbd == null || !mbd.isSynthetic()) {
           // 重點來了BeanPostProcessor的postProcessBeforeInitialization方法執行的地方
           // 這也是爲什麼他執行所有的初始化之前的原因了
           wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
       }
       try {
           // 初始化bean
           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()) {
           // BeanPostProcessor的PostProcessorsAfterInitialization方法執行的地方
           // 初始化完成之後執行BeanPostProcessor的postProcessorsAfterInitialization
           wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
       }
       return wrappedBean;
}


到這BeanPostProcessor的實現已經很清晰了吧BeanPostProcessorpostProcessBeforeInitialization方法位置2)BeanPostProcessorpostProcessAfterInitialization方法位置5)的執行位置我們搞清楚了,那上面的位置3位置4又是怎麼執行的呢,讓我們繼續到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 {
               // 位置3的 InitializingBean的afterPropertiesSet方法
               ((InitializingBean) bean).afterPropertiesSet();
           }
       }
       if (mbd != null) {
           // 位置4的 @Bean註解的initMethod方法
           String initMethodName = mbd.getInitMethodName();
           if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                   !mbd.isExternallyManagedInitMethod(initMethodName)) {
               invokeCustomInitMethod(beanName, bean, mbd);
           }
       }
}


聰明的你應該一眼就能看到位置3,以及位置4的執行順序了吧


好了初始化的邏輯部分搞清楚了,接下來我們一起來看看銷燬的流程,銷燬開始於applicationContext.close();方法,點進去看如下:


@Override
public void close() {
       synchronized (this.startupShutdownMonitor) {
           doClose();
           // If we registered a JVM shutdown hook, we don't need it anymore now:
           // We've already explicitly closed the context.
           if (this.shutdownHook != null) {
               try {
                   Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
               }
               catch (IllegalStateException ex) {
                   // ignore - VM is already shutting down
               }
           }
       }
}


看到其中有一個doClose繼續跟進去看會發現有一個destroyBeans方法,再進去直到找到destroySingletons方法如下:


public void destroySingletons() {
       // 省略部分代碼
       // 循環所有的disposableBean執行對應的destroy方法
       for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
           destroySingleton(disposableBeanNames[i]);
       }
       // 省略部分代碼
}


在繼續從destroySingleton方法進去可以找到destroyBean方法如下:


protected void destroyBean(String beanName, DisposableBean bean) {
       // 省略部分代碼
       // 重點的地方到了  執行DisposableBean 中的destroy 也就是位置6 中對應的打印
       if (bean != null) {
           try {
               bean.destroy();
           }
           catch (Throwable ex) {
               logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);
           }
       }
       // 省略部分代碼
}


到這裏我們已經完成了90%的原理分析了,這個時候細心的你一定會發現那位置7中的@Bean註解中配置的destroyMethod是在什麼時候調用的呢,好像上面都沒有講到,要想知道destroyMethod的調用讓我們回到上面講bean初始化中的doCreateBean方法中其中有一個registerDisposableBeanIfNecessary方法進去看如下:



protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
       AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
       if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
           if (mbd.isSingleton()) {
               // Register a DisposableBean implementation that performs all destruction
               // work for the given bean: DestructionAwareBeanPostProcessors,
               // DisposableBean interface, custom destroy method.
               registerDisposableBean(beanName,
                       new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
           }
           else {
               // A bean with a custom scope...
               Scope scope = this.scopes.get(mbd.getScope());
               if (scope == null) {
                   throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
               }
               // 關鍵代碼
               scope.registerDestructionCallback(beanName,
                       new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
           }
       }
}


繼續進去到DisposableBeanAdapter類如下:


public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
           List<BeanPostProcessor> postProcessors, AccessControlContext acc) {
       Assert.notNull(bean, "Disposable bean must not be null");
       this.bean = bean;
       this.beanName = beanName;
       this.invokeDisposableBean =
               (this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
       this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
       this.acc = acc;
       String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
       if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
               !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
           this.destroyMethodName = destroyMethodName;
           this.destroyMethod = determineDestroyMethod();
           if (this.destroyMethod == null) {
               if (beanDefinition.isEnforceDestroyMethod()) {
                   throw new BeanDefinitionValidationException("Couldn't find a destroy method named '" +
                           destroyMethodName + "' on bean with name '" + beanName + "'");
               }
           }
           else {
               Class<?>[] paramTypes = this.destroyMethod.getParameterTypes();
               if (paramTypes.length > 1) {
                   throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
                           beanName + "' has more than one parameter - not supported as destroy method");
               }
               else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
                   throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
                           beanName + "' has a non-boolean parameter - not supported as destroy method");
               }
           }
       }
       this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
   }


怎麼樣,到現在是不是就很清晰了,位置7的打印其實也是DisposableBean方法中打印出來的,@bean註解的destroyMethod其實是在初始化的時候轉換成DisposableBean的實現放入到了disposableBeans中


到此今天所有內容就到此結束了,最後以一張流程圖總結下如下:


以上是今天文章的所有內容,歡迎大家吐槽


推薦閱讀


深入理解java註解的實現原理
深入理解java的反射機制

250G偷懶必看資料全集


更多優質文章請關注以下公衆號查閱:




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章