(八)Spring教程——BeanFactory中Bean的生命周期

前言

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

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

1.生命周期图解

        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的postProcessBeforeInitialization(Object bean,String beanName)接口方法对Bean进行加工操作。其中,入参bean是当前正在处理的Bean,而beanNaem是当前Bean的配置名,返回的对象为加工处理后的Bean。用户可以使用该方法对某些Bean进行特殊的处理,甚至改变Bean的行为。BeanPostProcessor在Spring框架中占有重要的地位,为容器提供对Bean进行加工处理的切入点,Spring容器所提供的各种“神奇功能”(如AOP、动态代理等)都是通过BeanPostProcessor实施。
  9. 如果Bean实现了InitializingBean接口,则将调用接口的afterPropertiesSet()方法。
  10. 如果在<bean>中通过init-method属性定义了初始化方法,则将执行这个方法。
  11. BeanPostProcessor后处理器定义了两个方法:其一是postProcessBeforeInitialization(),在第(8)步调用;其二是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接口,则将调用接口的destrory()方法,可以在此编写释放资源、记录日志等操作。
  14. 对于scope=”singleton”的Bean,如果通过<bean>的destory-method属性指定了Bean的销毁方法,那么Spring将执行Bean的这个方法,完成Bean资源的释放等操作。

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

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

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

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

        工厂后处理器接口方法:包括ApsectJWeavingEnabler、CustomerAutoWireConfigurer、ConfigurationClassPostProcessor等方法。工厂后处理器也是容器级的,在应用上下文装配配置文件后立即调用。

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

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

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

2窥探Bean生命周期的实例

         首先创建一个Car类,让它实现所有Bean级的生命周期接口。此外,还定义初始化和销毁的方法,这两个方法将通过<bean>的init-method和destory-method属性指定。Car类的代码如下

package com.example.servlet001.bean;



import org.springframework.beans.BeansException;

import org.springframework.beans.factory.*;



// 管理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 String getBrand(){

        return brand;

    }



    public void setBrand(String brand){

        System.out.println("调用setBrand()设置属性。");

        this.brand=brand;

    }



    public String getColor(){

        return color;

    }



    public void setColor(String color){

        this.color=color;

    }



    public int getMaxSpeed(){

        return maxSpeed;

    }



    public void setMaxSpeed(int maxSpeed){

        this.maxSpeed=maxSpeed;

    }



    public void introduce(){

        System.out.println("brand:"+brand+";color:"+color+";maxSpeed:"+maxSpeed);

    }



    //BeanFactoryAware接口方法

    @Override

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

        System.out.println("调用BeanFactoryAware.setBeanFactory()");

        this.beanFactory=beanFactory;

    }



    //BeanNameAware接口方法

    @Override

    public void setBeanName(String s) {

        System.out.println("调用BeanName.setBeanName().");

        this.beanName=s;

    }



    //DisposableBean接口方法

    @Override

    public void destroy() throws Exception {

        System.out.println("调用DisposableBean.destroy()。");

    }



    //InitializingBean接口方法

    @Override

    public void afterPropertiesSet() throws Exception {

        System.out.println("调用InitializingBean.afterPropertiesSet()。");

    }



    //通过<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()。");

    }

}

        setBeanFactory()方法是对BeanFactoryAware接口的实现

        setBeanName方法是对BeanNameAware接口的实现

        aferPropertiesSet方法是对InitializingBean接口的实现

        destory方法是对DisposalbleBean接口的实现

         在resource文件夹中添加一个该Bean的配置文件text.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:p="http://www.springframework.org/schema/p"

       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="car1" name="car1" class="com.example.servlet001.bean.Car"

          init-method="myInit"

          destroy-method="myDestroy"

          p:brand="红旗"

          p:maxSpeed="200"

    />

</beans>

        然后我们创建一个Spring Bean测试类BeanTest.java

package com.example.servlet001;





import com.example.servlet001.bean.Car;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;

import org.springframework.beans.factory.xml.XmlBeanFactory;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.core.io.ClassPathResource;

import org.springframework.stereotype.Component;



public class BeanTest {

    public static void main(String[] args) {

        BeanFactory factory=new XmlBeanFactory(new ClassPathResource("test.xml"));

        //向容器注册MyBeanPostProcessor后处理器

        ((ConfigurableBeanFactory)factory).addBeanPostProcessor(new MyBeanPostProcessor());

        //向容器中注册MyInstantiationAwareBeanPostProcessor后处理器

        ((ConfigurableBeanFactory)factory).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());

        //第一次从容器中获取car,将触发容器实例化该Bean,这将引发Bean生命周期方法的调用

        Car car=factory.getBean("car1",Car.class);

        car.introduce();

        car.setColor("红色");

        //第二次从容器中获取car,直接从缓存池中获取

        Car car2=(Car) factory.getBean("car1");

        //查看car和car2是否指向同一引用

        System.out.println("car=car2:"+(car==car2));

        //关闭容器

        ((ConfigurableBeanFactory) factory).destroySingletons();

    }



//    @Configuration

//    public static class CarConfig{

//        @Bean(name="car1",initMethod = "myInit",destroyMethod = "myDestroy")

//        public Car car1(){

//           Car car=new Car();

//           car.setBrand("凯迪拉克");

//           return car;

//        }

//    }

}

        运行该代码后的结果如下图所示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jerry95270628

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值