生命週期
既然大家都放這個圖,那我也放吧:
主要流程
Bean 的生命週期概括起來就是 4 個階段:
- 例項化(Instantiation)
- 屬性賦值(Populate)
- 初始化(Initialization)
- 銷燬(Destruction)
看什麼都沒有直接看原始碼清楚,來吧,上程式碼:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.7</version>
</dependency>
AbstractAutowireCapableBeanFactory.java
doCreateBean()
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
//1-例項化
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
synchronized(mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable var17) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
}
mbd.postProcessed = true;
}
}
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
Object exposedObject = bean;
try {
//2-屬性賦值
this.populateBean(beanName, mbd, instanceWrapper);
//3-初始化
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
}
if (earlySingletonExposure) {
Object earlySingletonReference = this.getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
String[] dependentBeans = this.getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
String[] var12 = dependentBeans;
int var13 = dependentBeans.length;
for(int var14 = 0; var14 < var13; ++var14) {
String dependentBean = var12[var14];
if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
//4-銷燬-註冊回撥介面
try {
this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
} catch (BeanDefinitionValidationException var16) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
}
}
由於初始化包含了第 3~7步,較複雜,所以我們進到 initializeBean() 方法裡具體看下其過程(註釋的序號對應圖中序號):
initializeBean()
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//3-檢查 Aware 相關介面並設定相關依賴
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
//Aware系列介面,主要用於輔助Spring bean訪問Spring容器
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
this.invokeAwareMethods(beanName, bean);
}
// 4-BeanPostProcessor 前置處理
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
// 5-若實現 InitializingBean 介面,呼叫 afterPropertiesSet() 方法,這倆個方法都在invokeInitMethods裡面
// 6-若配置自定義的 init-method方法,則執行
try {
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}
// 7-BeanPostProceesor 後置處理
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
DisposableBeanAdapter.java
銷燬的過程
public void destroy() {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
Iterator var1 = this.beanPostProcessors.iterator();
while(var1.hasNext()) {
DestructionAwareBeanPostProcessor processor = (DestructionAwareBeanPostProcessor)var1.next();
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
//// 9-若實現 DisposableBean 介面,則執行 destory()方法
if (this.invokeDisposableBean) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
}
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
((DisposableBean)this.bean).destroy();
return null;
}, this.acc);
} else {
((DisposableBean)this.bean).destroy();
}
} catch (Throwable var3) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, var3);
} else {
logger.warn(msg + ": " + var3);
}
}
}
// 10-若配置自定義的 detory-method 方法,則執行
if (this.destroyMethod != null) {
this.invokeCustomDestroyMethod(this.destroyMethod);
} else if (this.destroyMethodName != null) {
Method methodToInvoke = this.determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) {
this.invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
}
}
}
註解方式
在 bean 初始化時會經歷幾個階段,首先可以使用註解 @PostConstruct
, @PreDestroy
來在 bean 的建立和銷燬階段進行呼叫:
@Component
public class AnnotationBean {
private final static Logger LOGGER = LoggerFactory.getLogger(AnnotationBean.class);
@PostConstruct
public void start(){
LOGGER.info("AnnotationBean start");
}
@PreDestroy
public void destroy(){
LOGGER.info("AnnotationBean destroy");
}
}
InitializingBean, DisposableBean 介面
還可以實現 InitializingBean,DisposableBean
這兩個介面,也是在初始化以及銷燬階段呼叫:
@Service
public class SpringLifeCycleService implements InitializingBean,DisposableBean{
private final static Logger LOGGER = LoggerFactory.getLogger(SpringLifeCycleService.class);
@Override
public void afterPropertiesSet() throws Exception {
LOGGER.info("SpringLifeCycleService start");
}
@Override
public void destroy() throws Exception {
LOGGER.info("SpringLifeCycleService destroy");
}
}
自定義初始化和銷燬方法
也可以自定義方法用於在初始化、銷燬階段呼叫:
@Configuration
public class LifeCycleConfig {
@Bean(initMethod = "start", destroyMethod = "destroy")
public SpringLifeCycle create(){
SpringLifeCycle springLifeCycle = new SpringLifeCycle() ;
return springLifeCycle ;
}
}
public class SpringLifeCycle{
private final static Logger LOGGER = LoggerFactory.getLogger(SpringLifeCycle.class);
public void start(){
LOGGER.info("SpringLifeCycle start");
}
public void destroy(){
LOGGER.info("SpringLifeCycle destroy");
}
}
以上是在 SpringBoot 中可以這樣配置,如果是原始的基於 XML 也是可以使用:
<bean class="com.crossoverjie.spring.SpringLifeCycle" init-method="start" destroy-method="destroy">
</bean>
擴充套件點的作用
Aware 介面
若 Spring 檢測到 bean 實現了 Aware 介面,則會為其注入相應的依賴。所以通過讓bean 實現 Aware 介面,則能在 bean 中獲得相應的 Spring 容器資源。
Spring 中提供的 Aware 介面有:
- BeanNameAware:注入當前 bean 對應 beanName;
- BeanClassLoaderAware:注入載入當前 bean 的 ClassLoader;
- BeanFactoryAware:注入 當前BeanFactory容器 的引用。
其程式碼實現如下:
// AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware)bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = this.getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware)bean).setBeanFactory(this);
}
}
}
以上是針對 BeanFactory 型別的容器,而對於 ApplicationContext 型別的容器,也提供了 Aware 介面,只不過這些 Aware 介面的注入實現,是通過 BeanPostProcessor 的方式注入的,但其作用仍是注入依賴。
- EnvironmentAware:注入 Enviroment,一般用於獲取配置屬性;
- EmbeddedValueResolverAware:注入 EmbeddedValueResolver(Spring EL解析器),一般用於引數解析;
- ApplicationContextAware(ResourceLoader、ApplicationEventPublisherAware、MessageSourceAware):注入 ApplicationContext 容器本身。
其程式碼實現如下:
// ApplicationContextAwareProcessor.java
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware)bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
}
實現 Aware 介面
例子:
@Component
public class SpringLifeCycleAware implements ApplicationContextAware {
private final static Logger LOGGER = LoggerFactory.getLogger(SpringLifeCycleAware.class);
private ApplicationContext applicationContext ;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext ;
LOGGER.info("SpringLifeCycleAware start");
}
}
BeanPostProcessor
實現 BeanPostProcessor 介面,Spring 中所有 bean 在做初始化時都會呼叫該介面中的兩個方法,可以用於對一些特殊的 bean 進行處理:
public interface BeanPostProcessor {
// 初始化前置處理
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 初始化後置處理
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
常用場景有:
- 對於標記介面的實現類,進行自定義處理。例如3.1節中所說的ApplicationContextAwareProcessor,為其注入相應依賴;再舉個例子,自定義對實現解密介面的類,將對其屬性進行解密處理;
- 為當前物件提供代理實現。
例如 Spring AOP 功能,生成物件的代理類,然後返回。
// AbstractAutoProxyCreator.java
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理類
return proxy;
}
return null;
}
例子:
@Component
public class SpringLifeCycleProcessor implements BeanPostProcessor {
private final static Logger LOGGER = LoggerFactory.getLogger(SpringLifeCycleProcessor.class);
/**
* 預初始化 初始化之前呼叫
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("annotationBean".equals(beanName)){
LOGGER.info("SpringLifeCycleProcessor start beanName={}",beanName);
}
return bean;
}
/**
* 後初始化 bean 初始化完成呼叫
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("annotationBean".equals(beanName)){
LOGGER.info("SpringLifeCycleProcessor end beanName={}",beanName);
}
return bean;
}
}
//結果
結果: 00:40:24.856 [restartedMain] INFO c.c.s.p.SpringLifeCycleProcessor - SpringLifeCycleProcessor start beanName=annotationBean
結果: 00:40:24.860 [restartedMain] INFO c.c.spring.annotation.AnnotationBean - AnnotationBean start
結果: 00:40:24.861 [restartedMain] INFO c.c.s.p.SpringLifeCycleProcessor - SpringLifeCycleProcessor end beanName=annotationBean
結果: 00:40:24.864 [restartedMain] INFO c.c.s.aware.SpringLifeCycleAware - SpringLifeCycleAware start
結果: 00:40:24.867 [restartedMain] INFO c.c.s.service.SpringLifeCycleService - SpringLifeCycleService start
結果: 00:40:24.887 [restartedMain] INFO c.c.spring.SpringLifeCycle - SpringLifeCycle start
結果: 00:40:25.062 [restartedMain] INFO o.s.b.d.a.OptionalLiveReloadServer - LiveReload server is running on port 35729
結果: 00:40:25.122 [restartedMain] INFO o.s.j.e.a.AnnotationMBeanExporter - Registering beans for JMX exposure on startup
結果: 00:40:25.140 [restartedMain] INFO com.crossoverjie.Application - Started Application in 2.309 seconds (JVM running for 3.681)
結果: 00:40:25.143 [restartedMain] INFO com.crossoverjie.Application - start ok!
結果: 00:40:25.153 [Thread-8] INFO o.s.c.a.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3913adad: startup date [Wed Mar 21 00:40:23 CST 2018]; root of context hierarchy
結果: 00:40:25.155 [Thread-8] INFO o.s.j.e.a.AnnotationMBeanExporter - Unregistering JMX-exposed beans on shutdown
結果: 00:40:25.156 [Thread-8] INFO c.c.spring.SpringLifeCycle - SpringLifeCycle destroy
結果: 00:40:25.156 [Thread-8] INFO c.c.s.service.SpringLifeCycleService - SpringLifeCycleService destroy
結果: 00:40:25.156 [Thread-8] INFO c.c.spring.annotation.AnnotationBean - AnnotationBean destroy
直到 Spring 上下文銷燬時則會呼叫自定義的銷燬方法以及實現了 DisposableBean
的 destroy()
方法。
InitializingBean 和 init-method
InitializingBean 和 init-method 是 Spring 為 bean 初始化提供的擴充套件點。
InitializingBean介面 的定義如下:
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
在 afterPropertiesSet() 方法寫初始化邏輯。
指定 init-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 id="demo" class="com.chaycao.Demo" init-method="init()"/>
</beans>
DisposableBean 和 destory-method 與上述類似,就不描述了。
總結
最後總結下如何記憶 Spring Bean 的生命週期:
- 首先是例項化、屬性賦值、初始化、銷燬這 4 個大階段;
- 再是初始化的具體操作,有 Aware 介面的依賴注入、BeanPostProcessor 在初始化前後的處理以及 InitializingBean 和 init-method 的初始化操作;
- 銷燬的具體操作,有註冊相關銷燬回撥介面,最後通過DisposableBean 和 destory-method 進行銷燬。
作用域
詳情請見: