Spring官網閱讀(九)Spring中Bean的生命週期(上)

在之前的文章中,我們一起學習過了官網上容器擴展點相關的知識,包括FactoryBeanBeanFactroyPostProcessor,BeanPostProcessor,其中BeanPostProcessor還剩一個很重要的知識點沒有介紹,就是相關的BeanPostProcessor中的方法的執行時機。之所以在之前的文章中沒有介紹是因爲這塊內容涉及到Bean的生命週期。在這篇文章中我們開始學習Bean的生命週期相關的知識,整個Bean的生命週期可以分爲以下幾個階段:

  • 實例化(得到一個還沒有經過屬性注入跟初始化的對象)
  • 屬性注入(得到一個經過了屬性注入但還沒有初始化的對象)
  • 初始化(得到一個經過了初始化但還沒有經過AOP的對象,AOP會在後置處理器中執行)
  • 銷燬

在上面幾個階段中,BeanPostProcessor將會穿插執行。而在初始化跟銷燬階段又分爲兩部分:

  • 生命週期回調方法的執行
  • aware相關接口方法的執行

這篇文章中,我們先完成Bean生命週期中,整個初始化階段的學習,對於官網中的章節爲1.6小結

生命週期回調

1、Bean初始化回調

實現初始化回調方法,有以下三種形式

  • 實現InitializingBean接口

如下:

public class AnotherExampleBean implements InitializingBean {

    public void afterPropertiesSet() {
        // do some initialization work
    }
}
  • 使用Bean標籤中的init-method屬性

配置如下:

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {

    public void init() {
        // do some initialization work
    }
}
  • 使用@PostConstruct註解

配置如下:

public class ExampleBean {
	@PostConstruct
    public void init() {
        // do some initialization work
    }
}

2、Bean銷燬回調

實現銷燬回調方法,有以下三種形式

  • 實現DisposableBean接口
public class AnotherExampleBean implements DisposableBean {

    public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }
}
  • 使用Bean標籤中的destroy-method屬性
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {

    public void cleanup() {
        // do some destruction work (like releasing pooled connections)
    }
}
  • 使用@PreDestroy註解
public class ExampleBean {
	@PreDestroy
    public void cleanup() {
        // do some destruction work (like releasing pooled connections)
    }
}

3、配置默認的初始化及銷燬方法

我們可以通過如下這種配置,爲多個Bean同時指定初始化或銷燬方法

<beans default-init-method="init" default-destroy-method="destory">
    <bean id="blogService" class="com.something.DefaultBlogService">
        <property name="blogDao" ref="blogDao" />
    </bean>
</beans>

在上面的XML配置中,Spring會將所有處於beans標籤下的Bean的初始化方法名默認爲init,銷燬方法名默認爲destory

但是如果我們同時在bean標籤中也指定了init-method屬性,那麼默認的配置將會被覆蓋。

4、執行順序

如果我們在配置中同時讓一個Bean實現了回調接口,又在Bean標籤中指定了初始化方法,還進行了
@PostContruct註解的配置的話,那麼它們的執行順序如下:

  1. @PostConstruct所標記的方法
  2. InitializingBean 接口中的afterPropertiesSet() 方法
  3. Bean標籤中的 init()方法

對於銷燬方法執行順序如下:

  1. @PreDestroy所標記的方法
  2. destroy() DisposableBean 回調接口中的destroy()方法
  3. Bean標籤中的 destroy()方法

我們可以總結如下:

註解的優先級 > 實現接口的優先級 > XML配置的優先級

同時我們需要注意的是,官網推薦我們使用註解的形式來定義生命週期回調方法,這是因爲相比於實現接口,採用註解這種方式我們的代碼跟Spring框架本身的耦合度更加低。

5、容器啓動或停止回調

Lifecycle 接口
public interface Lifecycle {
    // 當容器啓動時調用
    void start();
    // 當容器停止時調用
    void stop();
    // 當前組件的運行狀態
    boolean isRunning();
}

編寫一個Demo如下:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
		ac.start();
		ac.stop();
	}
}

@Component
public class LifeCycleService implements Lifecycle {

	boolean isRunning;

	@Override
	public void start() {
		isRunning = true;
		System.out.println("LifeCycleService start");
	}

	@Override
	public void stop() {
		isRunning = false;
		System.out.println("LifeCycleService stop");
	}

	@Override
	public boolean isRunning() {
		return isRunning;
	}
}

運行上面的代碼可以發現程序正常打印啓動跟停止的日誌,在上面的例子中需要注意的時,一定要在start方法執行時將容器的運行狀態isRunning置爲true,否則stop方法不會調用


在Spring容器中,當接收到start或stop信號時,容器會將這些傳遞到所有實現了Lifecycle的組件上,在Spring內部是通過LifecycleProcessor接口來完成這一功能的。其接口定義如下:

LifecycleProcessor
public interface LifecycleProcessor extends Lifecycle {
	// 容器刷新時執行
    void onRefresh();
	// 容器關閉時執行
    void onClose();
}

從上面的代碼中我們可以知道,LifecycleProcessor本身也是Lifecycle接口的擴展,它添加了兩個額外的方法在容器刷新跟關閉時執行。

我們需要注意以下幾點:

  1. 當我們實現Lifecycle接口時,如果我們想要其start或者stop執行,必須顯式的調用容器的start()或者stop()方法。
  2. stop方法不一定能保證在我們之前介紹的銷燬方法之前執行

當我們在容器中對多個Bean配置了在容器啓動或停止時的調用時,那麼這些Bean中start方法跟stop方法調用的順序就很重要了。如果兩個Bean之間有明確的依賴關係,比如我們通過@DepnedsOn註解,或者@AutoWired註解向容器表明了Bean之間的依賴關係,如下:

@Component
@DependsOn("b")
class A{
//	@AutoWired
//   B b;
}

@Component
class B{

}

這種情況下,b作爲被依賴項,其start方法會在a的start方法前調用,stop方法會在a的stop方法後調用

但是,在某些情況下Bean直接並沒有直接的依賴關係,可能我們只知道實現了接口一的所有Bean的方法的優先級要高於實現了接口二的Bean。在這種情況下,我們就需要用到SmartLifecycle這個接口了

SmartLifecycle

其繼承關係如下:

在這裏插入圖片描述

它本身除了繼承了Lifecycle接口還繼承了一個Phased接口,其接口定義如下:

public interface Phased { 
    /**    
     * Return the phase value of this object.    
     */
    int getPhase();
}

通過上面接口定義的方法,我們可以指定不同Bean方法回調方法執行的優先級。

再來看看SmartLifecycle本身這個接口的定義

public interface SmartLifecycle extends Lifecycle, Phased {
    
	int DEFAULT_PHASE = Integer.MAX_VALUE;
	
    // 不需要顯示的調用容器的start方法及stop方法也可以執行Bean的start方法跟stop方法
	default boolean isAutoStartup() {
		return true;
	}
	
    // 容器停止時調用的方法
	default void stop(Runnable callback) {
		stop();
		callback.run();
	}
	
    // 優先級,默認最低
	@Override
	default int getPhase() {
		return DEFAULT_PHASE;
	}

}

一般情況下,我們並不會複寫isAutoStartup以及stop方法,但是爲了指定方法執行的優先級,我們通常會覆蓋其中的getPhase()方法,默認情況下它的優先級是最低的。我們需要知道的是,當我們啓動容器時,如果有Bean實現了SmartLifecycle接口,其getPhase()方法返回的值越小,那麼對於的start方法執行的時間就會越早,stop方法執行的時機就會越晚。因此,一個實現SmartLifecycle的對象,它的getPhase()方法返回Integer.MIN_VALUE將是第一個執行start方法的Bean和最後一個執行Stop方法的Bean。

另外我們可以看到

源碼分析

源碼分析,我們需要分爲兩個階段:

啓動階段

整個流程圖如下:

在這裏插入圖片描述

我們主要分析的代碼在其中的3-12-23-12-3步驟中

3-12-2解析,代碼如下:

	protected void initLifecycleProcessor() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
			this.lifecycleProcessor =
					beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
			}
		}
		else {
			DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
			defaultProcessor.setBeanFactory(beanFactory);
			this.lifecycleProcessor = defaultProcessor;
			beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
						"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
			}
		}
	}

這段代碼很簡單,就是做了一件事:判斷當前容器中是否有一個lifecycleProcessor的Bean或者BeanDefinition。如果有的話,採用這個提供的lifecycleProcessor,如果沒有的話自己new一個DefaultLifecycleProcessor。這個類主要負載將啓動或停止信息傳播到具體的Bean當中,我們稍後分析的代碼基本都在這個類中。

3-12-3解析:

其中的getLifecycleProcessor(),就是獲取我們上一步提供的lifecycleProcessor,然後調用其onRefresh方法,代碼如下:

public void onRefresh() {
    // 將start信號傳遞到Bean
    startBeans(true); 
    // 這個類本身也是一個實現了Lifecycle的接口的對象,將其running置爲true,標記爲運行中
    this.running = true;
}

之後調用了startBeans方法

private void startBeans(boolean autoStartupOnly) {
    
    // 獲取所有實現了Lifecycle接口的Bean,如果採用了factroyBean的方式配置了一個LifecycleBean,那麼factroyBean本身也要實現Lifecycle接口
    // 配置爲懶加載的LifecycleBean必須實現SmartLifeCycle才能被調用start方法
    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
    
    // key:如果實現了SmartLifeCycle,則爲其getPhase方法返回的值,如果只是實現了Lifecycle,則返回0
    // value:相同phase的Lifecycle的集合,並將其封裝到了一個LifecycleGroup中
    Map<Integer, LifecycleGroup> phases = new HashMap<>();
    
    // 遍歷所有的lifecycleBeans,填充上面申明的map
    lifecycleBeans.forEach((beanName, bean) -> {
        
        // 我們可以看到autoStartupOnly這個變量在上層傳遞過來的
        // 這個參數意味着是否只啓動“自動”的Bean,這是什麼意思呢?就是說,不需要手動調用容器的start方法
        // 從這裏可以看出,實現了SmartLifecycle接口的類並且其isAutoStartup如果返回true的話,會在容器啓動過程中自動調用,而僅僅實現了Lifecycle接口的類並不會被調用。
        // 如果我們去閱讀容器的start方法的會發現,當調用鏈到達這個方法時,autoStartupOnly這個變量寫死的爲false
        if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
            
            // 獲取這個Bean執行的階段,實際上就是調用SmartLifecycle中的getPhase方法
            // 如果沒有實現SmartLifecycle,而是單純的實現了Lifecycle,那麼直接返回0
            int phase = getPhase(bean);
            
            // 下面就是一個填充Map的操作,有的話add,沒有的話直接new一個,比較簡單
            LifecycleGroup group = phases.get(phase);
            if (group == null) {
                
                // LifecycleGroup構造函數需要四個參數
                // phase:代表這一組lifecycleBeans的執行階段
                // timeoutPerShutdownPhase:因爲lifecycleBean中的stop方法可以在另一個線程中運行,所以爲了確保當前階段的所有lifecycleBean都執行完,Spring使用了CountDownLatch,而爲了防止無休止的等待下去,所有這裏設置了一個等待的最大時間,默認爲30秒
                // lifecycleBeans:所有的實現了Lifecycle的Bean
                // autoStartupOnly: 手動調用容器的start方法時,爲false。容器啓動階段自動調用時爲true,詳細的含義在上面解釋過了
                group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
                phases.put(phase, group);
            }
            group.add(beanName, bean);
        }
    });
    if (!phases.isEmpty()) {
        List<Integer> keys = new ArrayList<>(phases.keySet());
        // 升序排序
        Collections.sort(keys);
        for (Integer key : keys) {
            // 獲取每個階段下所有的lifecycleBean,然後調用其start方法
            phases.get(key).start();
        }
    }
}

跟蹤代碼可以發現,start方法最終調用到了doStart方法,其代碼如下

private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
    Lifecycle bean = lifecycleBeans.remove(beanName);
    if (bean != null && bean != this) {
        // 獲取這個Bean依賴的其它Bean,在啓動時先啓動其依賴的Bean
        String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
        for (String dependency : dependenciesForBean) {
            doStart(lifecycleBeans, dependency, autoStartupOnly);
        }
        if (!bean.isRunning() &&
            (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {
            try {
                bean.start();
            }
            catch (Throwable ex) {
                throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);
            }
        }
    }
}

上面的邏輯可以歸結爲一句話:獲取這個Bean依賴的其它Bean,在啓動時先啓動其依賴的Bean,這也驗證了我們從官網上得出的結論。

停止階段

停止容器有兩種辦法,一種時顯式的調用容器的stop或者close方法,如下:

public static void main(String[] args) {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
    ac.register(LifeCycleConfig.class);
    ac.refresh();
    ac.stop();
    //		ac.close();
}

而另外一箇中是註冊一個JVM退出時的鉤子,如下:

public static void main(String[] args) {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
    ac.register(LifeCycleConfig.class);
    // 當main函數運行完成後,會調用容器doClose方法
    ac.registerShutdownHook();
    ac.refresh();
}

不論是上面哪一種方法,最終都會調用到DefaultLifecycleProcessoronClose方法,代碼如下:

public void onClose() {
    // 傳遞所有的停止信號到Bean
    stopBeans();
    // 跟啓動階段一樣,因爲它本身是一個實現了Lifecycle接口的Bean,所有需要更改它的運行標誌
    this.running = false;
}
private void stopBeans() {
    // 獲取容器中所有的實現了Lifecycle接口的Bean
    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
    Map<Integer, LifecycleGroup> phases = new HashMap<>();
    lifecycleBeans.forEach((beanName, bean) -> {
        int shutdownPhase = getPhase(bean);
        LifecycleGroup group = phases.get(shutdownPhase);
        if (group == null) {
            group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false);
            phases.put(shutdownPhase, group);
        }
        // 同一階段的Bean放到一起
        group.add(beanName, bean);
    });
    if (!phases.isEmpty()) {
        List<Integer> keys = new ArrayList<>(phases.keySet());
        // 跟start階段不同的是,這裏採用的是降序
        // 也就是階段越後的Bean,越先stop
        keys.sort(Collections.reverseOrder());
        for (Integer key : keys) {
            phases.get(key).stop();
        }
    }
}
public void stop() {
    if (this.members.isEmpty()) {
        return;
    }
    this.members.sort(Collections.reverseOrder());
    
    // 創建了一個CountDownLatch,需要等待的線程數量爲當前階段的所有ifecycleBean的數量
    CountDownLatch latch = new CountDownLatch(this.smartMemberCount);
    
    // stop方法可以異步執行,這裏保存的是還沒有執行完的lifecycleBean的名稱
    Set<String> countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet<>());
    
    // 所有lifecycleBeans的名字集合
    Set<String> lifecycleBeanNames = new HashSet<>(this.lifecycleBeans.keySet());
    for (LifecycleGroupMember member : this.members) {
        if (lifecycleBeanNames.contains(member.name)) {
            doStop(this.lifecycleBeans, member.name, latch, countDownBeanNames);
        }
        else if (member.bean instanceof SmartLifecycle) {
            // 按理說,這段代碼永遠不會執行,可能是版本遺留的代碼沒有進行刪除
            // 大家可以自行對比4.x的代碼跟5.x的代碼
            latch.countDown();
        }
    }
    try {
        // 最大等待時間30s,超時進行日誌打印
        latch.await(this.timeout, TimeUnit.MILLISECONDS);
        if (latch.getCount() > 0 && !countDownBeanNames.isEmpty() && logger.isInfoEnabled()) {
            logger.info("Failed to shut down " + countDownBeanNames.size() + " bean" +
                        (countDownBeanNames.size() > 1 ? "s" : "") + " with phase value " +
                        this.phase + " within timeout of " + this.timeout + ": " + countDownBeanNames);
        }
    }
    catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
    }
}
}
private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,
                    final CountDownLatch latch, final Set<String> countDownBeanNames) {
	
    Lifecycle bean = lifecycleBeans.remove(beanName);
    if (bean != null) {
        // 獲取這個Bean所被依賴的Bean,先對這些Bean進行stop操作
        String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);
        for (String dependentBean : dependentBeans) {
            doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames);
        }
        try {
            if (bean.isRunning()) {
                if (bean instanceof SmartLifecycle) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Asking bean '" + beanName + "' of type [" +
                                     bean.getClass().getName() + "] to stop");
                    }
                    countDownBeanNames.add(beanName);
                    
                    // 還記得到SmartLifecycle中的stop方法嗎?裏面接受了一個Runnable參數
                    // 就是在這裏地方傳進去的。主要就是進行一個操作latch.countDown(),標記當前的lifeCycleBean的stop方法執行完成
                    ((SmartLifecycle) bean).stop(() -> {
                        latch.countDown();
                        countDownBeanNames.remove(beanName);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Bean '" + beanName + "' completed its stop procedure");
                        }
                    });
                }
                else {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Stopping bean '" + beanName + "' of type [" +
                                     bean.getClass().getName() + "]");
                    }
                    bean.stop();
                    if (logger.isDebugEnabled()) {
                        logger.debug("Successfully stopped bean '" + beanName + "'");
                    }
                }
            }
            else if (bean instanceof SmartLifecycle) {
                // Don't wait for beans that aren't running...
                latch.countDown();
            }
        }
        catch (Throwable ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Failed to stop bean '" + beanName + "'", ex);
            }
        }
    }
}

整個stop方法跟start方法相比,邏輯上並沒有很大的區別,除了執行時順序相反外。

  • start方法,先找出這個Bean的所有依賴,然後先啓動這個Bean的依賴
  • stop方法,先找出哪些Bean依賴了當前的Bean,然後停止這些被依賴的Bean,之後再停止當前的Bean

Aware接口

在整個Bean的生命週期的初始化階段,有一個很重要的步驟就是執行相關的Aware接口,而整個Aware接口執行又可以分爲兩個階段:

  • 第一階段,執行BeanXXXAware接口
  • 執行其它Aware接口

至於爲什麼需要這樣分,我們在進行源碼分析的時候就明白了

我們可以發現,所有的Aware接口都是爲了能讓我們拿到容器中相關的資源,比如BeanNameAware,可以讓我們拿到Bean的名稱,ApplicationContextAware 可以讓我們拿到整個容器。但是使用Aware接口也會相應的帶來一些弊病,當我們去實現這些接口時,意味着我們的應用程序跟Spring容器發生了強耦合,違背了IOC的原則。所以一般情況下,並不推薦採用這種方式,除非我們在編寫一些整個應用基礎的組件。

Spring內部提供瞭如下這些Aware接口

在這裏插入圖片描述

初始化過程源碼分析

回顧我們之前的流程圖,我們可以看到,創建Bean的動作主要發生在3-11-6-4步驟中,主要分爲三步:

  1. createBeanInstance ,創建實例
  2. populateBean,屬性注入
  3. initializeBean,初始化

我們今天要分析的代碼主要就是第3-11-6-4-3步,其完成的功能主要就是初始化,相對於我們之前分析過的代碼來說,這段代碼算比較簡單的:

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
            // 第一步:執行aware接口中的方法,需要主要的是,不是所有的Aware接口都是在這步執行了
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
            // 第二步:完成Aware接口方法的執行,以及@PostConstructor,@PreDestroy註解的處理
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
            // 第三步:完成初始化方法執行
			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()) {
            // 第四步:完成AOP代理
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

第一步:執行部分aware接口中的方法

private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            ClassLoader bcl = getBeanClassLoader();
            if (bcl != null) {
                ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
            }
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

可以看到,在invokeAwareMethods這個方法中,並不是所有的Aware接口都會被執行,只有BeanNameAware,BeanClassLoaderAware,BeanFactoryAware這三個接口會被執行,這也是爲什麼我單獨將BeanXXXAware這一類的接口劃分爲一組的原因。這三個Aware接口分別實現的功能爲:

BeanNameAware:獲取Bean的名字

BeanClassLoaderAware:獲取加載這個Bean的類加載器

BeanFactoryAware:獲取當前的BeanFactory

第二步:完成Aware接口方法的執行,以及@PostConstructor,@PreDestroy註解的處理

  • Aware接口執行,出了我們上面介紹的三個Aware接口,其餘的接口都會在這個階段執行,例如我們之前說到的ApplicationContextAware 接口,它會被一個專門的後置處理器ApplicationContextAwareProcessor處理。其餘的接口也是類似的操作,這裏就不在贅述了
  • @PostConstructor,@PreDestroy兩個註解的處理。這兩個註解會被CommonAnnotationBeanPostProcessor這個後置處理器處理,需要注意的是@Resource註解也是被這個後置處理器進行處理的。關於註解的處理邏輯,我們後面的源碼閱讀相關文章中再做詳細分析。

第三步:完成初始化方法執行

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
    throws Throwable {
	// 是否實現了 InitializingBean接口
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || 
                               // 這個判斷基本恆成立,除非手動改變了BD的屬性
                               !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                   // 調用afterPropertiesSet方法
                    ((InitializingBean) bean).afterPropertiesSet();
                    return null;
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
              // 調用afterPropertiesSet方法
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }
	
    if (mbd != null && bean.getClass() != NullBean.class) {
        String initMethodName = mbd.getInitMethodName();
        if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

整段代碼的邏輯還是很簡單的,先判斷是否實現了對應的生命週期回調的接口(InitializingBean),如果實現了接口,先調用接口中的afterPropertiesSet方法。之後在判斷是否提供了initMethod,也就是在XML中的Bean標籤中提供了init-method屬性。

第四步:完成AOP代理

AOP代理實現的具體過程放到之後的文章中分析,我們暫時只需要知道AOP是在Bean完成了所有初始化方法後完成的即可。這也不難理解,在進行AOP之前必須保證我們的Bean已經被充分的”裝配“了。

總結

就目前而言,我們可以將整個Bean的生命週期總結如下:

在這裏插入圖片描述
在上圖中,實例話跟屬性注入的過程我們還沒有分析,在後續的文章中,我們將對其進行詳細的分析。銷燬階段並不複雜,所以這裏也不做分析了,直接給出結論,大概可以自己閱讀代碼,入口在容器的close方法中。

另外,我這裏並沒有將實現了LifeCycle接口的Bean中的start方法跟stop方法算入到整個Bean的生命週期中,大家只要知道,如果實現了SmartLifeCyle接口,那麼在容器啓動時也會默認調用其start方法,並且調用的時機在Bean完成初始化後,而stop方法將在Bean銷燬前調用。

掃描下方二維碼,關注我的公衆號,更多精彩文章在等您!~~

公衆號

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