Spring Bean 生命週期 (實例結合源碼完全講透)

前言

本篇文章主要是要介紹如何在Spring IoC 容器中 如何管理Spring Bean生命週期。php

在應用開發中,經常須要執行一些特定的初始化工做,這些工做都是相對比較固定的,好比創建數據庫鏈接,打開網絡鏈接等,同時,在結束服務時,也有一些相對固定的銷燬工做須要執行。爲了便於這些工做的設計,Spring IoC容器提供了相關的功能,可讓應用定製Bean的初始化和銷燬過程。java

Spring Bean 生命週期

圖片描述

先來看看 Spring Bean 的生命週期流程圖。結合圖看後面的描述會更輕鬆一點哦。spring

spring bean life cycle.png

文字描述

  1. Bean容器在配置文件中找到Spring Bean的定義。
  2. Bean容器使用Java Reflection API建立Bean的實例。
  3. 若是聲明瞭任何屬性,聲明的屬性會被設置。若是屬性自己是Bean,則將對其進行解析和設置。
  4. 若是Bean類實現BeanNameAware接口,則將經過傳遞Bean的名稱來調用setBeanName()方法。
  5. 若是Bean類實現BeanClassLoaderAware接口,則將經過傳遞加載此Bean的ClassLoader對象的實例來調用setBeanClassLoader()方法。
  6. 若是Bean類實現BeanFactoryAware接口,則將經過傳遞BeanFactory對象的實例來調用setBeanFactory()方法。
  7. 若是有任何與BeanFactory關聯的BeanPostProcessors對象已加載Bean,則將在設置Bean屬性以前調用postProcessBeforeInitialization()方法。
  8. 若是Bean類實現了InitializingBean接口,則在設置了配置文件中定義的全部Bean屬性後,將調用afterPropertiesSet()方法。
  9. 若是配置文件中的Bean定義包含init-method屬性,則該屬性的值將解析爲Bean類中的方法名稱,並將調用該方法。
  10. 若是爲Bean Factory對象附加了任何Bean 後置處理器,則將調用postProcessAfterInitialization()方法。
  11. 若是Bean類實現DisposableBean接口,則當Application再也不須要Bean引用時,將調用destroy()方法。
  12. 若是配置文件中的Bean定義包含destroy-method屬性,那麼將調用Bean類中的相應方法定義。

實例演示

接下來,咱們用一個簡單的DEMO來演示一下,整個生命週期的流轉過程,加深你的印象。數據庫

  1. 定義一個Person類,實現了DisposableBean, InitializingBean, BeanFactoryAware, BeanNameAware這4個接口,同時還有自定義的init-methoddestroy-method。這裏,若是不瞭解這幾個接口的讀者,能夠先去看看這幾個接口的定義。
public class Person implements DisposableBean, InitializingBean, BeanFactoryAware, BeanNameAware {

    private String name;

    Person() {
        System.out.println("Constructor of person bean is invoked!");
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("setBeanFactory method of person is invoked");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("setBeanName method of person is invoked");
    }

    public void init() {
        System.out.println("custom init method of person bean is invoked!");
    }

    //Bean initialization code equals to
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet method of person bean is invoked!");
    }

    //Bean destruction code
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean Destroy method of person bean is invoked!");
    }

    public void destroyMethod() {
        System.out.println("custom Destroy method of person bean is invoked!");
    }

}
複製代碼
  1. 定義一個MyBeanPostProcessor實現BeanPostProcessor接口。
public class MyBeanPostProcessor implements BeanPostProcessor {


    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("post Process Before Initialization is invoked");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("post Process after Initialization is invoked");
        return bean;
    }
}

複製代碼
  1. 配置文件,指定init-methoddestroy-method屬性
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="myBeanPostProcessor" class="ric.study.demo.ioc.life_cycle_demo_set.MyBeanPostProcessor" />
    <bean name="personBean" class="ric.study.demo.ioc.life_cycle_demo_set.Person" init-method="init" destroy-method="destroyMethod">
        <property name="name" value="Richard Yi" />
    </bean>

</beans>
複製代碼
  1. 啓動容器、銷燬容器
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config-1.xml");
        ((ClassPathXmlApplicationContext) context).destroy();
    }
}
複製代碼
  1. 輸出
Constructor of person bean is invoked!
setBeanName method of person is invoked
setBeanFactory method of person is invoked
post Process Before Initialization is invoked
afterPropertiesSet method of person bean is invoked!
custom init method of person bean is invoked!
post Process after Initialization is invoked
DisposableBean Destroy method of person bean is invoked!
custom Destroy method of person bean is invoked!
複製代碼

能夠看到這個結果和咱們上面描述的同樣。bash

源碼解析

下面咱們從源碼角度來看看,上述描述的調用是如何實現的。網絡

實際上若是你看過我以前的文章 Spring IoC 依賴注入 源碼解析的話,應該知道上述調用的具體實現。app

這裏至關於把相關部分再拎出來說一遍。ide

容器初始化

Spring IoC 依賴注入的階段,建立Bean有三個關鍵步驟post

  1. createBeanInstance() 實例化
  2. populateBean(); 屬性裝配
  3. initializeBean() 處理Bean初始化以後的各類回調事件

其中,initializeBean()負責處理Bean初始化後的各類回調事件。ui

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					invokeAwareMethods(beanName, bean);
					return null;
				}
			}, getAccessControlContext());
		}
		else {
            // 涉及到的回調接口點進去一目瞭然,代碼都是自解釋的
            // BeanNameAware、BeanClassLoaderAware或BeanFactoryAware
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
            // BeanPostProcessor 的 postProcessBeforeInitialization 回調
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
            // init-methods
            // 或者是實現了InitializingBean接口,會調用afterPropertiesSet() 方法
			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 的 postProcessAfterInitialization 回調
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}
複製代碼

其中invokeAwareMethods會先調用一系列的***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) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}
複製代碼

而後再執行 BeanPostProcessorpostProcessBeforeInitialization 回調

@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			result = beanProcessor.postProcessBeforeInitialization(result, beanName);
			if (result == null) {
				return result;
			}
		}
		return result;
	}
複製代碼

而後再調用 初始化方法,其中包括 InitializingBeanafterPropertiesSet方法和指定的init-method方法,

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 {
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		if (mbd != null) {
			String initMethodName = mbd.getInitMethodName();
			if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}
複製代碼

最後再執行 BeanPostProcessorpostProcessAfterInitialization 回調

@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			result = beanProcessor.postProcessAfterInitialization(result, beanName);
			if (result == null) {
				return result;
			}
		}
		return result;
	}
複製代碼

好的,到這裏咱們介紹了Spring 容器初始化過程Bean加載過程中的各類回調實現,下面介紹Spring 容器銷燬階段。

容器關閉

與Bean初始化相似,當容器關閉時,能夠看到對Bean銷燬方法的調用。銷燬過程是這樣的。順着close()-> doClose() -> destroyBeans() -> destroySingletons() -> destroySingleton() -> destroyBean() -> bean.destroy(),會看到最終調用Bean的銷燬方法。

protected void destroyBean(String beanName, DisposableBean bean) {
		// 忽略

		// Actually destroy the bean now...
		if (bean != null) {
			try {
				bean.destroy();
			}
			catch (Throwable ex) {
				logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);
			}
		}

		// 忽略
	}
複製代碼

這裏注意哦,這個Bean的類型其實是DisposableBeanAdapter,DisposableBeanAdapter是管理Spring Bean的銷燬的,實際上這裏運用了適配器模式。再來看看destroy()的具體方法。

@Override
	public void destroy() {
		if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
			for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
				processor.postProcessBeforeDestruction(this.bean, this.beanName);
			}
		}

		if (this.invokeDisposableBean) {
			if (logger.isDebugEnabled()) {
				logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");
			}
			try {
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
						@Override
						public Object run() throws Exception {
							((DisposableBean) bean).destroy();
							return null;
						}
					}, acc);
				}
				else {
                    // 調用 DisposableBean 的 destroy()方法
					((DisposableBean) bean).destroy();
				}
			}
			catch (Throwable ex) {
				String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
				if (logger.isDebugEnabled()) {
					logger.warn(msg, ex);
				}
				else {
					logger.warn(msg + ": " + ex);
				}
			}
		}

		if (this.destroyMethod != null) {
            // 調用 設置的destroyMethod
			invokeCustomDestroyMethod(this.destroyMethod);
		}
		else if (this.destroyMethodName != null) {
			Method methodToCall = determineDestroyMethod();
			if (methodToCall != null) {
				invokeCustomDestroyMethod(methodToCall);
			}
		}
	}
複製代碼

BeanPostProcessor 是何時註冊到容器的?

前面只介紹了BeanPostProcessor類在 Spring Bean 生命週期中的回調實現,卻沒有說明 BeanPostProcessor 是何時註冊到容器的。下面咱們來介紹下。

在Spring IoC 容器初始化的時候,容器會作一些初始化操做,其中就包括了BeanPostProcessor的register過程。詳細的過程能夠看我這篇IoC 容器初始化

這裏直接放源碼吧。

源碼位置AbstractApplicationContext#refresh()

@Override
	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 {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
                // 在這裏
				registerBeanPostProcessors(beanFactory);
			// ....忽略
		}
	}
複製代碼
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
	}
複製代碼

源碼位置PostProcessorRegistrationDelegate#registerBeanPostProcessors()

public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// step1
		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// step2
		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
		List<String> orderedPostProcessorNames = new ArrayList<String>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}
// step3
		// First, register the BeanPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// Finally, re-register all internal BeanPostProcessors.
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}
複製代碼

上述過程能夠分紅四步:

  1. 經過beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);方法獲取beanFactory裏繼承了BeanPostProcessor接口的name的集合;
  2. 把後置器beans分爲PriorityOrdered、Ordered、nonOrdered三大類,前兩類是增長了排序條件的後置器;(Spring能夠經過PriorityOrderedOrdered接口控制處理器的優先級),這裏實際上還有一類是MergedBeanDefinitionPostProcessor,不是核心點,不展開講。
  3. 第三步能夠分爲如下小步
    1. priorityOrderedPostProcessors,先排序後註冊
    2. orderedPostProcessors,先排序後註冊
    3. 註冊nonOrderedPostProcessors,就是通常的處理器
    4. internalPostProcessors,先排序後註冊
    5. 註冊一個ApplicationListenerDetector的 processor

DisposableBeanAdapter 何時註冊到容器的?

DisposableBeanAdapter和上文的BeanPostProcessor的抽象層級不一樣,這個是和Bean綁定的,因此它的註冊時機是在Spring Bean的依賴注入階段,詳細源碼能夠看個人這篇文章Spring IoC 依賴注入 源碼解析

源碼位置:AbstractAutowireCapableBeanFactory#doCreateBean()

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException {
		// 省略前面的超多步驟,想了解的能夠去看源碼或者個人那篇文章

		// Register bean as disposable.
    	// 這裏就是DisposableBeanAdapter的註冊步驟了
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}
複製代碼

源碼位置:AbstractBeanFactory#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()) {
                // 註冊一個DisposableBean實現,該實現將執行給定bean的全部銷燬工做。
                // 包括:DestructionAwareBeanPostProcessors,DisposableBean接口,自定義destroy方法。
				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));
			}
		}
	}
複製代碼

結語

至此,Spring Bean的整個生命週期算是講解完了,從容器初始化到容器銷燬,以及回調事件的註冊時機等方面都說明了一下,但願能對你有所幫助。

本文由博客一文多發平臺 OpenWrite 發佈!

相關文章
相關標籤/搜索