BeanFactory中Bean的生命周期

我们知道Web容器中的Servlet拥有明确的生命周期,Spring容器中的Bean也拥有相似的生命周期。Bean生命周期由多个特定的生命阶段组成,每个生命阶段都开出了一扇门,允许外界对Bean施加控制。

在Spring中,我们可以从两个层面定义Bean的生命周期:第一个层面是Bean的作用范围;第二个层面是实例化Bean时所经历的一系列阶段。下面我们分别对BeanFactory和ApplicationContext中Bean的生命周期进行分析。

生命周期图解

由于Bean的生命周期所经历的阶段比较多,我们将通过一个图形化的方式进行描述。图3-11描述了BeanFactory中Bean生命周期的完整过程:

 
图3-11  BeanFactory中Bean的生命周期

1.当调用者通过getBean(beanName)向容器请求某一个Bean时,如果容器注册了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口,在实例化Bean之前,将调用接口的postProcessBeforeInstantiation()方法;

2.根据配置情况调用Bean构造函数或工厂方法实例化Bean;

3.如果容器注册了InstantiationAwareBeanPostProcessor接口,在实例化Bean之后,调用该接口的postProcessAfterInstantiation()方法,可在这里对已经实例化的对象进行一些"梳妆打扮";

4.如果Bean配置了属性信息,容器在这一步着手将配置值设置到Bean对应的属性中,不过在设置每个属性之前将先调用InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues()方法;

5.调用Bean的属性设置方法设置属性值;

6.如果Bean实现了org.springframework.beans.factory.BeanNameAware接口,将调用setBeanName()接口方法,将配置文件中该Bean对应的名称设置到Bean中;

7.如果Bean实现了org.springframework.beans.factory.BeanFactoryAware接口,将调用setBeanFactory()接口方法,将BeanFactory容器实例设置到Bean中;

8.如果BeanFactory装配了org.springframework.beans.factory.config.BeanPostProcessor后处理器,将调用BeanPostProcessor的Object postProcessBeforeInitialization(Object bean, String beanName)接口方法对Bean进行加工操作。其中入参bean是当前正在处理的Bean,而beanName是当前Bean的配置名,返回的对象为加工处理后的Bean。用户可以使用该方法对某些Bean进行特殊的处理,甚至改变Bean的行为,BeanPostProcessor在Spring框架中占有重要的地位,为容器提供对Bean进行后续加工处理的切入点,Spring容器所提供的各种"神奇功能"(如AOP,动态代理等)都通过BeanPostProcessor实施;

9.如果Bean实现了InitializingBean的接口,将调用接口的afterPropertiesSet()方法;

10.如果在<bean>通过init-method属性定义了初始化方法,将执行这个方法;

11.BeanPostProcessor后处理器定义了两个方法:其一是postProcessBeforeInitialization()在第8步调用;其二是Object postProcessAfterInitialization(Object bean, String beanName)方法,这个方法在此时调用,容器再次获得对Bean进行加工处理的机会;

12.如果在<bean>中指定Bean的作用范围为scope="prototype",将Bean返回给调用者,调用者负责Bean后续生命的管理,Spring不再管理这个Bean的生命周期。如果作用范围设置为scope="singleton",则将Bean放入到Spring IoC容器的缓存池中,并将Bean引用返回给调用者,Spring继续对这些Bean进行后续的生命管理;

13.对于scope="singleton"的Bean,当容器关闭时,将触发Spring对Bean的后续生命周期的管理工作,首先如果Bean实现了DisposableBean接口,则将调用接口的afterPropertiesSet()方法,可以在此编写释放资源、记录日志等操作;

14.对于scope="singleton"的Bean,如果通过<bean>的destroy-method属性指定了Bean的销毁方法,Spring将执行Bean的这个方法,完成Bean资源的释放等操作。

Bean的完整生命周期从Spring容器着手实例化Bean开始,直到最终销毁Bean,这当中经过了许多关键点,每个关键点都涉及特定的方法调用,可以将这些方法大致划分为三类:

Bean自身的方法:如调用Bean构造函数实例化Bean,调用Setter设置Bean的属性值以及通过<bean>的init-method和destroy-method所指定的方法;

Bean级生命周期接口方法:如BeanNameAware、BeanFactoryAware、InitializingBean 和DisposableBean,这些接口方法由Bean类直接实现;

容器级生命周期接口方法:在图3-11中带 "★" 的步骤是由InstantiationAwareBean PostProcessor和BeanPostProcessor这两个接口实现,一般称它们的实现类为"后处理器"。后处理器接口一般不由Bean本身实现,它们独立于Bean,实现类以容器附加装置的形式注册到Spring容器中并通过接口反射为Spring容器预先识别。当Spring容器创建任何Bean的时候,这些后处理器都会发生作用,所以这些后处理器的影响是全局性的。当然,用户可以通过合理地编写后处理器,让其仅对感兴趣Bean进行加工处理。

Bean级生命周期接口和容器级生命周期接口是个性和共性辩证统一思想的体现,前者解决Bean个性化处理的问题;而后者解决容器中某些Bean共性化处理的问题。

Spring容器中是否可以注册多个后处理器呢?答案是肯定的。只要它们同时实现org.springframework.core.Ordered接口,容器将按特定的顺序依次调用这些后处理器。所以图3-11带 ★ 的步骤中都可能调用多个后处理器进行一系列的加工操作。

InstantiationAwareBeanPostProcessor其实是BeanPostProcessor接口的子接口,在Spring 1.2中定义,在Spring 2.0中为其提供了一个适配器类InstantiationAwareBeanPostProcessorAdapter,一般情况下,可以方便地扩展该适配器覆盖感兴趣的方法以定义实现类。下面我们将通过一个具体的实例以更好地理解Bean生命周期的各个步骤。

窥探Bean生命周期的实例

我们依旧采用前面所介绍的Car类,让它实现所有Bean级的生命周期接口,此外还定义初始化和销毁的方法,这两个方法将通过<bean>的init-method和destroy-method属性指定。如代码清单3-26所示:

代码清单3-26 实现各种生命周期控制访问的Car

    package com.baobaotao;  
     
    import org.springframework.beans.BeansException;  
    import org.springframework.beans.factory.BeanFactory;  
    import org.springframework.beans.factory.BeanFactoryAware;  
    import org.springframework.beans.factory.BeanNameAware;  
    import org.springframework.beans.factory.DisposableBean;  
    import org.springframework.beans.factory.InitializingBean;  
     
    //①管理Bean生命周期的接口  
    public class Car implements BeanFactoryAware, BeanNameAware, InitializingBean,  
            DisposableBean {    
        private String brand;  
        private String color;  
        private int maxSpeed;  
     
        private BeanFactory beanFactory;  
        private String beanName;  
     
        public Car() {  
            System.out.println("调用Car()构造函数。");  
        }  
        public void setBrand(String brand) {  
            System.out.println("调用setBrand()设置属性。");  
            this.brand = brand;  
        }  
          
        public void introduce() {  
            System.out.println("brand:" + brand + ";color:" + color + ";maxSpeed:"  
                    + maxSpeed);  
        }  
     
        //②BeanFactoryAware接口方法  
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {  
            System.out.println("调用BeanFactoryAware.setBeanFactory()。");  
            this.beanFactory = beanFactory;  
        }  
          
         //③BeanNameAware接口方法  
        public void setBeanName(String beanName) {  
            System.out.println("调用BeanNameAware.setBeanName()。");  
            this.beanName = beanName;  
        }  
        //④InitializingBean接口方法  
        public void afterPropertiesSet() throws Exception {  
            System.out.println("调用InitializingBean.afterPropertiesSet()。");  
        }  
          
         //⑤DisposableBean接口方法  
        public void destroy() throws Exception {  
            System.out.println("调用DisposableBean.destroy()。");  
        }  
          
         //⑥通过<bean>的init-method属性指定的初始化方法  
        public void myInit() {  
            System.out.println("调用init-method所指定的myInit(),将maxSpeed设置为240。");  
            this.maxSpeed = 240;  
        }  
          
         //⑦通过<bean>的destroy-method属性指定的销毁方法  
        public void myDestroy() {  
            System.out.println("调用destroy-method所指定的myDestroy()。");  
        }  
    }  

Car类在②、③、④、⑤处实现了BeanFactoryAware、BeanNameAware、InitializingBean、DisposableBean这些Bean级的生命周期控制接口;在⑥和⑦处定义了myInit()和myDestroy()方法,以便在配置文件中通过init-method和destroy-method属性定义初始化和销毁方法。

MyInstantiationAwareBeanPostProcessor通过扩展InstantiationAwareBeanPostProcessor适配器InstantiationAwareBeanPostProcessorAdapter提供实现:

代码清单3-27 InstantiationAwareBeanPostProcessor实现类

    package com.baobaotao.beanfactory;  
    import java.beans.PropertyDescriptor;  
    import org.springframework.beans.BeansException;  
    import org.springframework.beans.PropertyValues;  
    import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;  
    import com.baobaotao.Car;  
    public class MyInstantiationAwareBeanPostProcessor extends Instantiation  AwareBeanPostProcessorAdapter{  
         //①接口方法:在实例化Bean前进行调用  
    public Object postProcessBeforeInstantiation(Class beanClass, String beanName)   
             throws BeansException {  
              //①-1仅对容器中car Bean进行处理  
             if("car".equals(beanName)){  
                System.out.println("InstantiationAware BeanPostProcessor. postProcess  
                     BeforeInstantiation");   
            }  
            return null;  
        }  
         //②接口方法:在实例化Bean后调用  
        public boolean postProcessAfterInstantiation(Object bean, String beanName)   
            throws BeansException {  
             //②-1仅对容器中car Bean进行处理  
            if("car".equals(beanName)){  
                System.out.println("InstantiationAware BeanPostProcessor.postProcess  
                     AfterInstantiation");  
            }  
            return true;  
        }  
     
         //③接口方法:在设置某个属性时调用  
        public PropertyValues postProcessPropertyValues(  
                PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)  
                throws BeansException {  
     
                    //③-1仅对容器中car Bean进行处理,还可以通过pdst入参进行过滤,  
                    //仅对car的某个特定属性时进行处理。  
                   if("car".equals(beanName)){  
    System.out.println("Instantiation AwareBeanPostProcessor.postProcess  
                     PropertyValues");  
            }  
            return pvs;  
        }  
    }  

在MyInstantiationAwareBeanPostProcessor中,我们通过过滤条件仅对car Bean进行处理,而对其他的Bean一概视而不见。

此外,我们还提供了一个BeanPostProcessor实现类,在该实现类中,我们也只对car Bean进行处理,对配置文件所提供的属性设置值进行判断,并执行相应的"补缺补漏"的操作:

代码清单3-28  BeanPostProcessor实现类

    package com.baobaotao.beanfactory;  
    import org.springframework.beans.BeansException;  
    import org.springframework.beans.factory.config.BeanPostProcessor;  
    import com.baobaotao.Car;  
    public class MyBeanPostProcessor implements BeanPostProcessor{  
        public Object postProcessBeforeInitialization(Object bean, String beanName)   
            throws BeansException {       
            if(beanName.equals("car")){  
                Car car = (Car)bean;  
                if(car.getColor() == null){  
                    System.out.println("调用BeanPostProcessor.postProcess BeforeInitialization(),  
                         color为空,设置为默认黑色。");  
                    car.setColor("黑色");  
                }  
            }  
            return bean;  
        }  
     
        public Object postProcessAfterInitialization(Object bean, String beanName)   
            throws BeansException {       
            if(beanName.equals("car")){  
                Car car = (Car)bean;  
                if(car.getMaxSpeed() >= 200){  
                    System.out.println("调用BeanPostProcessor.postProcess AfterInitialization(),  
                         将maxSpeed调整为200。");  
                    car.setMaxSpeed(200);  
                }  
            }  
            return bean;  
        }  
    }  

在MyBeanPostProcessor类的postProcessBeforeInitialization()方法中,我们首先判断处理的Bean是否名为car,如果是,进一步判断该Bean的color属性是否为空,如果为空,将该属性设置为"黑色"。在postProcessAfterInitialization()方法中,我们也是只对名为car的Bean进行处理,判断其maxSpeed是否超过最大速度200,如果超过,将其设置为200。

至于如何将MyInstantiationAwareBeanPostProcessor和MyBeanPostProcessor这两个后处理器注册到BeanFactory容器中,请参看代码清单3 30的内容。

现在,我们在Spring配置文件中定义Car的配置信息,如代码清单3 29所示:

代码清单3-29  beans.xml:配置Car

    <bean id="car" class="com.baobaotao.Car"   
         init-method="myInit" 
         destroy-method="myDestroy" 
         p:brand="红旗CA72" 
         p:maxSpeed="200"   
         />    

我们通过init-method指定Car的初始化方法为myInit();通过destroy-method指定Car的销毁方法为myDestroy();同时通过scope定义了Car的作用范围,关于Bean作用范围的详细讨论参见第4.7节的内容。

下面,我们让容器装载配置文件,然后再分别注册上面所提供的两个后处理器:

代码清单3-30  BeanLifeCycle

    package com.baobaotao.beanfactory;  
    import org.springframework.beans.factory.BeanFactory;  
    import org.springframework.beans.factory.config.ConfigurableBeanFactory;  
    import org.springframework.beans.factory.xml.XmlBeanFactory;  
    import org.springframework.core.io.ClassPathResource;  
    import org.springframework.core.io.Resource;  
    import com.baobaotao.Car;  
     
    public class BeanLifeCycle {  
        private static void LifeCycleInBeanFactory(){  
          //①下面两句装载配置文件并启动容器  
          Resource res = new ClassPathResource("com/baobaotao/beanfactory/beans.xml");    
          BeanFactory bf = new XmlBeanFactory(res);  
             
     
          //②向容器中注册MyBeanPostProcessor后处理器  
    ((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyBeanPostProcessor());  
            
          //③向容器中注册MyInstantiationAwareBeanPostProcessor后处理器  
    ((ConfigurableBeanFactory)bf).addBeanPostProcessor(  
                                   new MyInstantiationAwareBeanPostProcessor());  
          //④第一次从容器中获取car,将触发容器实例化该Bean,这将引发Bean生命周期方法的调用。  
           Car car1 = (Car)bf.getBean("car");   
          car1.introduce();  
          car1.setColor("红色");  
     
           //⑤第二次从容器中获取car,直接从缓存池中获取  
          Car car2 = (Car)bf.getBean("car");    
            
           //⑥查看car1和car2是否指向同一引用  
           System.out.println("car1==car2:"+(car1==car2))   
           //⑦关闭容器  
          ((XmlBeanFactory)bf).destroySingletons();  
        }  
        public static void main(String[] args) {  
            LifeCycleInBeanFactory();  
        }  
    }  

在①处,我们装载了配置文件并启动容器。在②处,我们向容器中注册了MyBeanPostProcessor后处理器,注意我们对BeanFactory类型的bf变量进行了强制类型转换,因为用于注册后处理器的addBeanPostProcessor()方法是在ConfigurableBeanFactory接口中定义的。如果有多个后处理器,可按照相似的方式调用addBeanPostProcessor()方法进行注册,需要强调的是,后处理器的实际调用顺序和注册顺序是无关的,在具有多个后处理器的情况下,必须通过实现的org.springframework.core.Ordered接口以确定调用顺序。

在③处,我们按照注册MyBeanPostProcessor后处理器相同的方法注册MyInstantiationAwareBeanPostProcessor后处理器,Spring容器会自动检查后处理器是否实现了InstantiationAwareBeanPostProcessor接口,并据此判断后处理器的类型。

在④处,我们第一次从容器中获取car Bean,容器将按图3-10中描述的Bean生命周期过程,实例化Car并将其放入到缓存中,然后再将这个Bean引用返回给调用者。在⑤处,我们再次从容器中获取car Bean时,Bean将从容器缓存中直接取出,不会引发生命周期相关方法的执行。如果Bean的作用范围定义为scope="prototype",则第二次getBean()时,生命周期方法会再次调用,因为prototype范围的Bean每次都返回新的实例。在⑥处,我们检验car1和car2是否指向相同的对象。

运行BeanLifeCycle,我们在控制台上得到以下输出信息:
    InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation  
    调用Car()构造函数。  
    InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation  
    InstantiationAwareBeanPostProcessor.postProcessPropertyValues  
    调用setBrand()设置属性。  
    调用BeanNameAware.setBeanName()。  
    调用BeanFactoryAware.setBeanFactory()。  
    调用BeanPostProcessor.postProcessBeforeInitialization(),color为空,设置为默认黑色。  
    调用InitializingBean.afterPropertiesSet()。  
    调用myInit(),将maxSpeed设置为240。  
    调用BeanPostProcessor.postProcessAfterInitialization(),将maxSpeed调整为200。  
    brand:奇瑞QQ;color:黑色;maxSpeed:200  
    brand:奇瑞QQ;color:红色;maxSpeed:200  
    2007-01-03 15:47:10,640  INFO [main]
    (DefaultSingletonBeanRegistry.java:272) - 
    Destroying singletons in {org.springframework.beans.
    factory.xml.XmlBeanFactory defining beans [car]; root of BeanFactory hierarchy}  
    调用DisposableBean.destroy()。  
    调用myDestroy()。  

仔细观察输出的信息,将发现它验证了我们前面所介绍了Bean生命周期的过程。在⑦处,我们通过destroySingletons()方法关闭了容器,由于Car实现了销毁接口并指定了销毁方法,所以容器将触发调用这两个方法。

关于Bean生命周期接口的探讨

通过实现Spring的Bean生命周期接口对Bean进行额外控制,虽然让Bean具有了更细致的生命周期阶段,但也带来了一个问题,Bean和Spring框架紧密绑定在一起了,这和Spring一直推崇的"不对应用程序类作任何限制"的理念是相悖的。因此,我们推荐业务类完全POJO化,只实现自己的业务接口,不需要和某个特定框架(包括Spring框架)的接口关联。

可以通过<bean>的init-method和destroy-method属性配置方式为Bean指定初始化和销毁的方法,采用这种方式对Bean生命周期的控制效果和通过实现InitializingBean、DisposableBean接口所达到的效果是完全相同的。采用前者的配置方式可以使Bean不需要和特定Spring框架接口绑定,达到了框架解耦的目的。Spring 2.1中还添加了一个InitDestroyAnnotationBeanPostProcessor,该Bean后处理器将对标注了@PostConstruct、@PreDestroy注解的Bean进行处理,在Bean初始化后及销毁前执行相应的逻辑。喜欢注解的读者,可以通过InitDestroyAnnotationBeanPostProcessor达到和以上两种方式相同的效果。

对于BeanFactoryAware和BeanNameAware接口,第一个接口让Bean感知容器(即BeanFactory实例),而后者让Bean获得配置文件中对应的配置名称。在一般情况下,用户几乎不需要关心这两个接口,如果Bean希望获取容器中其他的Bean,可以通过属性注入的方式引用这些Bean,如果Bean希望在运行期获知在配置文件中的Bean名称,也可以简单地将名称作为属性注入。

综上所述,我们认为除非编写一个基于Spring之上的扩展插件或子项目之类的东西,否则用户完全可以抛开以上4个Bean生命周期的接口类,使用更好的方案替代之。

但BeanPostProcessor接口却不一样,它不要求Bean去继承它,可以完全像插件一下注册到Spring容器中,为容器提供额外功能。Spring容器充分地利用了BeanPostProcessor对Bean进行加工处理,当我们讲到Spring的AOP功能时,还会对此进行分析,了解BeanPostProcessor对Bean的影响,对于深入理解Spring核心功能的工作机理将会有很大的帮助。不过,对于一般的应用而言,我们也不大需要使用到这个接口,Spring扩展插件或Spring子项目却可以使用这些后处理器完成很多激动人心的功能。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值