最初接觸java的接口服務是servlet,最基礎要掌握的就是servlet的生命週期。如今都是基於springboot開發後臺接口,spring框架的複雜度遠遠高於原始的servlet,弄清楚spring中bean的生命週期,有利於咱們對其框架的熟練掌握。java
springboot的啓動類中,都會執行SpringApplication.run
方法。在建立上下文環境以後,最核心的方法就是refreshContext
,對上下文環境進行初始化操做,本段就着重說明這一過程。spring
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { /** * 準備環境 * 1. 記錄容器的啓動時間startupDate,標記容器爲激活 * 2. 初始化上下文環境如文件路徑信息 * 3. 驗證必填屬性是否填寫 */ prepareRefresh(); /** * 告訴子類去刷新beanFactory * 這步完成後配置文件就解析成一個個beanDefination,註冊到BeanFactory(可是未被初始化,僅將信息寫到了beanDefination的map中) */ ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); /** * 設置beanFactory類加載器,添加多個beanPostProcesser */ prepareBeanFactory(beanFactory); try { /** * 容許子類上下文中對beanFactory作後期處理 */ postProcessBeanFactory(beanFactory); /** * 執行 context 中註冊的 BeanFactoryPostProcessor中的postProcessBeanFactory() 方法 * 1. BeanFactoryPostProcessor 是 bean 屬性處理容器。即管理 bean工廠中的BeanDefinition * 2. BeanDefinition在 spring mvc中就是xml文件中對應的bean標籤(注意,是標籤,而不是真實的 java bean) */ invokeBeanFactoryPostProcessors(beanFactory); /** * 註冊 BeanPostProcessor 的實現類 * 1. BeanPostProcessor接口包含兩個方法:postProcessBeforeInitialization 和 postProcessAfterInitialization * 2. 這裏只是註冊,兩個方法實際分別在 Bean初始化以前和初始化以後獲得執行 */ registerBeanPostProcessors(beanFactory); /** * 初始化ApplicationContext的MessageSource,MessageSource是國際化相關的接口 */ initMessageSource(); /** * 初始化ApplicationContext事件廣播器 */ initApplicationEventMulticaster(); // 初始化子類特殊bean(鉤子方法) onRefresh(); /** * 註冊事件監聽器 */ registerListeners(); /** * 初始化全部的單例java bean(不包含懶加載的類) */ finishBeanFactoryInitialization(beanFactory); /** * 廣播事件,ApplicationContext初始化完成 */ finishRefresh(); } catch (BeansException ex) { .................... } } }
BeanDefinition 是 spring bean 的建模對象,即把一個bean實例化出來的模型對象。有人會問把一個bean實例化出來有Class就好了啊,Class也就是咱們一般說的類對象,就是一個普通對象的建模對象,那麼爲何spring不能用Class來創建bean呢?很簡單,由於Class沒法完成bean的抽象,好比bean的做用域,bean的注入模型,bean是不是懶加載等等信息,Class是沒法抽象出來的,故而須要一個BeanDefinition類來抽象這些信息,以便於spring可以完美的實例化一個bean。緩存
spring掃描到某個bean的類時,除了要存儲類名、構造器等Class的基礎信息之外,還要存儲scope,lazy,dependsOn
等spring的屬性。BeanDefintion是一個類,專門用來存儲上述bean中的各類屬性。所以當spring掃描到一個符合規則的類時,首先是實例化一個BeanDefinition的對象,而且把根據類的類名生成一個bean的名字,繼而以beanName爲key,BeanDefinition對象爲value,存放在一個map中。springboot
值得注意的是,這裏都是講在掃描bean後,BeanDefinition的實例化,以及放入BeanDefinition的map中。尚未講到Bean的實例化和裝載。mybatis
BeanDefinition 的屬性方法以下:mvc
getBeanClassName
: 返回當前bean definition定義的類名getConstructorArgumentValues
:返回bean的構造函數參數getDependsOn
:返回當前bean所依賴的其餘bean的名稱getFactoryBeanName
: 返回factory bean的名稱getFactoryMethodName
: 返回工廠方法的名稱getOriginatingBeanDefinition
: 返回原始的BeanDefinition,若是不存在返回nullgetParentName
: 返回當前bean definition的父definition的名字getPropertyValues
: 返回一個用於新的bean實例上的屬性值getScope
: 返回當前bean的目標範圍isAbstract
: 當前bean是不是abstract,意味着不能被實例化isLazyInit
: bean是不是延遲初始化isPrimary
: bean是否爲自動裝配的主要候選beanisPrototype
: bean是不是多實例isSingleton
: bean是不是單例setAutowiredCandidate
(boolean): 設置bean是否對其餘bean是自動裝配的候選beansetBeanClassName
(String): 指定bean definition的類名setDependsOn
(String ...): 設置當前bean初始化所依賴的beans的名稱setFactoryBeanName
(String): 若是factory bean的名稱setFactoryMethodName
(String): 設置工廠的方法名setLazyInit
(boolean lazyInit): 設置是否延遲初始化setParentName
(String): 設置父definition的名稱setPrimary
(boolean): 設置是否主要的候選beansetScope
(String): 設置bean的範圍,如:單例,多實例BeanFactoryPostProcessor是實現spring容器功能擴展的重要接口,例如修改BeanDefinition,實現bean動態代理等。不少框架都是經過此接口實現對spring容器的擴展,例如mybatis與spring集成時,只定義了mapper接口,無實現類,接口也沒有添加@Component等註解,但spring卻能夠完成自動注入,也是基於BeanFactoryPostProcessor接口來實現的。app
BeanFactoryPostProcessor.java框架
@FunctionalInterface public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException; }
前文說到BeanDefinition在實例化以後,被放入BeanDefinition map中,而BeanFactoryPostProcessor就是在BeanDefinition map初始化完成後,Bean實例構造方法執行以前
執行的。ide
BeanFactoryPostProcessor的主要做用是,開發者能夠修改容器中全部BeanDefinition的信息
,接口方法的入參是ConfigurrableListableBeanFactory,使用該參數,能夠獲取到相關bean的定義信息。但 絕對不容許進行bean實例化相關的操做!
由於中spring加載機制中,BeanFactoryPostProcessor是在Bean構造方法以前執行的,若是這個時候提早實例化bean,極可能會一連串的問題。函數
如:在接口用經過configurableListableBeanFactory.getBean(「user」),獲取User類的bean,實際上即實例化了User的bean。會致使在後續其餘節點代碼中,沒法注入User的bean實例。
若是說BeanFactoryPostProcessor是對BeanDefinition的擴展處理,那麼BeanPostProcessor更多的是對Bean的擴展處理。BeanPostProcessor的觸發時間是在 Bean的實例化以後(執行了構造方法,而且對屬性進行了賦值),在Bean的init方法執行以前(@PostConstruct註解方法、InitializeBean接口方法、@Bean中initMethod方法)
。
BeanPostProcessor.java
public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
BeanPostProcessor接口中定義兩個方法,根據名字能夠推測,postProcessBeforeInitialization在Bean的init方法以前執行,postProcessAfterInitialization在Bean的init方法以後執行。這點很好的體現了spring的AOP思想,能夠理解爲BeanPostProcessor是對Bean的init方法執行先後,作了一層切面攔截。
有一個實現Spring aop 的BeanPostProcessor 叫 AnnotationAwareAspectJAutoProxyCreator。在postProcessBeforeInitialization或者postProcessAfterInitialization方法中,對對象進行判斷,看他需不須要織入切面邏輯,若是須要,那我就根據這個對象,生成一個代理對象,而後返回這個代理對象,那麼最終注入容器的,天然就是代理對象了。
該方法會實例化全部剩餘的非懶加載單例 bean。值得注意的是「全部剩餘的」
,就是有一些特殊的bean,這該方法以前就已經加載了,如:
其餘的非懶加載單例 bean 都會在這個方法中被實例化,而且 BeanPostProcessor 的觸發也是在這個方法中。
基於spring的refresh過程,咱們把關於bean的部分拎出來,就造成了下面的bean的加載過程:
BeanDefinition
的對象,放入beanDefinitionMap中。BeanFactoryPostProcessor
接口的就是一種特殊bean,在beanDefinitionMap加載後觸發,能夠自定義實現類,對其中的BeanDefinition進行修改。construct
過程。BeanFactory 執行getBean方法生產其餘的普通bean(調用類的構造方法,或FactoryBean的getObject方法,以及@Bean註解的方法)。populate
過程。設置bean的依賴關係(基於屬性注入)以及屬性值。BeanPostProcessor
接口的類,執行接口中的postProcessBeforeInitialization 方法。initialze
過程。執行bean的各類初始化方法,initialze方法的優先級以下:(1)@PostConstruct指定的方法 -> (2)InitializingBean接口的afterPropertiesSet()方法 -> (3)@Bean中initMethod指定的方法
。BeanPostProcessor
接口的類,執行接口中的postProcessAfterInitialization 方法。destroy
過程,容器銷燬,執行bean的各類銷燬方法,destroy方法的優先級以下:(1)@PostDestroy指定的方法 -> (2)DisposableBean接口的destroy()方法 -> (3)@Bean中destroyMethod指定的方法
。在spring bean生命週期中,網上有人用Bean的「初始化」、「實例化」等名字,很容易搞混,因此我使用了下列幾個英文單詞,感受更能表達這些過程:
其實並不是只有在populate
時纔會注入依賴,仍是要取決於屬性的注入方式:基於屬性注入、setter注入和構造器注入等。若是是基於構造器注入,在construct
過程當中,就會導入依賴。
另外咱們中使用@Value、@ConfigurationProperties等註解賦值,也是屬於populate
過程的操做。
對於上述關於bean生命週期的介紹,咱們寫個demo,一一實現相關的方法,親眼看看他們的加載過程。
@Slf4j @Component public class BeanFactoryPostProcessorImpl implements BeanFactoryPostProcessor { /** * getBean 是獲取Object對象,getBeanDefinition 是獲取Class類 * 能夠修改BeanDefinition * 但getBean方法不要用,會致使提早加載bean,bean實例化紊亂 * @param beanFactory */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { log.warn("實現 BeanFactoryPostProcessor 接口:開始了!"); Arrays.stream(beanFactory.getBeanDefinitionNames()) .filter(beanName -> User.USER_BEAN_NAME.equals(beanName)) .forEach(beanName -> { BeanDefinition beanDefinition=beanFactory.getBeanDefinition(beanName); beanDefinition.getPropertyValues().add("name","Kerry"); log.warn("BeanFactoryPostProcessor:Bean name is " + beanName); }); } }
主要是對 BeanDefinitionName 的修改,這裏將對象的屬性name的值設置爲Kerry。
@Slf4j @Component public class BeanPostProcessorImpl implements BeanPostProcessor { /** * Bean 初始化方法 執行前 調用 * @param bean * @param beanName * @return * @throws BeansException */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(User.USER_BEAN_NAME.equals(beanName)) { log.warn("BeanPostProcessor-name:"+((User)bean).getName()); log.warn("實現 BeanPostProcessor 接口:postProcessBeforeInitialization(Object bean, String beanName),beanName=" + beanName); } return bean; } /** * Bean 初始化方法 執行後 調用 * @param bean * @param beanName * @return * @throws BeansException */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(User.USER_BEAN_NAME.equals(beanName)) { log.warn("實現 BeanPostProcessor 接口:postProcessAfterInitialization(Object bean, String beanName),beanName=" + beanName); } return bean; } }
初始化和銷燬兩種方法每每是配套的,有下面三種,而且按照下列順序執行:
咱們在User類中定義了這些初始化和銷燬方法,因爲還要測試依賴注入順序,也定義了Type類的方法。
User.java
@Slf4j public class User implements InitializingBean, DisposableBean { public final static String USER_BEAN_NAME="user"; //配置文件中,注入的值爲 demoName @Value("${params.user.name}") private String name; private Integer age=1; @Autowired private Type type; @Override public String toString(){ return "My name is "+name+",I'm "+age+"years old."; } /** * 構造方法 * 一、默認構造方法 * 二、重載構造方法 */ public User(){ log.warn("構造方法:public User()"); } /** * 初始化 * 一、註解:@PostConstruct 的方法 * 二、實現 InitializeBean 接口:afterPropertiesSet() * 三、@Bean 中指定的 initMethod */ @PostConstruct public void postConstruct(){ log.warn("註解:@PostConstruct 的方法"); } @Override public void afterPropertiesSet(){ log.warn("實現 InitializeBean 接口:afterPropertiesSet()"); } public void initMethod(){ log.warn("@Bean 中指定的 initMethod "); } /** * 銷燬 * 一、註解:@PreDestroy 的方法 * 二、實現 DisposableBean 接口:destroy() * 三、@Bean 中指定的 destroyMethod */ @PreDestroy public void preDestroy(){ log.warn("註解:@PreDestroy 的方法"); } @Override public void destroy(){ log.warn("實現 DisposableBean 接口:destroy()"); } public void destroyMethod(){ log.warn("@Bean 中指定的 destroyMethod"); } public void setName(String name) { log.warn("User.setName方法:"+name); this.name = name; } }
Type.java
@Component @Data @Slf4j public class Type implements InitializingBean { private String typeCode; public Type(){ log.warn("構造方法:public Type()"); } @Override public void afterPropertiesSet(){ log.warn("Type:實現 InitializeBean 接口:afterPropertiesSet()"); } }
BeanConfig.java
@Configuration public class BeanConfig { @Bean(initMethod = "initMethod",destroyMethod = "destroyMethod") public User user(){ return new User(); } }
還記得咱們在BeanFactoryPostProcessorImpl中修改了name的值嗎?咱們先把修改的代碼註釋掉,執行以後的日誌以下,的確按照前面的Bean生命週期加載的:
p.k.e.s.c.BeanFactoryPostProcessorImpl : 實現 BeanFactoryPostProcessor 接口:開始了! p.k.e.s.c.BeanFactoryPostProcessorImpl : BeanFactoryPostProcessor:Bean name is user p.k.exercise.springexercise.pojo.User : 構造方法:public User() p.k.exercise.springexercise.pojo.Type : 構造方法:public Type() p.k.exercise.springexercise.pojo.Type : Type:實現 InitializeBean 接口:afterPropertiesSet() p.k.e.s.config.BeanPostProcessorImpl : BeanPostProcessor-name:demoName p.k.e.s.config.BeanPostProcessorImpl : 實現 BeanPostProcessor 接口:postProcessBeforeInitialization(Object bean, String beanName),beanName=user p.k.exercise.springexercise.pojo.User : 註解:@PostConstruct 的方法 p.k.exercise.springexercise.pojo.User : 實現 InitializeBean 接口:afterPropertiesSet() p.k.exercise.springexercise.pojo.User : @Bean 中指定的 initMethod p.k.e.s.config.BeanPostProcessorImpl : 實現 BeanPostProcessor 接口:postProcessAfterInitialization(Object bean, String beanName),beanName=user p.k.exercise.springexercise.pojo.User : 註解:@PreDestroy 的方法 p.k.exercise.springexercise.pojo.User : 實現 DisposableBean 接口:destroy() p.k.exercise.springexercise.pojo.User : @Bean 中指定的 destroyMethod
如今把BeanFactoryPostProcessorImpl中的註釋放開,日誌變了:
p.k.e.s.c.BeanFactoryPostProcessorImpl : 實現 BeanFactoryPostProcessor 接口:開始了! p.k.e.s.c.BeanFactoryPostProcessorImpl : BeanFactoryPostProcessor:Bean name is user p.k.exercise.springexercise.pojo.User : 構造方法:public User() p.k.exercise.springexercise.pojo.Type : 構造方法:public Type() p.k.exercise.springexercise.pojo.Type : Type:實現 InitializeBean 接口:afterPropertiesSet() p.k.exercise.springexercise.pojo.User : User.setName方法:Kerry p.k.e.s.config.BeanPostProcessorImpl : BeanPostProcessor-name:Kerry p.k.e.s.config.BeanPostProcessorImpl : 實現 BeanPostProcessor 接口:postProcessBeforeInitialization(Object bean, String beanName),beanName=user p.k.exercise.springexercise.pojo.User : 註解:@PostConstruct 的方法 p.k.exercise.springexercise.pojo.User : 實現 InitializeBean 接口:afterPropertiesSet() p.k.exercise.springexercise.pojo.User : @Bean 中指定的 initMethod p.k.e.s.config.BeanPostProcessorImpl : 實現 BeanPostProcessor 接口:postProcessAfterInitialization(Object bean, String beanName),beanName=user p.k.exercise.springexercise.pojo.User : 註解:@PreDestroy 的方法 p.k.exercise.springexercise.pojo.User : 實現 DisposableBean 接口:destroy() p.k.exercise.springexercise.pojo.User : @Bean 中指定的 destroyMethod
能夠看到若是咱們在BeanFactoryPostProcessor接口中經過BeanDefinition 的PropertyValue 設置屬性值,其實只是修改了該屬性的setter方法,而真正執行該方法,仍是在populate
階段,而非BeanFactoryPostProcessor執行階段。