源碼分享《SpringBean生命周期》
今日主題:Spring Bean的生命周期的分析和說明
使用場景:
1.項目啟動做一些業(yè)務化的操作
2.項目停止的時候做一些業(yè)務化的操作
3.面試官會問你,SpringBena的生命周期了解嗎
其實SpringBean的生命周期其實只有四個部分
Bean的實例化
Bean的初始化
Bean的使用
Bean的銷毀
知識儲備
接下來我們一起看幾個Spring提供的接口(源碼中的所有英文注釋全部留著了,大家可以看看Spring自身對其的描述,不同人可能會有不同的想法吧)
1.BeanNameAware只有一個方法setBeanName,這個方法主要是讓Bean自身知道定義的Bean的名稱,有之前接觸過使用XML配置spring bean的同學,就應該知道,這個就是bean的id屬性;實現(xiàn)這個接口,我們的Bean就可以知道自身注冊在容器中的名稱
public interface BeanNameAware extends Aware {/*** Set the name of the bean in the bean factory that created this bean.* <p>Invoked after population of normal bean properties but before an* init callback such as {@link InitializingBean#afterPropertiesSet()}* or a custom init-method.* @param name the name of the bean in the factory.* Note that this name is the actual bean name used in the factory, which may* differ from the originally specified name: in particular for inner bean* names, the actual bean name might have been made unique through appending* "#..." suffixes. Use the {@link BeanFactoryUtils#originalBeanName(String)}* method to extract the original bean name (without suffix), if desired.*/void setBeanName(String name);}
2.BeanFactoryAware也是只有一個方法setBeanFactory,這個方法主要是讓Bean獲取到容器的內部信息,從而進行某些定制化的操作
public interface BeanFactoryAware extends Aware {/*** Callback that supplies the owning factory to a bean instance.* <p>Invoked after the population of normal bean properties* but before an initialization callback such as* {@link InitializingBean#afterPropertiesSet()} or a custom init-method.* @param beanFactory owning BeanFactory (never {@code null}).* The bean can immediately call methods on the factory.* @throws BeansException in case of initialization errors* @see BeanInitializationException*/void setBeanFactory(BeanFactory beanFactory) throws BeansException;}
3.ApplicationContextAware也是只有一個方法setApplicationContext,該方法可以將ApplicationContext設置到Bean中,可以由此獲取其他的bean。比如我們開發(fā)的時候,并不是說在每一個地方都能將屬性注入到我們想要的地方去的,比如在Utils使用到dao,我們就不能直接注入了,這個時候就是我們需要封裝springContext的時候了,而ApplicationContextAware就起了關鍵性的作用
public interface ApplicationContextAware extends Aware {/*** Set the ApplicationContext that this object runs in.* Normally this call will be used to initialize the object.* <p>Invoked after population of normal bean properties but before an init callback such* as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and* {@link MessageSourceAware}, if applicable.* @param applicationContext the ApplicationContext object to be used by this object* @throws ApplicationContextException in case of context initialization errors* @throws BeansException if thrown by application context methods* @see org.springframework.beans.factory.BeanInitializationException*/void setApplicationContext(ApplicationContext applicationContext) throws BeansException;}
4.BeanPostProcessor從字面上來說,就是Bean的后置處理器,就是在bean的生命周期內,對Bean進行一系列的操作,簡單來說就是初始化之前操作Bean,初始化后在對于Bean進行操作
public interface BeanPostProcessor {/*** Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}* or a custom init-method). The bean will already be populated with property values.* The returned bean instance may be a wrapper around the original.* <p>The default implementation returns the given {@code bean} as-is.* @param bean the new bean instance* @param beanName the name of the bean* @return the bean instance to use, either the original or a wrapped one;* if {@code null}, no subsequent BeanPostProcessors will be invoked* @throws org.springframework.beans.BeansException in case of errors* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet*/default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}/*** Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}* or a custom init-method). The bean will already be populated with property values.* The returned bean instance may be a wrapper around the original.* <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean* instance and the objects created by the FactoryBean (as of Spring 2.0). The* post-processor can decide whether to apply to either the FactoryBean or created* objects or both through corresponding {@code bean instanceof FactoryBean} checks.* <p>This callback will also be invoked after a short-circuiting triggered by a* {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,* in contrast to all other BeanPostProcessor callbacks.* <p>The default implementation returns the given {@code bean} as-is.* @param bean the new bean instance* @param beanName the name of the bean* @return the bean instance to use, either the original or a wrapped one;* if {@code null}, no subsequent BeanPostProcessors will be invoked* @throws org.springframework.beans.BeansException in case of errors* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet* @see org.springframework.beans.factory.FactoryBean*/default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;????}}
5.InitializingBean在當你通過sring容器生產(chǎn)出實現(xiàn)了該接口的類的實例后,它就會調用afterPropertiesSet方法,通過這個方法,你可以檢查你的bean是否正確地被初始化了
public interface InitializingBean {/*** Invoked by the containing {@code BeanFactory} after it has set all bean properties* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.* <p>This method allows the bean instance to perform validation of its overall* configuration and final initialization when all bean properties have been set.* @throws Exception in the event of misconfiguration (such as failure to set an* essential property) or if initialization fails for any other reason*/void afterPropertiesSet() throws Exception;}
Spring Bean生命周期圖示
如圖所示
Bean初期涉及到Bean定義和初始化加載,初始化加載部分,可以查看另一篇文章
實現(xiàn)接口BeanNameAware,BeanFactoryAware,ApplicationContextAware來在Bean中使用Spring框架的一些對象屬性。
實現(xiàn)接口BeanPostProcessor對于bean進行前置處理
調用bean的自定義方法(注解@PostConstruct方法)
實現(xiàn)InitializingBean方法
Bean定義的初始化方法init-method
實現(xiàn)接口BeanPostProcessor對于bean進行后置處理
生存期.....
調用bean的自定義方法(注解PreDestory方法)
實現(xiàn)接口DisposableBean重寫destory方法
Bean定義的銷毀方法destory-method
額外知識點
實現(xiàn)*Aware接口 在Bean中使用Spring框架的一些對象
有些時候我們需要在Bean的初始化中使用Spring框架自身的一些對象來執(zhí)行一些操作,比如獲取ServletContext的一些參數(shù),獲取ApplicaitionContext中的BeanDefinition的名字,獲取Bean在容器中的名字等等。為了讓Bean可以獲取到框架自身的一些對象,Spring提供了一組名為*Aware的接口。
這些接口均繼承于標記接口org.springframework.beans.factory.Aware,并提供一個將由Bean實現(xiàn)的set*方法,Spring通過基于setter的依賴注入方式使相應的對象可以被Bean使用
就此我們來說一下重要的Aware接口
ApplicationContextAware: 獲得ApplicationContext對象,可以用來獲取所有Bean definition的名字。
BeanFactoryAware:獲得BeanFactory對象,可以用來檢測Bean的作用域。
BeanNameAware:獲得Bean在配置文件中定義的名字。
ResourceLoaderAware:獲得ResourceLoader對象,可以獲得classpath中某個文件。
ServletContextAware:在一個MVC應用中可以獲取ServletContext對象,可以讀取context中的參數(shù)。
ServletConfigAware在一個MVC應用中可以獲取ServletConfig對象,可以讀取config中的參數(shù)。
代碼示例
1.新建一個SpringBoot項目
?
2示例代碼如下:
BeanLifeCycle.java
package com.example.smile7up.demo.spring.bean;import com.example.smile7up.demo.spring.common.OrderCount;import org.springframework.beans.BeansException;import org.springframework.beans.factory.*;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import javax.annotation.PostConstruct;import javax.annotation.PreDestroy;/*** 2020/7/9** @author smile7up*/public class BeanLifeCycle implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware, ApplicationContextAware {public BeanLifeCycle() {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement+":調用Bean的構造器方法(constructor)");}public void setBeanName(String name) {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement+":獲取定義的Bean的名稱為:" + name);}public void setBeanFactory(BeanFactory beanFactory) throws BeansException {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement+":獲取定義的Bean所在的BeanFactory" + beanFactory.getClass().getSimpleName());}public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement+":獲取定義的Bean所在的ApplicationContext,為" + applicationContext.getClass().getSimpleName());}public void postConstruct() {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement+":調用Bean的函數(shù):方法包含注解@PostConstruct");}public void afterPropertiesSet() throws Exception {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement+":調用Bean的函數(shù)實現(xiàn)接口InitializingBean,重寫方法afterPropertiesSet)");}public void initMethod() {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement+":調用Bean的定義的時候聲明的initMethod");}public void preDestroy() {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement+":調用Bean的函數(shù):方法包含注解@PreDestroy");}public void destroy() throws Exception {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement+":調用Bean的函數(shù)實現(xiàn)接口DisposableBean,重寫方法destory");}public void destroyMethod() {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement+":調用Bean的定義的時候聲明的destroyMethod)");}}
OrderCount.java
package com.example.smile7up.demo.spring.common;import lombok.Getter;import java.util.concurrent.atomic.AtomicInteger;/*** 2020/7/9** @author smile7up*/public class OrderCount {public static AtomicInteger count = new AtomicInteger(0);}
BeanLifeCycleConfig.java
package com.example.smile7up.demo.spring.config;import com.example.smile7up.demo.spring.bean.BeanLifeCycle;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/*** 2020/7/9** @author smile7up*/@Configurationpublic class BeanLifeCycleConfig {@Bean(name = "testBeanName",initMethod = "initMethod", destroyMethod = "destroyMethod")public BeanLifeCycle beanLifeCycle() {return new BeanLifeCycle();}}
CustomBeanProcessor.java
package com.example.smile7up.demo.spring.processor;import com.example.smile7up.demo.spring.bean.BeanLifeCycle;import com.example.smile7up.demo.spring.common.OrderCount;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;import org.springframework.stereotype.Component;/*** 2020/7/9** @author smile7up*/@Componentpublic class CustomBeanProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean.getClass() == BeanLifeCycle.class) {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement + ":調用方法postProcessBeforeInitialization...");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean.getClass() == BeanLifeCycle.class) {int andIncrement = OrderCount.count.getAndIncrement();System.out.println(andIncrement + ":調用方法postProcessAfterInitialization...");}return bean;}}
執(zhí)行結果如下
2020-07-15 14:13:36.988 INFO 20923 --- [ main] c.e.s.demo.spring.DemoSpringApplication : Starting DemoSpringApplication on liuzuolongdeMacBook-Pro.local with PID 20923 (/Users/liuzuolong/project/smile_show_project/demo-spring/target/classes started by liuzuolong in /Users/liuzuolong/project/smile_show_project/demo-spring)2020-07-15 14:13:36.990 INFO 20923 --- [ main] c.e.s.demo.spring.DemoSpringApplication : No active profile set, falling back to default profiles: default2020-07-15 14:13:37.741 INFO 20923 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8081 (http)2020-07-15 14:13:37.758 INFO 20923 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]2020-07-15 14:13:37.758 INFO 20923 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.21]2020-07-15 14:13:37.821 INFO 20923 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext2020-07-15 14:13:37.822 INFO 20923 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 790 ms0:調用Bean的構造器方法(constructor)1:獲取定義的Bean的名稱為:testBeanName2:獲取定義的Bean所在的BeanFactoryDefaultListableBeanFactory3:獲取定義的Bean所在的ApplicationContext,為AnnotationConfigServletWebServerApplicationContext4:調用方法postProcessBeforeInitialization...5:調用Bean的函數(shù):方法包含注解6:調用Bean的函數(shù)實現(xiàn)接口InitializingBean,重寫方法afterPropertiesSet)7:調用Bean的定義的時候聲明的initMethod8:調用方法postProcessAfterInitialization...2020-07-15 14:13:37.965 INFO 20923 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'2020-07-15 14:13:38.107 INFO 20923 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path ''2020-07-15 14:13:38.110 INFO 20923 --- [ main] c.e.s.demo.spring.DemoSpringApplication : Started DemoSpringApplication in 1.42 seconds (JVM running for 2.479)Disconnected from the target VM, address: '127.0.0.1:64381', transport: 'socket'2020-07-15 14:13:42.260 INFO 20923 --- [ Thread-5] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'9:調用Bean的函數(shù):方法包含注解10:調用Bean的函數(shù)實現(xiàn)接口DisposableBean,重寫方法destory11:調用Bean的定義的時候聲明的destroyMethod)
經(jīng)過今天的學習,我們可以大致的了解了Spring Bean的生命周期,這樣對以后我們在寫技術代碼的時候,可以知道什么時候,實現(xiàn)什么方法,同樣也為我們后續(xù)的源碼分析研究打下基礎
