spring擴展接口解析2--生命周期LifeCycle接口


前言

Spring容器本身是有生命周期的,比如容器啟動則開始生命和容器關閉則結束生命,如果想讓Spring容器管理的bean也同樣有生命周期的話,比如數據庫連接對象,當容器啟動時,連接bean生命周期開啟,當容器關閉時,連接bean生命周期結束。

此時就可以用到Spring提供的一個擴展接口--Lifecycle接口

一、Lifecycle接口定義

Lifecycle接口一共定義了三個方法,分別如下:

 1 public interface Lifecycle {
 2 
 3         /**
 4          * 生命周期開始
 5          */
 6         void start();
 7 
 8         /**
 9          * 生命周期結束
10          */
11         void stop();
12 
13         /**
14          * 判斷當前bean是否是開始狀態
15          */
16         boolean isRunning();
17 
18     }

 

start():表示開啟該對象的生命周期

stop():表示結束該對象的生命周期

isRunning():判斷當前對象的生命周期是否時開始狀態

從接口的方法上很好理解,主要是開始和結束當前對象的生命周期,以及判斷當前對象生命周期的狀態。

 

二、Lifecycle接口的擴展LifecycleProcessor接口

Spring中提供了Lifecycle接口的子接口 LifecycleProcessor,從字面意思上看是Lifecycle接口的處理器,LifecycleProcessor接口定義如下:

 1 public interface LifecycleProcessor extends Lifecycle {
 2 
 3     /**
 4      * 刷新容器,自動開始生命周期
 5      */
 6     void onRefresh();
 7 
 8     /**
 9      * 關閉容器,自動結束生命周期
10      */
11     void onClose();
12 
13 }

 

三、Spring容器的生命周期

Spring容器是有生命周期的,因為Spring容器抽象類AbstractApplicationContext實現了Lifecycle接口,實現代碼如下:

1 LifecycleProcessor getLifecycleProcessor() throws IllegalStateException {
2         if (this.lifecycleProcessor == null) {
3             throw new IllegalStateException("LifecycleProcessor not initialized - " +
4                     "call 'refresh' before invoking lifecycle methods via the context: " + this);
5         }
6         return this.lifecycleProcessor;
7     }

 

 1 @Override
 2     public void start() {
 3         getLifecycleProcessor().start();
 4         publishEvent(new ContextStartedEvent(this));
 5     }
 6 
 7     @Override
 8     public void stop() {
 9         getLifecycleProcessor().stop();
10         publishEvent(new ContextStoppedEvent(this));
11     }
12 
13     @Override
14     public boolean isRunning() {
15         return (this.lifecycleProcessor != null && this.lifecycleProcessor.isRunning());
16     }

 

從源碼看出,AbstractApplicationContext的start和stop方法完全委托給了內部的LifecycleProcessor來執行的。而LifecycleProcessor的初始化是在AbstractactApplicationContext初始化時進行的

AbstractApplicationContext初始化時,當容器全部初始化完畢之后會執行finishRefresh方法表示整個容器刷新完成了,執行邏輯如下:

 1 protected void finishRefresh() {
 2         // Clear context-level resource caches (such as ASM metadata from scanning).
 3         clearResourceCaches();
 4 
 5         //初始化LifecycleProcessor對象
 6         initLifecycleProcessor();
 7 
 8         //調用LifecycleProcessor對象的onRefresh()方法
 9         getLifecycleProcessor().onRefresh();
10 
11         // Publish the final event.
12         publishEvent(new ContextRefreshedEvent(this));
13 
14         // Participate in LiveBeansView MBean, if active.
15         LiveBeansView.registerApplicationContext(this);
16     }

 

在finishRefresh方法中首先是初始化了內部的LifecycleProcessor對象,然后調用了該對象的onRefresh()方法,而初始化LifecycleProcessor方法的邏輯也不復雜,首先是從BeanFactory中找到自定義的LifecycleProcessor,如果沒有用戶自定義的,則創建一個默認的LifecycleProcessor實現類DefaultLifecycleProcessor對象,源碼如下:

 1 protected void initLifecycleProcessor() {
 2         ConfigurableListableBeanFactory beanFactory = getBeanFactory();
 3 /** 如果BeanFactory中有自定義的LifecycleProcessor的bean,則直接用自定義的*/
 4         if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
 5             this.lifecycleProcessor = beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
 7             if (logger.isTraceEnabled()) {
 8                 logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
 9             }
10         }
11         else {
12 /** 如果沒有自定義,則創建默認的實現類DefaultLifecycleProcesor*/
13             DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
14             defaultProcessor.setBeanFactory(beanFactory);
15             this.lifecycleProcessor = defaultProcessor;
16             beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
17             if (logger.isTraceEnabled()) {
18                 logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
19                         "[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
20             }
21         }
22     }

 

接下來在分析下默認的LifecycleProcessor的處理邏輯,實現了LifecycleProcessor接口的實現源碼如下:

 1        /**
 2     * 執行startBeans(false)方法開啟所有實現了Lifecycle接口的bean的生命周期
 3      */
 4     @Override
 5     public void start() {
 6         startBeans(false);
 7         this.running = true;
 8     }
 9 
10     /**
11      * 執行stopBeans()方法關閉所有實現了Lifecycle接口的bean的生命周期
12      */
13     @Override
14     public void stop() {
15  stopBeans();
16         this.running = false;
17     }
18 
19     @Override
20     public void onRefresh() {
21         startBeans(true);
22         this.running = true;
23     }
24 
25     @Override
26     public void onClose() {
27         stopBeans();
28         this.running = false;
29     }
30 
31     @Override
32     public boolean isRunning() {
33         return this.running;
34     }

 

可以看出實現邏輯也不復雜,start()方法和onRefresh()方法分別都是執行了startBeans方法;stop方法和onClose方法都是執行了stopBeans方法,並且內部有一個running屬性用於表示當前的生命周期狀態。

所以核心邏輯都是在startBeans和stopBeans兩個方法中。

startBeans源碼解析:

 1 /** 開始bean的生命周期
 2      * @param autoStartupOnly:自動開啟還是手動開啟
 3      * */
 4     private void startBeans(boolean autoStartupOnly) {
 5         /**
 6          * 1.調用getLifecycleBeans方法獲取所有實現了Lifecycle接口的bean
 7          *  實現邏輯就是調用BeanFactory的getBeanNamesForType(LifeCycle.class)方法來獲取所有bean
 8          * */
 9         Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
10         Map<Integer, LifecycleGroup> phases = new HashMap<>();
11         /**
12          * 2.遍歷所有Lifecycle的bean,按不同階段進行分組,同組的封裝為LifecycleGroup對象
13          * */
14         lifecycleBeans.forEach((beanName, bean) -> {
15             if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
16                 int phase = getPhase(bean);
17                 LifecycleGroup group = phases.get(phase);
18                 if (group == null) {
19                     group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
20                     phases.put(phase, group);
21                 }
22                 group.add(beanName, bean);
23             }
24         });
25         /**
26          * 3.遍歷所有LifecycleGroup,調用LifecycleGroup的start方法
27          * */
28         if (!phases.isEmpty()) {
29             List<Integer> keys = new ArrayList<>(phases.keySet());
30             Collections.sort(keys);
31             for (Integer key : keys) {
32                 phases.get(key).start();
33             }
34         }
35     }

 

主要分成以下三步:

第一步:從BeanFactory中獲取所有實現了Lifecycle接口的bean

第二步:遍歷所有實現了Lifecycle接口的bean,按不同階段進行分組,同一組的bean封裝成LifecycleGroup對象

第三步:遍歷所有組,調用LifecycleGroup對象的start方法

LifecycleGroup對象的start方法源碼如下:

 1 public void start() {
 2             if (this.members.isEmpty()) {
 3                 return;
 4             }
 5             if (logger.isDebugEnabled()) {
 6                 logger.debug("Starting beans in phase " + this.phase);
 7             }
 8 /** 將Lifecycle對象進行排序*/
 9             Collections.sort(this.members);
10 /** 遍歷調用doStart方法開啟Lifecycle對象的生命周期*/
11             for (LifecycleGroupMember member : this.members) {
12                 doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
13             }
14         }

 

 1 private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
 2         /**
 3          * 1.根據beanName從集合中獲取Lifecycle對象並移除
 4          * */
 5         Lifecycle bean = lifecycleBeans.remove(beanName);
 6         if (bean != null && bean != this) {
 7             /**
 8              * 2.如果有依賴,則先開啟依賴bean的生命周期
 9              * */
10             String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
11             for (String dependency : dependenciesForBean) {
12                 doStart(lifecycleBeans, dependency, autoStartupOnly);
13             }
14             if (!bean.isRunning() &&
15                     (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {
16                 try {
17                     /**
18                      * 3.調用Lifecycle對象的start方法開啟生命周期
19                      * */
20                     bean.start();
21                 }
22                 catch (Throwable ex) {
23                     throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);
24                 }
25             }
26         }
27     }

 

總結:

startBeans整體邏輯如下:

1、從BeanFactory中獲取所有實現了Lifecycle接口的bean

2、將所有Lifecycle按階段進行分組

3、遍歷所有階段的組,遍歷每個組內的所有Lifecycle對象,如果Lifecycle對象有依賴bean就先開啟依賴bean的生命周期,然后直接執行Lifecycle對象的start方法

 

同理,stopBeans的整體邏輯和startBeans完全一樣,只不過一個是執行LifeCycle的start方法一個是執行LifeCycle的stop方法。

四、Lifecycle接口的擴展SmartLifecycle接口

SmartLifecycle接口繼承之Lifecycle接口和Phased接口,源碼如下:

 1 public interface SmartLifecycle extends Lifecycle, Phased {
 2 
 3     /**
 4      * 默認優先級,Integer的最大值
 5      */
 6     int DEFAULT_PHASE = Integer.MAX_VALUE;
 7 
 8 
 9     /**
10      * 是否自動啟動,默認為true
11      */
12     default boolean isAutoStartup() {
13         return true;
14     }
15 
16     /**
17      * 默認直接執行stop方法,並執行回調方法
18      */
19     default void stop(Runnable callback) {
20         stop();
21         callback.run();
22     }
23 
24     /**
25      * 獲取優先級,啟動時值越小越先啟動;停止時值越小越后停止
26      */
27     @Override
28     default int getPhase() {
29         return DEFAULT_PHASE;
30     }
31 
32 }

 

SmartLifecycle接口有一個優先級,如果沒有實現SmartLifecycle接口的其他的Lifecycle的優先級為0,啟動的時候按phase的值從小到大執行;關閉的時候按phase的值從大到小執行。

isAutoStartup()方法表示Spring容器刷新的時候自動執行start()方法,返回true表示會;返回false則不會,那么就需要手動調用start方法才可以執行。

Spring容器初始化完成之后,會調用LifecycleProcessor的onRefresh方法刷新整個上下文,但是此時的AbstractApplicationContext實際上還並沒有執行start方法,但是如果有bean需要在Spring容器刷新的時候就調用start方法,那么就可以使用SmartLifecycle,

當SmartLifecycle接口的isAutoStartup方法返回true時表示只要Spring容器刷新了就會調用該bean的start方法,否則必須要等到Spring容器執行了start方法之后才會執行SmartLifecycle對象的start方法。

測試案例如下:

定義兩個bean,一個設置isAutoStartup為true,一個為false

 1 public class AutoBean implements SmartLifecycle {
 2 
 3     boolean running;
 4 
 5     public boolean isAutoStartup() {
 6         return true;
 7     }
 8 
 9     @Override
10     public void start() {
11         System.out.println("AutoBean 執行start方法");
12         running = true;
13     }
14 
15     @Override
16     public void stop() {
17         System.out.println("AutoBean 執行stop方法");
18         running = false;
19     }
20 
21     @Override
22     public boolean isRunning() {
23         return running;
24     }
25 }
 1 public class NoAutoBean implements SmartLifecycle {
 2 
 3     boolean running;
 4 
 5     public boolean isAutoStartup() {
 6         return false;
 7     }
 8 
 9     @Override
10     public void start() {
11         System.out.println("NoAutoBean 執行start方法");
12         running = true;
13     }
14 
15     @Override
16     public void stop() {
17         System.out.println("NoAutoBean 執行stop方法");
18         running = false;
19     }
20 
21     @Override
22     public boolean isRunning() {
23         return running;
24     }
25 }

 

測試代碼如下:

1  public static void main(String[] args) throws Exception {
2         System.out.println("---->初始化Spring容器");
3         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
4         System.out.println("---->啟動Spring容器");
5         context.start();
6         System.out.println("---->關閉Spring容器");
7         context.stop();
8     }

 

測試代碼中,先初始化Spring容器,然后啟動Spring容器,最后在關閉Spring容器,測試結果如下:

---->初始化Spring容器
AutoBean 執行start方法
---->啟動Spring容器
NoAutoBean 執行start方法
---->關閉Spring容器
AutoBean 執行stop方法
NoAutoBean 執行stop方法

 從結果可以看出,當SmartLifecycle的isAutoStartup為true時,只要Spring容器刷新了就會自動執行start方法,而isAutoStartup為false時,只有當容器執行了start方法之后才會執行start方法

所以如果想要Lifecycle對象隨着Spring容器初始化之后就開啟,就可以采用實現SmartLifecycle接口的方式。

五、總結

1、Lifecycle接口用於實現bean的生命周期,執行start方法開啟生命周期;執行stop方法結束生命周期

2、ApplicationContext通過LifecycleProcessor來管理所有bean的生命周期,當Spring容器啟動或者刷新時,都會調用容器中所有實現了Lifecycle接口的bean的start方法,關閉時調用所有實現了Lifecycle接口的bean的stop方法

3、SmartLifecycle可以實現異步回調執行stop方法,用於結束生命周期之前的收尾業務邏輯處理;並且可以設置是否在容器刷新時自動開啟生命周期


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM