Spring Bean的生命周期小析(二)

简介: 在上一篇文章中我们说了BeanFactory中Bean的生命周期(点击这里查看),在这一篇文章中我们说一下ApplicationContex中Bean的生命周期。

在上一篇文章中我们说了BeanFactory中Bean的生命周期(点击这里查看),在这一篇文章中我们说一下ApplicationContex中Bean的生命周期。ApplicationContext中Bean的生命周期和在BeanFactory中的生命周期大致相同,不同的是多了一个BeanFactoryPostProcessor的接口和ApplicationContextAware接口(这个接口会设置应用上下文即ApplicationContext)。如果配置文件中声明了工厂后处理器接口BeanFactoryPostProcessor的实现类,则应用上下文在装载配置文件之后初始化Bean实例之前将调用这些BeanFactoryPostProcessor对配置信息进行加工处理。Spring框架也提供了多个工厂后处理器如:CustomEditorConfigurer、PropertyPlaceholderConfigurer(解析properties文件)。ApplicationContext和BeanFactory的另一个不同之处是(在上篇文章中我们提到了ApplicationContext和BeanFactory的一个不同):ApplicationContext会利用Java反射机制自动识别出配置文件中定义的BeanPostProcessor、InstantiationAwareBeanPostProcessor和BeanFactoryPostProcessor,并将它们自动注册到应用上下文中;而BeanFactory需要我们手工调用addBeanPostProcessor()方法进行注册.下面我们来看一下ApplicationContext中Bean的生命周期的图示:


下面我们写个程序测试一下:

Bean的生命周期接口和自身的方法以及ApplicationContextAware接口:

package com.zkn.newlearn.spring.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * Created by zkn
 * BeanFactoryAware、BeanNameAware、InitializingBean、DisposableBean是Bean级的生命周期接口方法.
 */
public class BeanLifeCycleLearn01 implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean,ApplicationContextAware {
    /**
     * 姓名
     */
    private String name;
    /**
     * BeanFactory
     */
    private BeanFactory beanFactory;

    private String beanName;

    static {
        System.out.println("BeanLifeCycleLearn01的静态方法块。。。。");
    }

    private ApplicationContext applicationContext;

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

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

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

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

    public void setName(String name) {
        System.out.println("BeanLifeCycleLearn01调用set方法进行name属性值的设置!");
        this.name = name;
    }

    public void initMethod(){
        System.out.println("我是配置文件中的init-method。。。。");
    }

    public void destoryMethod(){
        System.out.println("我是配置文件中的destory-method。。。。");
    }

    @Override
    public String toString() {
        return "BeanLifeCycleLearn01{" +
            "name='" + name + '\'' +
            ", beanName='" + beanName + '\'' +
            '}';
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        System.out.println("ApplicationContextAware中的setApplicationContext方法。。。。。");
    }
}


BeanFactoryPostProcessor的实现类:

package com.zkn.newlearn.spring.lifecycle;

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;

/**
 * Created by zkn 
 * BeanFactoryPostProcessor:这个在Spring容器的生命周期中只会被调用一次。
 */
public class BeanFactoryPostProcessor01 implements BeanFactoryPostProcessor {

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

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

实现容器级的InstantiationAwareBeanPostProcessor接口:

InstantiationAwareBeanPostProcessor接口是BeanPostProcessor接口的子接口,在Spring1.2中定义的,在Spring2.0中为其提供了一个适配器类org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter,一般情况下,我们可以方便的扩展该适配器覆盖感兴趣的方法以定义实现类。所在我们在这里也是继承的InstantiationAwareBeanPostProcessorAdapter。
package com.zkn.newlearn.spring.lifecycle;

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

import java.beans.PropertyDescriptor;

/**
 * Created by zkn
 * InstantiationAwareBeanPostProcessorAdapter:每个Bean在设置属性的时候都会调用者三个方法,在用的时候要慎重.
 */
public class InstantiationAwareBeanPostProcessor01 extends InstantiationAwareBeanPostProcessorAdapter {

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

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

    /**
     *  接口方法、实例化Bean之后调用
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法");
        if(bean instanceof BeanLifeCycleLearn01){
            ((BeanLifeCycleLearn01) bean).setName("我被该名为张四了");
        }
        return bean;
    }

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

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("InstantiationAwareBeanPostProcessor调用postProcessAfterInstantiation方法");
        return true;
    }
}

BeanPostProcessor后置处理器:

package com.zkn.newlearn.spring.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
 * Created by zkn
 * BeanPostProcessor:每个Bean都会调用,用的时候要慎重.
 */
public class BeanPostProcessor01 implements BeanPostProcessor {

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

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

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

Spring的配置文件:

<?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 id="beanLifeCycleLearn01" class="com.zkn.newlearn.spring.lifecycle.BeanLifeCycleLearn01"
          init-method="initMethod" destroy-method="destoryMethod">
        <property name="name" value="zhangsan"/>
    </bean>

    <bean id="beanPostProcessor01" class="com.zkn.newlearn.spring.lifecycle.BeanPostProcessor01"/>

    <bean id="beanFactoryPostProcessor01" class="com.zkn.newlearn.spring.lifecycle.BeanFactoryPostProcessor01"/>

    <bean id="instantiationAwareBeanPostProcessor01"
          class="com.zkn.newlearn.spring.lifecycle.InstantiationAwareBeanPostProcessor01"/>
</beans>

测试方法:

    @Test
    public void testBeanLifeCycle(){

        ApplicationContext applicationContext =  new ClassPathXmlApplicationContext("com/zkn/newlearn/spring/lifecycle/beans.xml");

        BeanLifeCycleLearn01 beanLifeCycle = (BeanLifeCycleLearn01)applicationContext.getBean("beanLifeCycleLearn01");
        System.out.println(beanLifeCycle.toString());
        ((ClassPathXmlApplicationContext)applicationContext).registerShutdownHook();
    }

输出结果为:


输出结果和我们上面画的图是一样的。但是这里需要注意的是我们的Bean实现了ApplicationContextAware这个接口。有的人可能是用另外的一个Bean实现了ApplicationContextAware这个接口,然后输出结果可能和我们上面的图是不一样的,为什么会不一样呢?因为实现ApplicationContextAware接口的Bean和我们定义的业务Bean是一样的,即 ApplicationContextAware是一个Bean级的生命周期接口,它不是容器级的生命周期接口!!!在这里我们再做个总结, 总结一下Bean的生命周期的执行顺序,先执行容器级的生命周期的接口:BeanFactoryPostProcessor的postProcessBeanFactory方法(这个容器只会执行一次),接着实例化BeanPostProcessor的实现类,实例化InstantiationAwareBeanPostProcessorAdapter的实现类;然后一个Bean被创建的顺序是这样的:执行容器级的生命周期接口:InstantiationAwareBeanPostProcessorAdapter的postProcessBeforeInstantiation方法,再执行Bean的实例化,再执行容器级的生命周期接口:InstantiationAwareBeanPostProcessorAdapter的postProcessAfterInstantiation,再执行容器级的生命周期接口:InstantiationAwareBeanPostProcessorAdapter的postProcessPropertyValues,再接着调用bean自身的setter方法进行属性值的设置,再接着调用Bean级的生命周期接口:BeanNameAware的setBeanName方法,再接着调用Bean级的生命周期接口:BeanFactoryAware的setBeanFactory方法,再接着调用Bean级的生命周期接口:ApplicationContextAware的setApplicationContext方法,再接着调用容器级的生命周期接口:BeanPostProcessor中的postProcessBeforeInitialization方法,再接着调用Bean级的生命周期接口:InitializingBean的afterPropertiesSet方法,再接着调用配置文件中的init-method指定的方法,再接着调用容器级的生命周期接口:BeanPostProcessor中的postProcessAfterInitialization方法,再接着调用容器级的生命周期接口:InstantiationAwareBeanPostProcessor的postProcessAfterInitialization方法,接着执行一些的业务操作,当容器关闭时,先调用Bean级的生命周期接口:DiposibleBean的destory方法,最后调用配置文件中destory-method指定的方法。
当然Spring在实例化Bean的时候还有很多Spring自身的处理,这里我们说的只是和Bean的生命周期中有关的一些东西(Spring提供的能让我们控制Bean的内容)。

参考:
Spring 3.x 企业应用开发实战   陈雄华 林开雄著。





相关文章
|
1月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
164 26
|
3月前
|
XML 安全 Java
|
3月前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
101 12
|
3月前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
3月前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
94 6
|
3月前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
250 4
|
4月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
224 4
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
3月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
64 1
|
5月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
120 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
6月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
399 18

热门文章

最新文章