­

淺嘗Spring註解開發_Bean生命周期及執行過程

Spring註解開發

淺嘗Spring註解開發,基於Spring 4.3.12
包含Bean生命周期、自定義初始化方法、Debug BeanPostProcessor執行過程及在Spring底層中的應用

淺嘗Spring註解開發_自定義註冊組件、屬性賦值、自動裝配
淺嘗Spring註解開發_Bean生命周期及執行過程

Bean生命周期

了解Bean的生命周期,就可以在Bean聲明周期的不同階段進行自定義的操作,滿足更複雜的需求。簡單的將Bean生命周期分為三個階段:Bean創建、初始化、銷毀

  • 對象創建:單實例在容器啟動的時候創建對象,多實例在每次獲取的時候創建對象
    • 初始化之前:BeanPostProcessor.postProcessBeforeInitialization()
  • 初始化:對象創建完成,並賦值好,調用初始化方法
    • 初始化之後:BeanPostProcessor.postProcessAfterInitialization()
  • [容器創建完成]
  • 銷毀:單實例在容器關閉的時候銷毀,多實例容器不會管理這個bean,容器不會調用銷毀方法

現在可以通過下面方法在初始化和銷毀時自定義初始化方法來干涉Bean創建過程。

  1. @Bean()註解參數
  2. InitializingBean、DisposableBean接口
  3. @PostConstruct、@PreDestroy註解
  4. BeanPostProcessor接口

1.@Bean生命周期

通過@Bean指定init-method和destroy-method的初始化方法

  • 先自定義Bean初始化和銷毀方法

    @Component
    public class Car {
    	
    	public Car(){
    		System.out.println("car constructor...");
    	}
    	//現在只是普通方法
    	public void init(){
    		System.out.println("car ... init...");
    	}
    	//現在只是普通方法
    	public void detory(){
    		System.out.println("car ... destory...");
    	}
    
    }
    
  • 配置進容器

    • 通過@Bean註解,在@Bean註冊進容器時指定自定義方法
    @Configuration
    public class MainConfigOfLifeCycle {
    	
    	//@Scope("prototype")多實例,不管銷毀
    	//指定用於初始化和銷毀的方法
    	@Bean(initMethod="init",destroyMethod="destory")
    	public Car car(){
    		return new Car();
    	}
    
    }
    
  • 測試

    public class IOCTest_LifeCycle {
    	
    	@Test
    	public void test01(){
    		//1、創建ioc容器
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    		System.out.println("容器創建完成...");
    		
    		//applicationContext.getBean("car");
    		//關閉容器
    		applicationContext.close();
    	}
    
    }
    

    輸出

    //先創建對象
    car constructor...
    //再自定義初始化方法
    car ... init...
    //創建完成
    容器創建完成...
    //關閉時自定義銷毀方法
    car ... destory...
    

2.InitializingBean,DisposableBean生命周期

接口,需實現,通過讓Bean實現InitializingBean(定義初始化邏輯),DisposableBean(定義銷毀邏輯);

  • 實現接口,自定義初始化Bean

    public class Cat implements InitializingBean,DisposableBean {
    	
    	public Cat(){
    		System.out.println("cat constructor...");
    	}
    
    	//定義銷毀邏輯
    	@Override
    	public void destroy() throws Exception {
    		// TODO Auto-generated method stub
    		System.out.println("cat...destroy...");
    	}
    
    	//定義初始化邏輯
    	@Override
    	public void afterPropertiesSet() throws Exception {
    		// TODO Auto-generated method stub
    		System.out.println("cat...afterPropertiesSet...");
    	}
    
    }
    
  • 配置進容器

    • 在@Configuration配置類中使用@Bean
    • 或在Bean類上使用@Component然後再配置類上使用@ComponentScan
    //配置組件
    @Component
    public class Cat implements InitializingBean,DisposableBean {
    	//...
    }
    
    //掃描進容器
    @ComponentScan("com.xxx.bean")
    @Configuration
    public class MainConfigOfLifeCycle {
    	//...
    }
    
  • 測試

    public class IOCTest_LifeCycle {
    	
    	@Test
    	public void test01(){
    		//1、創建ioc容器
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    		System.out.println("容器創建完成...");
    		
    		//applicationContext.getBean("car");
    		//關閉容器
    		applicationContext.close();
    	}
    }
    

    輸出

    //注意順序,每個Bean先構造並初始化,然後才進行下一個Bean,關閉時從內向外
    (貓)cat constructor...
    (貓)cat...afterPropertiesSet...
    (車)car constructor...
    (車)car ... init...
    //創建完成
     容器創建完成...
    //關閉時銷毀
    (車)car ... destory...
    (貓)cat...destroy...
    

3.@PostConstruct生命周期

可以使用JSR250;

  • @PostConstruct:在bean創建完成並且屬性賦值完成之後,來執行初始化方法

  • @PreDestroy:在容器銷毀bean之前通知我們進行清理工作

  • 標註註解,自定義初始化Bean

    public class Dog {
    
    	public Dog(){
    		System.out.println("dog constructor...");
    	}
    	
    	//對象創建並賦值之後調用
    	@PostConstruct
    	public void init(){
    		System.out.println("Dog....@PostConstruct...");
    	}
    	
    	//容器移除對象之前
    	@PreDestroy
    	public void detory(){
    		System.out.println("Dog....@PreDestroy...");
    	}
    }
    
  • 配置進容器

    • 在@Configuration配置類中使用@Bean
    • 或在Bean類上使用@Component然後再配置類上使用@ComponentScan
    @Component
    public class Dog {
    	//...
    }
    
    //掃描進容器
    @ComponentScan("com.xxx.bean")
    @Configuration
    public class MainConfigOfLifeCycle {
    	//...
    }
    
  • 測試

    public class IOCTest_LifeCycle {
    	
    	@Test
    	public void test01(){
    		//1、創建ioc容器
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    		System.out.println("容器創建完成...");
    		
    		//applicationContext.getBean("car");
    		//關閉容器
    		applicationContext.close();
    	}
    
    }
    

    輸出

    //注意順序,每個Bean先構造並初始化,然後才進行下一個Bean,關閉時從內向外
    (貓)cat constructor...
    (貓)cat...afterPropertiesSet...
    (狗)dog constructor...
    (狗)Dog....@PostConstruct...
    (車)car constructor...
    (車)car ... init...
    //創建完成
    容器創建完成...
    //關閉時銷毀
    (車)car ... destory...
    (狗)Dog....@PreDestroy...
    (貓)cat...destroy...
    

4.BeanPostProcessor

postProcessBeforeInitialization:在創建Bean實例之後,在自定義初始化之前進行調用

postProcessAfterInitialization:在自定義初始化之後進行調用

BeanPostProcessor接口:bean的後置處理器,需實現,在bean初始化前後進行一些處理工作

  • postProcessBeforeInitialization:(自定義初始化,如InitializingBean[afterPropertiesSet]、init-method等,就是上面那些自定義初始化方法)初始化之前工作(創建Bean實例之後,在自定義初始化之前)

  • postProcessAfterInitialization:在(自定義)初始化之後工作

  • 實現後置處理器接口

    public class MyBeanPostProcessor implements BeanPostProcessor {
    
    	//初始化前置方法
    	//bean:新創建的實例,還未初始化
    	//beanName:未初始化的Bean名字
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		// TODO Auto-generated method stub
    		System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
    		return bean;
    	}
    	//初始化後置方法
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		// TODO Auto-generated method stub
    		System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
    		return bean;
    	}
        
    }
    
  • 配置進容器

    • 在@Configuration配置類中使用@Bean
    • 或在Bean類上使用@Component然後再配置類上使用@ComponentScan
    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        //...
    }
    
    //掃描進容器
    @ComponentScan("com.xxx.bean")
    @Configuration
    public class MainConfigOfLifeCycle {
    	//...
    }
    
  • 測試

    • 這次沒有新增的Bean,只配置了一個後置處理器,
    • 這個後置處理器會對容器中的Bean起作用,包括上面三種自定義初始化Bean
    public class IOCTest_LifeCycle {
    	
    	@Test
    	public void test01(){
    		//1、創建ioc容器
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    		System.out.println("容器創建完成...");
    		
    		//applicationContext.getBean("car");
    		//關閉容器
    		applicationContext.close();
    	}
    
    }
    

    輸出

    //對於每一個Bean都要執行一遍
    //1.創建
    //2.BeanPostProcessor.postProcessBeforeInitialization()
    //3.初始化:對象創建完成,並賦值好,調用初始化方法...
    //4.BeanPostProcessor.postProcessAfterInitialization()
    //5.銷毀
    
    
    //以其中一個Bean為例:
    //構造對象
    cat constructor...
    //初始化之前
    postProcessBeforeInitialization...cat=>com.xxx.bean.Cat@7d68ef40
    //使用InitializingBean自定義初始化邏輯
    cat...afterPropertiesSet...
    //初始化之後
    postProcessAfterInitialization...cat=>com.xxx.bean.Cat@7d68ef40
    //創建完成
    容器創建完成...
    //關閉時銷毀
    cat ... destroy...
    

⭐BeanPostProcessor原理

bean賦值,注入其他組件,@Autowired,生命周期註解功能,@Async,xxxBeanPostProcessor都通過BeanPostProcessor實現

詳細視頻 //www.bilibili.com/video/BV1gW411W7wy?p=16

主要方法

populateBean(beanName, mbd, instanceWrapper):給bean進行屬性賦值
initializeBean:初始化Bean
{
    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);初始化前應用後置處理器
    invokeInitMethods(beanName, wrappedBean, mbd);執行自定義初始化
    applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);初始化後應用後置處理器
}
遍歷得到容器中所有的BeanPostProcessor;挨個執行beforeInitialization,
一但返回null,跳出for循環

執行過程

了解BeanPostProcessor的執行過程,從AnnotationConfigApplicationContext開始Debug

public class IOCTest_LifeCycle {
	
	@Test
	public void test01(){
		//1、創建ioc容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
		System.out.println("容器創建完成...");
		
		//applicationContext.getBean("car");
		//關閉容器
		applicationContext.close();
	}
}
  1. 先從創建ioc容器開始,進入AnnotationConfigApplicationContext()構造方法,執行裏面的refresh()方法刷新容器
    1. refresh()方法裏面有一個finishBeanFactoryInitialization(beanFactory)初始化所有剩餘的單實例對象,進入這個方法
  2. 這個方法最後一步有一個beanFactory.preInstantiateSingletons()初始化所有單實例Bean,進入這個方法
    1. 觸發所有非惰性單例bean的初始化
    2. 裏面調用getBean(beanName)
    3. 進入getBean(beanName)裏面再調用doGetBean(name,null,null,false)
    4. 進入doGetBean(name,null,null,false)裏面有getSingleton(beanName,new ObjectFactory(){singletonFactory.getObject()})通過匿名內部類調用getObject()
  3. 此時通過匿名類getObject()進入下一個調用棧AbstractBeanFactory$1.getObject(),如果是單例,調用createBean(beanName,mbd,args)
  4. 進入createBean(beanName,mbd,args)調用doCreateBean(beanName,mbd,args)創建一個實例,過程如下
    1. 進入doCreateBean(beanName,mbd,args),裏面調用一個initializeBean(beanName,exposedObject,mbd)初始化方法,這個方法裏面就是調用的後置處理器
    2. 在這個方法上面有populateBean(beanName,mbd,instanceWrapper)方法,這個方法為Bean屬性賦值
    3. 進入initializeBean(beanName,exposedObject,mbd),下面有一個invokeInitMethods(beanName,wrappedBean,mbd)執行初始化方法(就是上面的自定義初始化InitializingBean[afterPropertiesSet]、init-method)
    4. invokeInitMethods(beanName,wrappedBean,mbd)[在初始化之前應用 BeanPost 處理器]上面有一個applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)下面有一個applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName)[在初始化之後應用 BeanPost 處理器],作用是在初始化之前應用所有的BeanPostProcessors在初始化之後應用所有的BeanPostProcessors
  5. 進入applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)
    1. 裏面有getBeanPostProcessors()找到所有BeanPostProcessors遍歷,包括Spring系統的BeanPostProcessorApplicationContextAwareProcessorConfigurationClassPostProcessor等,然後才是自定義的MyBeanPostProcessor,依次執行beanProcessor.postProcessBeforeInitialization()
    2. 如果有執行返回null,就結束遍歷,返回null,後面的處理器就不執行了(不應用後續的BeanPostProcessors了)

調用棧

  • 獲取單例

    image

  • 創建實例Bean

    image

  • 給Bean屬性賦值和初始化Bean

    image

完整流程

Spring底層對 BeanPostProcessor 的使用;

image

  1. 由上圖可以看到,Spring中的BeanPostProcessor在實例化過程處於的位置,BeanPostProcessor接口有兩個方法需要實現:postProcessBeforeInitialization和postProcessAfterInitialization
  2. 前者在實例化及依賴注入完成後、在任何初始化代碼(比如配置文件中的init-method)調用之前調用;後者在初始化代碼調用之後調用。

⭐BeanPostProcessor在Spring底層的使用

許多註解底層都是基於BeanPostProcessor

BeanPostProcessor接口實現類

image

向組件中注入IoC容器

在Bean創建過程中,初始化之前,判斷是否實現了某Aware接口,如果實現了,就向Bean中注入ApplicationContext容器

  • 向Bean中注入IoC容器

    • 實現ApplicationContextAware接口,聲明屬性,賦值,就可以在組件中使用Ioc容器

      @Component
      public class Dog implements ApplicationContextAware {
      	
      	//聲明IoC容器
      	private ApplicationContext applicationContext;
      	
      	public Dog(){
      		System.out.println("dog constructor...");
      	}
      	
      	//對象創建並賦值之後調用
      	@PostConstruct
      	public void init(){
      		System.out.println("Dog....@PostConstruct...");
      	}
      	
      	//容器移除對象之前
      	@PreDestroy
      	public void detory(){
      		System.out.println("Dog....@PreDestroy...");
      	}
      
      	//把applicationContext IoC容器賦值給屬性
      	@Override
      	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      		// TODO Auto-generated method stub
      		this.applicationContext = applicationContext;
      	}
      }
      
  • 原理是通過ApplicationContextAwareProcessor實現

    • ApplicationContextAwareProcessor實現了BeanPostProcessor接口

      image

    • postProcessBeforeInitialization()方法中

      1. 在Bean初始化之前,判斷Bean是否實現了ApplicationContextAware接口,或其他Aware接口
      2. 如果實現了,就調用invokeAwareInterfaces(bean)給Bean注入值
      3. 判斷Bean是什麼類型Aware,將Bean轉成對應類型調用((ApplicationContextAware)bean).setApplicationContext(this.applicationContext)注入IoC容器
      4. 於是就到了上面實現的接口的未實現方法中

數據校驗

  • BeanValidationPostProcessor也實現了BeanPostProcessor接口
  • 在Bean創建完賦值後,同樣調用postProcessBeforeInitialization()方法,進行數據校驗
    • postProcessBeforeInitialization(){doValidate(bean)}
    • postProcessAfterInitialization(){doValidate(bean)}

自定義初始化註解

  • Bean初始化有一種方法是使用@PostConstruct註解,也是通過BeanPostProcessor實現
  • InitDestroyAnnotationBeanPostProcessor處理@PostConstruct@PreDestroy註解
    • postProcessBeforeInitialization()中找到Bean的生命周期註解所標註的方法,如initMethods、destroyMethods
    • 找到之後就執行註解標註的初始化方法metatata.invokeInitMethods(bean,beanName)element.invoke(target),利用反射執行。

自動注入註解@Autowired

  • 為什麼@Autowired能夠自動注入值,是通過這個AutowiredAnnotationBeanPostProcessor實現BeanPostProcessors接口
  • 在對象創建完之後,處理標註@Autowired標註的所有屬性進行注入值
Tags: