zoukankan      html  css  js  c++  java
  • spring bean 生命周期

    生命周期图解

    由于Bean的生命周期经历的阶段比较多,我们将通过一个图形化的方式进行描述。下图描述了BeanFactory中Bean生命周期的完整过程:
     
    Bean 的生命周期从Spring容器着手实例化Bean开始,直到最终销毁Bean,这当中经过了许多关键点,每个关键点都涉及特定方法的调用,可以将这些方法大致划分为3类:
        (1)Bean自身的方法:如调用Bean构造函数,实例化Bean,,调用Setter设置Bean的属性值以及通过<bean>的init-method和destroy-method所指定的方法;
        (2)Bean级生命周期接口方法:如BeanNameAware、BeanFactoryAware、InitializationBean和DisposableBean,这些接口方法由Bean类直接实现;
        (3)容器级生命周期接口方法:如上图中的红色部分所示,由InstantiationAwareBeanPostProcessor和BeanPostProcessor这连个接口实现,一般称他们的实现类为”后处理器“。后处理器接口,一般不由Bean本身实现,他们独立于Bean,实现类以容器附加装置的形式注册到Spring容器中,并通过接口反射为Spring容器预先识别。当Spring容器创建任何Bean的时候,这些后处理器都会发生作用,所以这些后处理器的影响是全局性的。当然,用户可以通过合理的编写后处理器,让其仅对感兴趣的Bean进行加工处理.
     
    InstantiationAwareBeanPostProcessor其实是BeanPostProcessor接口的子接口,在Spring 1.2中定义,在Spring2.0中为其提供了一个适配器类InstantiationAwareBeanPostProcessorAdapter,一般情况下,可以方便的扩展改适配器覆盖感兴趣的方法以定义实现类。下面我们通过一个具体的实例以更好的理解Bean生命周期的各个步骤.
     

    窥探Bean生命周期的实例

    实现各种生命周期控制访问的Car
    [java] view plain copy
     
    1. package com.spring.beanfactory;  
    2.   
    3. import org.springframework.beans.BeansException;  
    4. import org.springframework.beans.factory.BeanFactory;  
    5. import org.springframework.beans.factory.BeanFactoryAware;  
    6. import org.springframework.beans.factory.BeanNameAware;  
    7. import org.springframework.beans.factory.DisposableBean;  
    8. import org.springframework.beans.factory.InitializingBean;  
    9.   
    10. public class Car implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean{  
    11.     private String brand;  
    12.     private String color;  
    13.     private int maxSpeed;  
    14.     private BeanFactory beanFactory;  
    15.     private String beanName;  
    16.       
    17.     public String getColor() {  
    18.         return color;  
    19.     }  
    20.   
    21.     public void setColor(String color) {  
    22.         this.color = color;  
    23.     }  
    24.   
    25.     public int getMaxSpeed() {  
    26.         return maxSpeed;  
    27.     }  
    28.   
    29.     public void setMaxSpeed(int maxSpeed) {  
    30.         this.maxSpeed = maxSpeed;  
    31.     }  
    32.   
    33.     public String getBrand() {  
    34.         return brand;  
    35.     }  
    36.   
    37.     public BeanFactory getBeanFactory() {  
    38.         return beanFactory;  
    39.     }  
    40.   
    41.     public String getBeanName() {  
    42.         return beanName;  
    43.     }  
    44.   
    45.     //1、管理Bean生命周期的接口  
    46.     public Car(){  
    47.         System.out.println("调用Car构造函数");  
    48.     }  
    49.       
    50.     public void setBrand(String brand) {  
    51.         System.out.println("调用setBrand()设置属性");  
    52.         this.brand = brand;  
    53.     }  
    54.   
    55.    public void introduce(){  
    56.        System.out.println("bradn:"+brand+";color"+color+"; maxSpeed:"+maxSpeed);  
    57.    }  
    58.      
    59.    //2、BeanFactoryAware接口方法  
    60.     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {  
    61.         System.out.println("调用BeanFactoryAware.setBeanFactory()");  
    62.         this.beanFactory=beanFactory;  
    63.     }  
    64.        
    65.     //3、BeanNameAware接口方法  
    66.     public void setBeanName(String beanName) {  
    67.         System.out.println("调用BeanNameAware.setBeanName()");  
    68.         this.beanName=beanName;  
    69.     }  
    70.       
    71.       
    72.     //4 nitializingBean接口方法  
    73.     public void afterPropertiesSet() throws Exception {  
    74.         System.out.println("调用InitializingBean.afterPropertiesSet()");  
    75.     }  
    76.       
    77.     // 5  DisposableBean接口方法  
    78.     public void destroy() throws Exception {  
    79.         System.out.println("调用DisposableBean.destroy()");  
    80.     }  
    81.       
    82.     // 6  通过<bean>的init-method属性指定的初始化方法  
    83.     public void myInit(){  
    84.         System.out.println("调用inti-method所指定的myInit(),将maxSpeed设置为240.");  
    85.         this.maxSpeed=240;  
    86.     }  
    87.       
    88.     //7  通过<bean>的destory-method属性指定的销毁方法  
    89.     public void myDestory(){  
    90.         System.out.println("调用destory-method所指定的myDestory()方法。");  
    91.     }  
    92. }  
    InstantiationAwareBeanPostProcessor实现类
    [java] view plain copy
     
    1. package com.spring.beanfactory;  
    2.   
    3. import java.beans.PropertyDescriptor;  
    4.   
    5. import org.springframework.beans.BeansException;  
    6. import org.springframework.beans.PropertyValues;  
    7. import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;  
    8.   
    9. @SuppressWarnings("unchecked")  
    10. public class MyInstantiationAwareBeanPostProcessor extends  
    11.         InstantiationAwareBeanPostProcessorAdapter {  
    12.       
    13.     //1 接口方法:实例化bean前进行调用  
    14.     public Object postProcessBeforeInstantiation(Class beanClass,String beanName) throws BeansException {  
    15.         //1-1仅对容器中的car-bean进行处理  
    16.            if("car".equals(beanName)){  
    17.               System.out.println("InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()");   
    18.            }  
    19.              
    20.         return null;  
    21.     }  
    22.       
    23.     //2 接口方法:在实例化bean后进行调用  
    24.     public boolean postProcessAfterInstantiation(Object bean, String beanName )  
    25.     throws BeansException{  
    26.            if("car".equals(beanName)){  
    27.                   System.out.println("InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()");   
    28.                }  
    29.         return true;  
    30.     }  
    31.       
    32.       
    33.     //3接口方法:在设置某个属性时调用  
    34.     public  PropertyValues postProcessPropertyValues(  
    35.             PropertyValues propertyvalues,  
    36.             PropertyDescriptor apropertydescriptor[], Object bean, String beanName)  
    37.             throws BeansException{  
    38.      //3-1仅对容器中car-bean进行处理,还可以通过post入参进行过滤,  
    39.         //仅对car的某个特定属性进行处理  
    40.                     if("car".equals(beanName)){  
    41.                       System.out.println("InstantiationAwareBeanPostProcessor.postProcessPropertyValues");    
    42.                     }  
    43.                 return propertyvalues;  
    44.             }  
    45. }  
    BeanPostProcessor实现类
    [java] view plain copy
     
    1. package com.spring.beanfactory;  
    2.   
    3. import org.springframework.beans.BeansException;  
    4. import org.springframework.beans.factory.config.BeanPostProcessor;  
    5.   
    6. public class MyBeanPostProcessor implements BeanPostProcessor {  
    7.   
    8.   
    9.     public Object postProcessBeforeInitialization(Object bean, String beanName)  
    10.             throws BeansException {  
    11.          if(beanName.equals("car")){  
    12.             Car car=(Car)bean;   
    13.             if(car.getColor()==null){  
    14.                 System.out.println("调用BeanPostProcessor.postProcessBeforeInitialization(),color为空,设置为默认黑色.");  
    15.                 car.setColor("黑色");  
    16.             }  
    17.          }  
    18.         return bean;  
    19.     }  
    20.       
    21.     public Object postProcessAfterInitialization(Object bean, String beanName)  
    22.     throws BeansException {  
    23.           
    24.          if(beanName.equals("car")){  
    25.              Car car=(Car)bean;  
    26.              if(car.getMaxSpeed()>=200){  
    27.                 System.out.println("调用BeanPostProcessor.postProcessAfterInitialization(),将maxSpedd调整为200.");   
    28.                 car.setMaxSpeed(200);  
    29.              }  
    30.          }  
    31.       return bean;  
    32. }  
    33.   
    34. }  
    在Spring配置文件中定义Car的配置信息
    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    4.        xmlns:p="http://www.springframework.org/schema/p"   
    5.        xsi:schemaLocation="http://www.springframework.org/schema/beans  
    6.            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
    7.   
    8.    <bean  id="car" class="com.spring.beanfactory.Car" init-method="myInit" destroy-method="myDestory"  
    9.        p:brand="红旗CA72"  
    10.        p:maxSpeed="300"  
    11.        scope="singleton"  
    12.    />  
    13.     
    14. </beans>  
    下面我们让容器装载配置文件,然后再分别注册上面所提供的两个后处理器:
    [java] view plain copy
     
    1. package com.spring.beanfactory;  
    2.   
    3. import org.springframework.beans.factory.BeanFactory;  
    4. import org.springframework.beans.factory.config.ConfigurableBeanFactory;  
    5. import org.springframework.beans.factory.xml.XmlBeanFactory;  
    6. import org.springframework.core.io.ClassPathResource;  
    7. import org.springframework.core.io.Resource;  
    8.   
    9. public class BeanLifeCycle {  
    10.       
    11.     private static void LifiCycleInBeanFactory(){  
    12.         // 1 下面两句装载配置文件,并启动容器  
    13.         Resource res=new  ClassPathResource("beans.xml");  
    14.         BeanFactory bf=new XmlBeanFactory(res);  
    15.           
    16.         // 2 向容器中注册MyBeanPostProcesser处理器  
    17.         ((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyBeanPostProcessor());  
    18.          //3 向容器中注册MyInstantiationAwareBeanPostProcessor后处理器  
    19.         ((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());  
    20.           
    21.           
    22.         //4 第一次从容器中获取car,将处罚容器实例化该Bean,这将引发Bean生命周期方法的调用  
    23.         Car car1=(Car)bf.getBean("car");  
    24.         car1.introduce();  
    25.         car1.setColor("红色");  
    26.           
    27.         // 5第二次从容器中获取car,直接从缓存池中取(因为 scope="singleton")  
    28.         Car car2=(Car)bf.getBean("car");  
    29.           
    30.         // 6 查看car1和car2是否指向同一引用  
    31.         System.out.println("car1==car2"+(car1==car2));  
    32.           
    33.         // 7 关闭容器  
    34.         ((XmlBeanFactory)bf).destroySingletons();  
    35.           
    36.     }  
    37.       
    38.     public static void main(String[] args) {  
    39.         LifiCycleInBeanFactory();  
    40.     }  
    41.   
    42. }  
    运行后,结果如下:
    [java] view plain copy
     
    1. 三月 27, 2014 11:16:39 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions  
    2. 信息: Loading XML bean definitions from class path resource [beans.xml]  
    3. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()  
    4. 调用Car构造函数  
    5. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()  
    6. InstantiationAwareBeanPostProcessor.postProcessPropertyValues  
    7. 调用setBrand()设置属性  
    8. 调用BeanNameAware.setBeanName()  
    9. 调用BeanFactoryAware.setBeanFactory()  
    10. 调用BeanPostProcessor.postProcessBeforeInitialization(),color为空,设置为默认黑色.  
    11. 调用InitializingBean.afterPropertiesSet()  
    12. 调用inti-method所指定的myInit(),将maxSpeed设置为240.  
    13. 调用BeanPostProcessor.postProcessAfterInitialization(),将maxSpedd调整为200.  
    14. bradn:红旗CA72;color黑色; maxSpeed:200  
    15. car1==car2true  
    16. 三月 27, 2014 11:16:39 上午 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons  
    17. 信息: Destroying singletons in org.springframework.beans.factory.xml.XmlBeanFactory@1ed7c33: defining beans [car]; root of factory hierarchy  
    18. 调用DisposableBean.destroy()  
    19. 调用destory-method所指定的myDestory()方法。  
    仔细观察输出的信息,将发现它验证了我们前面所介绍的生命周期的过程。在7处,我们通过destroySingletons()方法关闭容器,由于Car实现了销毁接口并指定了销毁方法,所以容器将触发调用这两个方法.
     

    ApplicationContext中Bean的生命周期

        Bean在应用上下文中的生命周期和在BeanFactory中生命周期类似,不同是,如果Bean实现了org.springframework.context.ApplicationContext接口,会增加一个调用该接口的方法setApplicationContext()步骤,该方法紧接着BeanFactoryAware之后,
    此外,如果配置文件中声明了工厂后处理器接口BeanFactoryPostProcessor的实现类,则应用上下文在装载配置文件之后,初始化Bean实例之前将调用这些BeanFactoryPostProcessor对配置信息进行加工处理。
     
          ApplicationContext和BeanFactory另一个最大的不同之处在于:前者会利用JAVA机制自动识别出配置文件中定义的BeanPostProcessor,InstantiationAwareBeanPostProcessor和BeanFactoryPostProcessor,并自动将他们注册到应用上下文中;而后者需要在代码中通过手工调用addBeanPostProcessor()方法进行注册。这也是为什么在应用开发时,我们普遍使用ApplicationContext而很少使用BeanFactory的原因之一。
         在ApplicationContext中,我们只需要在配置文件中通过<bean>定义工厂后处理器和Bean后处理器,他们就会按预期的方式执行。
         来看一个使用工厂后处理器的实例,假设我们希望对配置文件中car的brand配置属性进行调整,则可以编写一个如下的工厂后处理器:
     
    工厂后处理器器:MyBeanFactoyPostProcessor.java
    [java] view plain copy
     
    1. package com.spring.context;  
    2.   
    3. import org.springframework.beans.BeansException;  
    4. import org.springframework.beans.factory.config.BeanDefinition;  
    5. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;  
    6. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;  
    7. import org.springframework.context.annotation.Bean;  
    8.   
    9. public class MyBeanFactoyPostProcessor  implements BeanFactoryPostProcessor{  
    10.    //1 对car<bean> 的brand属性配置信息进行“偷梁换柱”的加工操作  
    11.     public void postProcessBeanFactory(  
    12.             ConfigurableListableBeanFactory bf)  
    13.             throws BeansException {  
    14.           
    15.             BeanDefinition bd=bf.getBeanDefinition("car");  
    16.             bd.getPropertyValues().addPropertyValue("brand", "奇瑞QQ");  
    17.             System.out.println("调用BeanFactoryPostProcessor.postProcessBeanFactory()!");  
    18.     }  
    19. }  
    ApplicationContext在启动时,将首先为配置文件中的每个<bean>生成一个BeanDefinition对象,BeanDefinition是<bean>在Spring容器中的内部表示。当配置文件中所有的<bean>都被解析成Definition时,ApplicationContext将调用工厂后处理器的方法,因此我们有机会通过程序的方式调整bean的配置信息。在这里,我们将car的BeanDefinition进行调整,将brand属性设置为"奇瑞QQ",下面是具体的配置:
    beans.xml
    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    4.        xmlns:p="http://www.springframework.org/schema/p"   
    5.        xsi:schemaLocation="http://www.springframework.org/schema/beans  
    6.            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
    7.     <!-- 1 这个brand属性的值将被工厂后处理器更改掉-->  
    8.    <bean  id="car" class="com.spring.beanfactory.Car" init-method="myInit" destroy-method="myDestory"  
    9.        p:brand="红旗CA72"  
    10.        p:maxSpeed="300"  
    11.    />  
    12.      
    13.    <!-- 2 Bean后处理器-->  
    14.    <bean id="myBeanPostprocessor" class="com.spring.beanfactory.MyBeanPostProcessor"/>  
    15.      
    16.    <!-- 3 Bean工厂后处理器 -->  
    17.    <bean id="myBeanFactory" class="com.spring.context.MyBeanFactoyPostProcessor"/>  
    18. </beans>  
    2和3处定义的BeanPostProcessor和BeanFactoryPostProcessor会自动被ApplicationContext识别并注册到容器中。3处注册的工厂后处理器将会对1处配置的属性值进行调整。在2处,我们还定义了一个Bean后处理器,它也可以对1处配置的属性进行调整。启动容器并查看car Bean的信息,我们将发现car Bean的brand属性成功被工厂后处理器修改了.
    [java] view plain copy
     
    1. package com.spring.test;  
    2.   
    3. import org.springframework.context.ApplicationContext;  
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
    5. import com.spring.beanfactory.Car;  
    6. public class Test {  
    7.     public static void main(String[] args) {  
    8.              
    9.         ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");  
    10.         Car car =(Car) ctx.getBean("car");  
    11.         System.out.println(car.getBrand());  
    12.     }  
    13. }  
    输出信息如下:
    [java] view plain copy
     
    1. 三月 27, 2014 1:55:54 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh  
    2. 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@17f1841: startup date [Thu Mar 27 13:55:54 CST 2014]; root of context hierarchy  
    3. 三月 27, 2014 1:55:54 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions  
    4. 信息: Loading XML bean definitions from class path resource [beans.xml]  
    5. 调用BeanFactoryPostProcessor.postProcessBeanFactory()!  
    6. 三月 27, 2014 1:55:54 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons  
    7. 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@16fb592: defining beans [car,myBeanPostprocessor,myBeanFactory]; root of factory hierarchy  
    8. 调用Car构造函数  
    9. 调用setBrand()设置属性  
    10. 调用BeanNameAware.setBeanName()  
    11. 调用BeanFactoryAware.setBeanFactory()  
    12. 调用BeanPostProcessor.postProcessBeforeInitialization(),color为空,设置为默认黑色.  
    13. 调用InitializingBean.afterPropertiesSet()  
    14. 调用inti-method所指定的myInit(),将maxSpeed设置为240.  
    15. 调用BeanPostProcessor.postProcessAfterInitialization(),将maxSpedd调整为200.  
    16. 奇瑞QQ  
  • 相关阅读:
    [BUUOJ记录] [ZJCTF 2019]NiZhuanSiWei
    [BUUOJ记录] [BJDCTF2020]EasySearch
    [BUUOJ记录] [BJDCTF2020]The mystery of ip
    php版本:实现过滤掉广告、色情、政治相关的敏感词
    热门搜索词获取java版
    如何用代码挖局长尾关键词
    几行python代码解决相关词联想
    如何高效的完成中文分词?
    python 脚本撞库国内“某榴”账号
    搜索引擎之全文搜索算法功能实现(基于Lucene)
  • 原文地址:https://www.cnblogs.com/lize1215/p/8185395.html
Copyright © 2011-2022 走看看