Spring Bean生命周期中各阶段的作用及实例演示说明

本文分两个部分

第一部分 解释SpringBean生命周期中各接口作用

第二部分 对SpringBean生命周期中各接口的执行顺序以Demo形式进行说明

第一部分转载于:

Spring Bean生命周期的各阶段介绍 - 寻觅beyond - 博客园

第二部分转载于:

Spring Bean的生命周期(非常详细) - Chandler Qian - 博客园

目录

解释SpringBean生命周期中各接口作用

一、xml方式配置Bean

1.1 创建Student类

1.2 创建配置文件

1.3 测试

二.Aware接口

2.1 BeanNameAware

2.2 BeanFactoryAware

2.3 ApplicationContextAware

2.4 Aware各接口执行的先后顺序

2.4 Aware接口总结

三.BeanPostProcessor接口

四.InitializingBean接口

五.init-method

六.DestructionAwareBeanPostProcessor接口

七.DisposableBean接口 

八.destroy-method方法

Spring Bean的生命周期演示

一、实现多接口的Person类

二、BeanPostProcessor前后置处理

三、实现InstantiationAwareBeanPostProcessor 接口

四、实现BeanFactoryPostProcessor接口

五、配置xml文件

六、测试

七、输出


解释SpringBean生命周期中各接口作用

  上面的提到的流程图,注意上面的图只是Spring Bean的大概流程(省略了一部分),主要涉及到了5个接口,分别是XxxAware、BeanPostProcessor、InitiailizingBean、Destruction、DisposableBean接口,本文将会对这几个接口,以及init-method、destroy-method做相关的使用介绍,在明白怎么使用后,再把他们串起来,这样的话,对于Spring Bean的生命周期就差不多知道咋回事了,而不用死记硬背。 

一、xml方式配置Bean

  在说Aware、BeanPostProcessor、InitiailizingBean、Destruction、DisposableBean这些接口前,先简单回顾一下使用xml配置并获取一个Student类的bean过程,后面介绍各个接口的使用方式时时,也是按照这个形式;

1.1 创建Student类

  平淡无奇的Student类:

package cn.ganlixin.entity;
 
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
 
@Data
@Slf4j
public class Student {
 
    private Integer id;
    private String name;
}

1.2 创建配置文件

  平淡无奇的applicationContext.xml配置文件,创建一个student bean,利用setter方式设置初始值:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean class="cn.ganlixin.entity.Student" id="student">
        <property name="id" value="99"/>
        <property name="name" value="张三"/>
    </bean>
</beans>

1.3 测试

  创建一个Main类,用于测试

package cn.ganlixin;
 
import cn.ganlixin.entity.Student;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
 
@Slf4j
public class Test {
 
    public static void main(String[] args) {
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
 
        Student student = beanFactory.getBean("student", Student.class);
        log.info("测试程序获取到的student bean:{}", student);
    }
}

二.Aware接口

  Aware接口有很多实现类,本文只介绍BeanNameAware、BeanFactoryAware、    ApplicationContextAware,关系如下:

2.1 BeanNameAware

  创建一个Student类,让该类实现BeanNameAware接口,并且重写setBeanName方法

@Data
@Slf4j
public class Student implements BeanNameAware {
 
    private Integer id;
    private String name;
 
    /**
     * 实现了BeanNameAware接口后,需重写setBeanName方法,接收的参数就是bean的id
     *
     * @param s bean的id
     */
    @Override
    public void setBeanName(String s) {
        log.info("beanName:{}, student bean:{}", s, this);
        this.id = 100;
        log.info("将beanName:{}的id改为100", s);
    }
}

         配置文件和测试程序都不改变,运行测试程序,输出内容如下:

INFO  [main] cn.ganlixin.entity.Student - beanName:student, student bean:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.entity.Student - 将beanName:student的id改为100
INFO  [main] cn.ganlixin.Test - 测试程序获取到的student bean:Student(id=100, name=张三)

        可以看到,实现BeanNameAware接口后,重写setBeanName的方法中,获取到的student bean,是已经初始化的bean(属性都已经有值了),并且setBeanName方法中可以对当前的bean进行各种操作,包括修改bean的某些属性,最后获取到的bean是已经修改后的bean。

  这里只是简单介绍了一下BeanNameAware接口的用法,使用BeanNameAware接口,可以对当前Bean进行操作。

2.2 BeanFactoryAware

  创建Student类,实现BeanFactoryAware接口,并且重写setBeanFactory方法

@Data
@Slf4j
public class Student implements BeanFactoryAware {
 
    private Integer id;
    private String name;
 
    /**
     * 实现BeanFactoryAware接口后,需重写setBeanFactroy方法
     *
     * @param beanFactory 创建该bean的beanFactory
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        // 可以在setBeanFactory方法中获取、修改beanFactory中的所有bean
         
        log.info("student this bean:{}", this);
        Student student = beanFactory.getBean("student", Student.class);
        log.info("通过beanFactory获取student bean:{}", student);
 
        // 将name设置为李四
        this.name = "李四";
    }
}

        运行输出如下:

INFO  [main] cn.ganlixin.entity.Student - student this bean:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.entity.Student - 通过beanFactory获取student bean:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.Test - 测试程序获取到的student bean:Student(id=99, name=李四)

        通过上面的代码输出结果可以看出,实现BeanFactoryAware接口后,可以在setBeanFactory方法中操作BeanFactory的所有bean,操作的范围要比BeanNameAware要大。

2.3 ApplicationContextAware

  ApplicationContext,有多种称呼,比如“应用容器”、“环境”、“上线文”...

  创建Student类,实现ApplicationContextAware接口,并且重写setApplicationContext接口:

@Data
@Slf4j
public class Student implements ApplicationContextAware {
 
    private Integer id;
    private String name;
 
    /**
     * 实现ApplicationContextAware接口后,徐重写setApplicationContext方法
     *
     * @param applicationContext 该bean所在的上下文(applicationContext、容器)
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("Student this:{}", this);
 
        final Student student = applicationContext.getBean("student", Student.class);
        final Environment environment = applicationContext.getEnvironment();
        log.info("student bean:{}", student);
        log.info("env -> user.dir:{}", environment.getProperty("user.dir"));
    }
}

  需要修改一下测试程序,测试程序中加载配置时使用的XmlBeanFactory,而XmlBeanFactory不会回调ApplicationContextAware接口的setApplicationContext方法,下面使用  ClassPathXmlApplicationContext类来加载配置:

@Slf4j
public class Test {
 
    public static void main(String[] args) {
        //BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
 
        // 使用ApplicationContext来加载配置
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = context.getBean("student", Student.class);
        log.info("测试程序获取到的student bean:{}", student);
    }
}

  运行测试程序:

INFO  [main] cn.ganlixin.entity.Student - Student this:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.entity.Student - student bean:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.entity.Student - env -> user.dir:/Users/ganlixin/code/java-code-all/spring
INFO  [main] cn.ganlixin.Test - 测试程序获取到的student bean:Student(id=99, name=张三)

  实现ApplicationContextAware接口后,在setApplicationContext方法中,入参是当前的applicationContext,也就是说,可以在该方法中对Spring容器进行设置,操作的范围又要比BeanFactoryAware的setBeanFactory要广得多

2.4 Aware各接口执行的先后顺序

  既然有这几个Aware接口,如果一个类同时实现了这3个接口,那么执行顺序是怎样的呢?下面就来测试一下。

  创建Student类,分别实现BeanNameAware、BeanFactoryAware、ApplicationContextAware接口,并重写其接口的方法:

@Data
@Slf4j
public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
 
    private Integer id;
    private String name;
 
    /**
     * 实现了BeanNameAware接口后,需重写setBeanName方法,接收的参数就是bean的id
     *
     * @param s bean的id
     */
    @Override
    public void setBeanName(String s) {
        log.info("call BeanNameAware.setBeanName()");
    }
 
    /**
     * 实现BeanFactoryAware接口后,需重写setBeanFactroy
     *
     * @param beanFactory 创建该bean的bean工厂
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.info("call BeanFactoryAware.setBeanFactory()");
    }
 
    /**
     * 实现ApplicationContextAware接口后,徐重写setApplicationContext方法
     *
     * @param applicationContext 该bean所在的上下文(applicationContext、容器)
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("call ApplicationContextAware.setApplicationContext()");
    }
}

  仍旧使用ClassPathXmlApplicationContext类来加载配置,运行输出结果如下:

INFO  [main] cn.ganlixin.entity.Student - call BeanNameAware.setBeanName()
INFO  [main] cn.ganlixin.entity.Student - call BeanFactoryAware.setBeanFactory()
INFO  [main] cn.ganlixin.entity.Student - call ApplicationContextAware.setApplicationContext()
INFO  [main] cn.ganlixin.Test - 测试程序获取到的student bean:Student(id=99, name=张三)

2.4 Aware接口总结

  上面演示了Spring中几个Aware接口的用法和特点,下面总结一下:

  1.实现BeanNameAware接口后,重写setBeanName方法,可以对单个Bean进行扩展修改;

  2.实现BeanFactoryAware接口后,重写setBeanFactory方法,可以对bean工厂中的所有Bean进行扩展修改;

  3.实现ApplicationContextAware接口后,重写setApplicationContext方法后,可以对整个容器进行扩展修改;

  4.这几个接口的执行顺序分别是BeanNameAware->BeanFactoryAware->ApplicationContextAware;

三.BeanPostProcessor接口

  BeanPostProcessor和前面的Aware接口有些区别,通过下面的例子就能看出区别在哪里!

  下面举个例子,创建MyBeanPostProcessor类,实现BeanPostProcessor接口,注意,这里没有在Student类上实现BeanPostProcessor接口。

@Slf4j
public class MyBeanPostProcessor implements BeanPostProcessor {
 
    /**
     * 实现了BeanPostProcessor接口后,重写postProcessBeforeInitialization,在各种Aware接口执行完毕后执行该方法
     *
     * @param bean     本次处理的bean
     * @param beanName 本次处理的beanName(bean id)
     * @return 返回的是在本方法中处理后的bean
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        log.info("MyBeanPostProcessor.postProcessBeforeInitialization, beanName:{}, bean:{}", beanName, bean);
        return bean;
    }
 
    /**
     * 实现了BeanPostProcessor接口后,重写postProcessBeforeInitialization,在initMethod方法执行完毕后执行该方法
     *
     * @param bean     本次处理的bean
     * @param beanName 本次处理的beanName(bean id)
     * @return 返回的是在本方法中处理后的bean
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("MyBeanPostProcessor.postProcessAfterInitialization, beanName:{}, bean:{}", beanName, bean);
        return bean;
    }
}

  创建两个类,分别是Student和User类,其中Use类没有实现Aware接口,Student类实现了前面提到的3个Aware接口

@Data
public class User {
    private Integer id;
    private String name;
}
@Data
@Slf4j
public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
 
    private Integer id;
    private String name;
 
    /**
     * 实现了BeanNameAware接口后,需重写setBeanName方法,接收的参数就是bean的id
     *
     * @param s bean的id
     */
    @Override
    public void setBeanName(String s) {
        log.info("call BeanNameAware.setBeanName()");
    }
 
    /**
     * 实现BeanFactoryAware接口后,需重写setBeanFactroy
     *
     * @param beanFactory 创建该bean的bean工厂
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.info("call BeanFactoryAware.setBeanFactory()");
    }
 
    /**
     * 实现ApplicationContextAware接口后,徐重写setApplicationContext方法
     *
     * @param applicationContext 该bean所在的上下文(applicationContext、容器)
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("call ApplicationContextAware.setApplicationContext()");
    }
}

  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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean class="cn.ganlixin.entity.Student" id="student">
        <property name="id" value="99"/>
        <property name="name" value="张三"/>
    </bean>
 
    <bean class="cn.ganlixin.entity.User" id="user">
        <property name="id" value="88"/>
        <property name="name" value="王五"/>
    </bean>
 
    <!-- 将实现了BeanPostProcessor接口的类也声明为bean -->
    <bean class="cn.ganlixin.processor.MyBeanPostProcessor"/>
</beans>

  测试:

INFO  [main] cn.ganlixin.entity.Student - call BeanNameAware.setBeanName()
INFO  [main] cn.ganlixin.entity.Student - call BeanFactoryAware.setBeanFactory()
INFO  [main] cn.ganlixin.entity.Student - call ApplicationContextAware.setApplicationContext()
INFO  [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:student1, bean:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:student1, bean:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:user, bean:User(id=88, name=王五)
INFO  [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:user, bean:User(id=88, name=王五)
INFO  [main] cn.ganlixin.Test - 测试程序获取到的student bean:Student(id=99, name=张三)

  从上面的运行结果可以得出以下结论:

  1.因为只有Student实现了Aware接口,所以创建student bean的时候会调用对应的Aware接口方法,而User类没有实现Aware接口,所以并没有调用Aware接口方法;

  2.Student和User类都没有继承BeanPostProcessor接口,但是在创建student和user bean的时候,都掉用了MyBeanPostProcessor类中的前置和后置处理(继承自BeanPostProcessor接口);

  3.BeanPostProcessor接口的前置和后置处理,是在Aware接口之后调用;

  4.很重要的一点,需要将BeanPostProcessor接口实现类声明为bean,使用<bean>配置或者使用@Component注解,不然BeanPostProcessor不起作用。

四.InitializingBean接口

  创建Student类,实现InitializingBean接口,然后重写afterPropertiesSet方法:

@Data
@Slf4j
public class Student implements InitializingBean {
 
    private Integer id;
    private String name;
 
    @Override
    public void afterPropertiesSet() throws Exception {
        // 同样可以在这里修改bean的属性值
        log.info("InitialingBean.afterPropertiesSet, this:{}", this);
    }
}

  修改xml配置文件,创建student bean,测试:

INFO  [main] cn.ganlixin.entity.Student - InitialingBean.afterPropertiesSet, this:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.Test - 测试程序获取到的student bean:Student(id=99, name=张三)

五.init-method

  创建Student类,增加一个额外的方法display()

@Data
@Slf4j
public class Student {
 
    private Integer id;
    private String name;
 
    public void display() {
        log.info("Student.display call, this:{}", this);
    }
}

  修改配置文件,在<bean>标签中增加init-method属性,值为display,也就是Student的display方法名:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean class="cn.ganlixin.entity.Student" id="student" init-method="display">
        <property name="id" value="99"/>
        <property name="name" value="张三"/>
    </bean>
</beans>

  运行测试:

INFO  [main] cn.ganlixin.entity.Student - Student.display call, this:Student(id=99, name=张三)

INFO  [main] cn.ganlixin.Test - 测试程序获取到的student bean:Student(id=99, name=张三)

  上面,输出了display中的内容,这是在设置bean的时候调用的。

六.DestructionAwareBeanPostProcessor接口

  DestructionAwareBeanPostProcessor接口,从名称上可以看出来是DestructionAware + BeanPostProcessor的组合,其实也的确是这样,但是需要注意的就是,spring并没有提供DestructionAware接口!!

  下面是DestructionAwareBeanPostProcessor接口的定义:

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
 
    /**
     * Destruction执行的操作
     *
     * @param bean     处理的bean
     * @param beanName bean的名称
     * @throws BeansException
     */
    void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
 
    /**
     * 是否需要执行postProcessBeforeDestruction方法
     *
     * @param bean 执行Destruction的bean
     * @return 是否需要执行postProcessBeforeDestruction方法
     */
    default boolean requiresDestruction(Object bean) {
        return true;
    }
}

  DestructionAwareBeanPostProceesor继承自BeanPostProcessor接口,所以也可以重写前值和后置处理。

  下面介绍使用示例,创建MyDestructionAwareBeanPostProceesor,继承DestructionAwareBeanPostProceesor接口:

@Slf4j
public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
 
    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        log.info("DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, \n\tbeanName:{}, bean:{}", beanName, bean);
    }
     
    @Override
    public boolean requiresDestruction(Object bean) {
        return true; // 返回true,一律执行postProcessBeforeDestruction方法
        // 如果返回false,则不执行postProcessBeforeDestruction方法
    }
}

  修改配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean class="cn.ganlixin.entity.Student" id="student">
        <property name="id" value="99"/>
        <property name="name" value="张三"/>
    </bean>
 
 
    <bean class="cn.ganlixin.entity.User" id="user">
        <property name="id" value="88"/>
        <property name="name" value="王五"/>
    </bean>
 
    <!-- 将实现了DestructionAwareBeanPostProcessor接口的实现类声明为bean> -->
    <bean class="cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor"/>
</beans>

  测试程序:

@Slf4j
public class Test {
 
    public static void main(String[] args) {
        // 使用ApplicationContext来加载配置
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = context.getBean("student", Student.class);
        User user = context.getBean("user", User.class);
 
        log.info("测试程序获取到的student bean:{}", student);
 
        // 获取bean工厂,然后调用destroyBean销毁bean
        AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory();
        factory.destroyBean(student);
    }
}

  运行测试程序,输出如下:

INFO  [main] cn.ganlixin.Test - 测试程序获取到的student bean:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor - DestructionAwareBeanPostProcessor.postProcessBeforeDestruction,
    beanName:cn.ganlixin.entity.Student, bean:Student(id=99, name=张三)

  可以看到,在手动调用destroyBean方法来销毁student bean的时候,调用了MyDestructionAwareBeanPostProcessor中定义的方法。

  需要注意的是,虽然这里使用destroyBean来销毁了student bean,如果又通过getBean来获取student bean,则会重新创建student bean。

七.DisposableBean接口 

  前面介绍了DestructionAwareBeanPostProcessor接口,可以对所有的bean设置销毁(destruction)后的处理操作。

  而这里介绍的DisposableBean接口,就是对单独的Bean进行destrction后的处理,也就是说不是应用到所有的bean上。

  简单介绍一下用法,创建Student类和User类,User类正常(不实现任何接口),Student类实现DisposableBean接口,然后重写destroy方法:

@Data
@Slf4j
public class Student implements DisposableBean {
 
    private Integer id;
    private String name;
 
    @Override
    public void destroy() throws Exception {
        log.info("DisposableBean.destroy, this:{}", this);
    }
}
 
@Data
public class User {
    private Integer id;
    private String name;
}

  创建配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean class="cn.ganlixin.entity.Student" id="student">
        <property name="id" value="99"/>
        <property name="name" value="张三"/>
    </bean>
 
    <bean class="cn.ganlixin.entity.User" id="user">
        <property name="id" value="88"/>
        <property name="name" value="王五"/>
    </bean>
</beans>

  测试程序:

@Slf4j
public class Test {
 
    public static void main(String[] args) {
        // 使用ApplicationContext来加载配置
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = context.getBean("student", Student.class);
        User user = context.getBean("user", User.class);
 
        log.info("测试程序获取到的student bean:{}", student);
        log.info("测试程序获取到的user bean:{}",user);
 
        // 获取bean工厂,然后调用destroyBean销毁bean
        AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory();
        factory.destroyBean(student);
        factory.destroyBean(user);
    }
}

运行输出:

INFO  [main] cn.ganlixin.Test - 测试程序获取到的student bean:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.Test - 测试程序获取到的user bean:User(id=88, name=王五)
INFO  [main] cn.ganlixin.entity.Student - DisposableBean.destroy, this:Student(id=99, name=张三)

  可以看到,虽然测试代码中destroy了student和user两个bean,但是只有student bean在销毁时触发了DisposableBean的destory方法。

八.destroy-method方法

  和init-method相对应的就是destory-method方法了,创建Student类,增加clean方法(自定义):

@Data
@Slf4j
public class Student {
 
    private Integer id;
    private String name;
 
    public void clean() {
        log.info("Student.clean, this:{}", this);
    }
}

  修改配置文件,<bean>标签中使用destroy-method属性,值为clean方法

<bean class="cn.ganlixin.entity.Student" id="student" destroy-method="clean">
    <property name="id" value="99"/>
    <property name="name" value="张三"/>
</bean>

  测试程序:

@Slf4j
public class Test {
 
    public static void main(String[] args) {
        // 使用ApplicationContext来加载配置
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = context.getBean("student", Student.class);
 
        log.info("测试程序获取到的student bean:{}", student);
 
        // 删除bean
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
        registry.removeBeanDefinition("student");
    }
}

  输出:

INFO  [main] cn.ganlixin.Test - 测试程序获取到的student bean:Student(id=99, name=张三)
INFO  [main] cn.ganlixin.entity.Student - Student.clean, this:Student(id=99, name=张三)

Spring Bean的生命周期演示

  上面对每一种接口都做了介绍,我们来演示一下Spring Bean的生命周期。

一、实现多接口的Person类

  首先是一个简单的Spring Bean,调用Bean自身的方法和Bean级生命周期接口方法,为了方便演示,它实现了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这4个接口,同时有2个方法,对应配置文件中<bean>的init-method和destroy-method。如下:

package springBeanTest;

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;

/**
 * @author qsk
 */
public class Person implements BeanFactoryAware, BeanNameAware,
        InitializingBean, DisposableBean {

    private String name;
    private String address;
    private int phone;

    private BeanFactory beanFactory;
    private String beanName;

    public Person() {
        System.out.println("【构造器】调用Person的构造器实例化");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("【注入属性】注入属性name");
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        System.out.println("【注入属性】注入属性address");
        this.address = address;
    }

    public int getPhone() {
        return phone;
    }

    public void setPhone(int phone) {
        System.out.println("【注入属性】注入属性phone");
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "Person [address=" + address + ", name=" + name + ", phone="
                + phone + "]";
    }

    // 这是BeanFactoryAware接口方法
    @Override
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        System.out
                .println("【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()");
        this.beanFactory = arg0;
    }

    // 这是BeanNameAware接口方法
    @Override
    public void setBeanName(String arg0) {
        System.out.println("【BeanNameAware接口】调用BeanNameAware.setBeanName()");
        this.beanName = arg0;
    }

    // 这是InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out
                .println("【InitializingBean接口】调用InitializingBean.afterPropertiesSet()");
    }

    // 这是DiposibleBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("【DiposibleBean接口】调用DiposibleBean.destory()");
    }

    // 通过<bean>的init-method属性指定的初始化方法
    public void myInit() {
        System.out.println("【init-method】调用<bean>的init-method属性指定的初始化方法");
    }

    // 通过<bean>的destroy-method属性指定的初始化方法
    public void myDestory() {
        System.out.println("【destroy-method】调用<bean>的destroy-method属性指定的初始化方法");
    }
}

二、BeanPostProcessor前后置处理

package springBeanTest;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        super();
        System.out.println("这是BeanPostProcessor实现类构造器!!");
        // TODO Auto-generated constructor stub
    }

    @Override
    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException {
        System.out
        .println("BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改!");
        return arg0;
    }

    @Override
    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException {
        System.out
        .println("BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改!");
        return arg0;
    }
}

  如上,BeanPostProcessor接口包括2个方法postProcessAfterInitialization和postProcessBeforeInitialization,这两个方法的第一个参数都是要处理的Bean对象,第二个参数都是Bean的name。返回值也都是要处理的Bean对象。这里要注意。

三、实现InstantiationAwareBeanPostProcessor 接口

  InstantiationAwareBeanPostProcessor 接口本质是BeanPostProcessor的子接口,一般我们继承Spring为其提供的适配器类InstantiationAwareBeanPostProcessor Adapter来使用它,如下:

package springBeanTest;

import java.beans.PropertyDescriptor;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;

public class MyInstantiationAwareBeanPostProcessor extends
        InstantiationAwareBeanPostProcessorAdapter {

    public MyInstantiationAwareBeanPostProcessor() {
        super();
        System.out
                .println("这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!");
    }

    // 接口方法、实例化Bean之前调用
    @Override
    public Object postProcessBeforeInstantiation(Class beanClass,
            String beanName) throws BeansException {
        System.out
                .println("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法");
        return null;
    }

    // 接口方法、实例化Bean之后调用
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out
                .println("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法");
        return bean;
    }

    // 接口方法、设置某个属性时调用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,
            PropertyDescriptor[] pds, Object bean, String beanName)
            throws BeansException {
        System.out
                .println("InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法");
        return pvs;
    }
}

  这个有3个方法,其中第二个方法postProcessAfterInitialization就是重写了BeanPostProcessor的方法。第三个方法postProcessPropertyValues用来操作属性,返回值也应该是PropertyValues对象。

四、实现BeanFactoryPostProcessor接口

  演示工厂后处理器BeanFactoryPostProcessor接口方法,如下:

package springBeanTest;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public MyBeanFactoryPostProcessor() {
        super();
        System.out.println("这是BeanFactoryPostProcessor实现类构造器!!");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
            throws BeansException {
        System.out
                .println("BeanFactoryPostProcessor调用postProcessBeanFactory方法");
        BeanDefinition bd = arg0.getBeanDefinition("person");
        bd.getPropertyValues().addPropertyValue("phone", "110");
    }

}

五、配置xml文件

  配置文件如下beans.xml,很简单,使用ApplicationContext,处理器不用手动注册:

<?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"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <bean id="beanPostProcessor" class="springBeanTest.MyBeanPostProcessor">
    </bean>

    <bean id="instantiationAwareBeanPostProcessor" class="springBeanTest.MyInstantiationAwareBeanPostProcessor">
    </bean>

    <bean id="beanFactoryPostProcessor" class="springBeanTest.MyBeanFactoryPostProcessor">
    </bean>
    
    <bean id="person" class="springBeanTest.Person" init-method="myInit"
        destroy-method="myDestory" scope="singleton" p:name="张三" p:address="广州"
        p:phone="15900000000" />

</beans>

六、测试

  下面测试一下:

package springBeanTest;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifeCycle {

    public static void main(String[] args) {

        System.out.println("现在开始初始化容器");

        ApplicationContext factory = new ClassPathXmlApplicationContext("springBeanTest/beans.xml");
        System.out.println("容器初始化成功");
        //得到Preson,并使用
        Person person = factory.getBean("person",Person.class);
        System.out.println(person);

        System.out.println("现在开始关闭容器!");
        ((ClassPathXmlApplicationContext)factory).registerShutdownHook();
    }
}

  关闭容器使用的是实际是AbstractApplicationContext的钩子方法。

七、输出

  我们来看一下结果:

现在开始初始化容器
2014-5-18 15:46:20 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@19a0c7c: startup date [Sun May 18 15:46:20 CST 2014]; root of context hierarchy
2014-5-18 15:46:20 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [springBeanTest/beans.xml]
这是BeanFactoryPostProcessor实现类构造器!!
BeanFactoryPostProcessor调用postProcessBeanFactory方法
这是BeanPostProcessor实现类构造器!!
这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!
2014-5-18 15:46:20 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@9934d4: defining beans [beanPostProcessor,instantiationAwareBeanPostProcessor,beanFactoryPostProcessor,person]; root of factory hierarchy
InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法
【构造器】调用Person的构造器实例化
InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法
【注入属性】注入属性address
【注入属性】注入属性name
【注入属性】注入属性phone
【BeanNameAware接口】调用BeanNameAware.setBeanName()
【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()
BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改!
【InitializingBean接口】调用InitializingBean.afterPropertiesSet()
【init-method】调用<bean>的init-method属性指定的初始化方法
BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改!
InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法
容器初始化成功
Person [address=广州, name=张三, phone=110]
现在开始关闭容器!
【DiposibleBean接口】调用DiposibleBean.destory()
【destroy-method】调用<bean>的destroy-method属性指定的初始化方法

猜你喜欢

转载自blog.csdn.net/Ahuuua/article/details/124213778
今日推荐