Bean-生命週期

生命週期

既然你們都放這個圖,那我也放吧:java

主要流程

Bean 的生命週期歸納起來就是 4 個階段web

  1. 實例化(Instantiation)
  2. 屬性賦值(Populate)
  3. 初始化(Initialization)
  4. 銷燬(Destruction)

看什麼都沒有直接看源代碼清楚,來吧,上代碼:spring

<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() 方法裏具體看下其過程(註釋的序號對應圖中序號):mvc

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

銷燬的過程app

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 的建立和銷燬階段進行調用:ide

@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 這兩個接口,也是在初始化以及銷燬階段調用:post

@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");
    }
}

自定義初始化和銷燬方法

也能夠自定義方法用於在初始化、銷燬階段調用:this

@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 容器資源rest

Spring 中提供的 Aware 接口有:

  1. BeanNameAware:注入當前 bean 對應 beanName;
  2. BeanClassLoaderAware:注入加載當前 bean 的 ClassLoader;
  3. 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 的方式注入的,但其做用還是注入依賴。

  1. EnvironmentAware:注入 Enviroment,通常用於獲取配置屬性;
  2. EmbeddedValueResolverAware:注入 EmbeddedValueResolver(Spring EL解析器),通常用於參數解析;
  3. 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;
	}

}

經常使用場景有:

  1. 對於標記接口的實現類,進行自定義處理。例如3.1節中所說的ApplicationContextAwareProcessor,爲其注入相應依賴;再舉個例子,自定義對實現解密接口的類,將對其屬性進行解密處理;
  2. 爲當前對象提供代理實現。

例如 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 上下文銷燬時則會調用自定義的銷燬方法以及實現了 DisposableBeandestroy() 方法。

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 進行銷燬。

做用域

詳情請見:

參考連接

https://juejin.cn/post/6844903581011689480

https://juejin.cn/post/6844904065457979405

相關文章
相關標籤/搜索