`

Spring基本用法5——容器中Bean的生命周期

阅读更多

        前言:Spring可以管理singleton作用域的Bean的生命周期,Spring可以精确知道该Bean何时被创建、何时被初始化完成、容器何时准备销毁该Bean实例。Spring管理Bean的生命周期行为主要有两个时机,一是注入依赖关系之后,二是即将销毁Bean之前。(本篇主要针对ApplicationContext容器进行展开)

本篇文章重点关注以下问题:

  • 引言;
  • Spring容器中各级别的生命周期接口及方法;
  • 演示Spring Bean的生命周期。

0. 引言

        对于prototype作用域的Bean,Spring容器仅仅负责创建,当容器创建了Bena实例之后,Bean实例完全交给客户端代码管理,容器不再跟踪其生命周期。每次客户端请求prototype作用域的Bean时,Spring都会产生一个新的实例,Spring容器无法知道它曾经创造了多少个prototype作用域的Bean,也无从知道这些prototype作用域的Bean什么时候才会销毁。因此,Spring无法管理prototype作用域的Bean。
       对于singleton作用域的Bean,每次客户端代码请求时,都返回同一个贡献实例,客户端代码不能控制Bean的销毁,Spring容器负责跟踪Bean实例的产生、销毁。Spring容器可以在创建Bean之后,进行某些通用资源的申请;还可以在销毁Bean实例之前,先回收某些资源,比如数据库连接等。
       首先给出Spring Bean的完整生命周期,从创建Spring容器开始,直到最终Spring容器销毁Bean,这其中包含了一系列关键点:

1. Spring容器中各级别的生命周期接口及方法

       我们将Spring容器中Bean的生命周期级别分为四级,分别是:Bean自身方法、Bean级生命周期接口方法、容器级生命周期接口方法、工厂后处理器接口方法。

1. Bean自身的方法,包括:
      * Bean本身调用的方法
      * 通过配置文件中的init-method和destroy-method指定的方法;
2. Bean级生命周期接口方法,包括:
      * InitializingBean接口
      * DiposableBean接口
      * BeanNameAware接口
      * ApplicationContextAware接口
      * BeanFactoryAware接口
      * 其他
3. 容器级生命周期接口方法,包括:
      * InstantiationAwareBeanPostProcessor接口实现
      * BeanPostProcessor 接口实现
      * 一般称它们的实现类为“后处理器”
4. 工厂级生命周期口方法(BeanFactoryPostProcessor接口的实现类)
      * AspectJWeavingEnabler
      * ConfigurationClassPostProcessor
      * CustomAutowireConfigurer等
      * 工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

 2.  Bean自身方法及Bean级生命周期方法

         Bean自身的方法:调用构造函数实例化bean,调用setter设置属性,调用init-method,destroy-method。

1. init-method    :指定某个方法在Bean实例化完成,依赖关系设置结束后执行;
2. destroy-method :指定某个方法在Bean销毁之前被执行。
         Bean级生命周期方法:如BeanNameAware,BeanFactoryAware,InitializingBean和DisposableBean,这些接口由bean直接实现。
1. InitializingBean接口 :指定某个方法在Bean实例化完成,依赖关系设置结束后执行;(init-method之前执行)
2. DiposableBean接口           :指定某个方法在Bean销毁之前被执行。(destory-method之前执行)
3. ApplicationContextAware接口 :在实例化Bean时,为Bean注入ApplicationContext
4. BeanNameAware接口           :在实例化Bean时,为Bean注入beanName 
         下面的Person类中定义了Bean自身方法以及Bean级生命周期方法,便于最后进行测试,以观察Person实例的整个生命周期变化。
package com.wj.chapter5.life.all;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * 
 * Bean自身方法
 *  * Bean本身调用的方法
 *  * init-method
 *  * destroy-method
 * 
 * Bean级生命周期接口:
 *  * BeanNameAware           : 在实例化Bean时,为Bean注入beanName
 *  * ApplicationContextAware : 在实例化Bean时,为Bean注入ApplicationContext
 *  * InitializingBean        : 在实例化Bean之前,进行初始化操作
 *  * DisposableBean          : 在销毁Bean之前,进行析构操作
 * @author Administrator
 *
 */
public class Person implements BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean {

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

    private ApplicationContext applicationContext;
    private String             beanName;

    public Person() {
        System.out.println("【Person】【构造器】");
    }
    
    /*********************************** Bean自身方法begin. ************************************/
    
    // 通过<bean>的init-method属性指定的初始化方法
    public void myInit() {
        System.out.println("【Bean自身方法】【init-method】初始化方法...");
    }
    
    // 通过<bean>的destroy-method属性指定的初始化方法
    public void myDestory() {
        System.out.println("【Bean自身方法】【destroy-method】销毁方法...");
    }
    
    public void sayHello() {
        System.out.println("【Bean自身方法】sayHello...");
    }
    
    /*********************************** Bean级生命接口方法begin. ************************************/

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

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

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

    // 这是BeanFactoryAware接口方法
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        System.out.println("【Bean级接口】【ApplicationContextAware接口】注入Spring容器ApplicationContext...");
    }

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

    // 这是InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("【Bean级接口】【InitializingBean接口】初始化方法...");
    }
    
    // 这是DiposibleBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("【DiposibleBean接口】销毁方法...");
    }
    
    @Override
    public String toString() {
        return "Person [name=" + name + ", address=" + address + ", phone=" + phone + ", applicationContext=" + applicationContext + ", beanName=" + beanName + "]";
    }
    
}

 3. 容器级生命周期接口方法

        容器级生命周期接口方法:有InstantiationAwareBeanPostProcessor和BeanPostProcessor这两个接口实现,一般称他们的实现类为后处理器。实现类独立于bean,以容器附加装置的形式注册到spring当中。当spring创建任何bean时,这些后处理器都会发生作用,所以后处理器的影响是全局性的。当然,用户可以通过合理的编写后处理器,让其仅对感兴趣的bean进行加工处理。

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

1. InstantiationAwareBeanPostProcessor接口:此接口可以在Bean实例化前、Bean实例化后分别进行操作,也可以对Bean实例化之后进行属性操作;(为BeanPostProcessor的子接口)
2. BeanPostProcessor接口:此接口的方法可以对Bean的属性进行更改。

         下面分别实现两种容器级接口,首先是InstantiationAwareBeanPostProcessor接口:

package com.wj.chapter5.life.all;

import java.beans.PropertyDescriptor;

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

/**
 * 容器级生命周期接口:
 * InstantiationAwareBeanPostProcessor 接口本质是BeanPostProcessor的子接口,
 * 一般我们继承Spring为其提供的适配器类,InstantiationAwareBeanPostProcessorAdapter来使用它,
 * 此接口可以在Bean实例化前、Bean实例化后分别进行操作,也可以对Bean实例化之后进行属性操作
 */
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

    public MyInstantiationAwareBeanPostProcessor() {
        super();
        System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】【构造器】");
    }

    // 实例化Bean之前调用
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】实例化Bean之前调用");
        return null;
    }

    // 实例化Bean之后调用
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】实例化Bean之后调用");
        return true;
    }

    // 初始化Bean之前调用
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】初始化Bean之前调用");
        return bean;
    }

    // 初始化Bean之后调用
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】初始化Bean之后调用");
        return bean;
    }

    // 设置某个属性时调用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
            String beanName) throws BeansException {
        System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】实例化Bean之后,设置某个属性时调用");
        return pvs;
    }
}
         然后实现BeanPostProcessor接口:
package com.wj.chapter5.life.all;

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

/**
 * 容器级生命周期接口:
 * 此接口的方法可以对Bean的属性进行更改
 */
public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        System.out.println("【容器级接口】【MyBeanPostProcessor实现类】【构造器】");
    }

    // 初始化Bean之前调用
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【容器级接口】【BeanPostProcessor实现类】初始化Bean之前调用");
        return bean;
    }

    // 初始化Bean之后调用
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【容器级接口】【BeanPostProcessor实现类】初始化Bean之后调用");
        return bean;
    }
}
         注意:InstantiationAwareBeanPostProcessor接口实际上是BeanPostProcessor的子接口,所以实际开发中用InstantiationAwareBeanPostProcessor接口的适配器类InstantiationAwareBeanPostProcessorAdapter即可。

4. 工厂级生命周期方法

          工厂级生命周期接口方法(BeanFactoryPostProcessor接口的实现类):

package com.wj.chapter5.life.all;

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;

/**
 * 工厂级接口(此接口可用于重写或添加bean的属性值,甚至可以立即初始化Bean)
 * 
 * BeanFactoryPostProcessor可以对bean的定义(配置元数据)进行处理。
 * 也就是说,Spring IoC容器允许BeanFactoryPostProcessor
 * 在容器实际实例化任何其它的bean之前读取配置元数据,并有可能修改它。
 * 如果你愿意,你可以配置多个BeanFactoryPostProcessor。
 * 你还能通过设置'order'属性来控制BeanFactoryPostProcessor的执行次序。
 */
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public MyBeanFactoryPostProcessor() {
        super();
        System.out.println("【工厂级接口】【BeanFactoryPostProcessor实现类】【构造器】");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
        System.out.println("【工厂级接口】【BeanFactoryPostProcessor实现类】Spring容器加载之后,所有Bean实例化之前调用");
        // 重写Person Bean的phone属性
        BeanDefinition bd = arg0.getBeanDefinition("person");
        bd.getPropertyValues().addPropertyValue("phone", "110");
    }
}

 

5. 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-4.3.xsd">
    
    <!-- 定义工厂级生命周期接口. -->
    <bean id="beanFactoryPostProcessor" class="com.wj.chapter5.life.all.MyBeanFactoryPostProcessor"></bean>

    <!-- 定义容器级生命周期接口. -->
    <bean id="beanPostProcessor" class="com.wj.chapter5.life.all.MyBeanPostProcessor"></bean>
    <bean id="instantiationAwareBeanPostProcessor" class="com.wj.chapter5.life.all.MyInstantiationAwareBeanPostProcessor"></bean>
    
    <!-- 定义Bean自身及Bean级生命周期接口. -->
    <bean id="person" class="com.wj.chapter5.life.all.Person" 
            init-method="myInit" 
            destroy-method="myDestory" 
            scope="singleton">
        <property name="name"    value="熊燕子"></property>
        <property name="address" value="南京"></property>
        <property name="phone"   value="60110"></property>
    </bean>
    
</beans>

6. 测试代码

package com.wj.chapter5.life.all;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestMain {
    
    private static final String PATH_XML = "com/wj/chapter5/life/all/applicationContext-all.xml";

    public static void main(String[] args) {
        
        System.out.println("============================== 现在开始初始化容器. ==============================");
        
        ClassPathXmlApplicationContext factory = new ClassPathXmlApplicationContext(PATH_XML);
        System.out.println("\r\n============================== 容器初始化成功. ==============================");
        //得到Preson,并使用
        Person person = factory.getBean("person",Person.class);
        person.sayHello();
        System.out.println(person);
        
        System.out.println("\r\n============================== 现在开始关闭容器! ==============================");
        factory.close();
    }

}

          运行结果为:

        分析上述运行结果,可以发现Person Bean的实例化过程如下:

1. 准备Spring容器
    * 实例化BeanFactoryPostProcessor实现类;
    * 执行BeanFactoryPostProcessor的postProcessBeanFactory修改XML对Bean配置的元信息;
2. 实例化Bean
    * 实例化BeanPostProcessor实现类
    * 实例化InstantiationAwareBeanPostProcessorAdapter实现类
    * InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法,Bean实例化之前调用此方法
    * 调用Person构造器进行初始化
    * InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法,Bean实例化之后调用此方法
    * InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法,可以修改Bean的属性信息(读取BeanFactoryPostProcessor的postProcessBeanFactory方法中修改的XML对Bean的配置的元信息,修改Bean的属性)
3. 注入依赖关系
    * 注入属性:name、address、phone
    * 注入BeanName
    * 注入ApplicationContext
4. 初始化Bean
    * BeanPostProcessor实现类调用接口方法postProcessBeforeInitialization对属性进行更改
    * InstantiationAwareBeanPostProcessor调用postProcessBeforeInitialization方法,初始化Bean之前调用
    * InitializingBean实现类调用afterPropertiesSet()进行Bean的初始化方法
    * 调用<bean>的init-method属性指定的初始化方法
    * BeanPostProcessor实现类接口方法postProcessAfterInitialization对属性进行更改
    * InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法,初始化Bean之后调用
    * 
5. 使用Bean
    * 调用sayHello()方法
    * 打印Person信息(可以发现舒心phone已改为110,和配置文件中不同)
6. 销毁Bean
    * 调用DiposibleBean接口的destory方法
    * 调用<bean>的destroy-method属性指定的销毁方法

 7. 小结

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

       可通过<bean>的init-method和destroy-method属性配置方式为bean指定初始化和销毁的方法,采用这种方式的效果和通过实现InitializingBean,DisposableBean接口所达到的效果是完全相同的,但是采用前者配置方式可以使bean不需要和特定的spring接口绑定。

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

      综上所述,我们认为除非编写一个基于spring之上的扩展框架插件或者子项目之类的东西,否则用户完全可以抛开以上4个bean生命周期的接口类。

      但BeanPostProcessor接口却不一样,它不要求bean去继承它,它可以完全像插件一样注册到spring容器中,为容器提供额外的功能。spring充分利用了BeanPostProcessor对bean进行加工处理(SpringAOP以此为基础)

 

代码下载地址链接:http://pan.baidu.com/s/1gf3mQUR  密码:utv9

 

  • 大小: 83 KB
  • 大小: 101.3 KB
分享到:
评论

相关推荐

    第2章 容器和bean的基本原理1

    【Spring框架技术——容器和bean的基本原理】 Spring框架的核心特性之一是依赖注入(Dependency Injection,简称DI),也称为控制反转(Inversion of Control,简称IoC)。这一特性改变了传统组件调用的方式,使得...

    第四章 在Ioc容器中装配Bean

    Spring IoC容器在装配Bean时还可以应用生命周期回调,例如实现InitializingBean和DisposableBean接口,或者使用@PostConstruct和@PreDestroy注解,可以在Bean的生命周期的特定点执行代码。 除了上述提到的装配方式...

    二、Spring源码分析——BeanFactory

    3. **生命周期管理**:提供bean的初始化和销毁方法调用,允许开发者自定义bean的生命周期行为。 4. **作用域管理**:支持单例(singleton)、原型(prototype)等多种bean的作用域。 5. **配置元数据**:可以读取XML...

    Spring简单模拟Spring容器

    标题中的“Spring简单模拟Spring容器”意味着我们将探讨Spring框架的核心特性——IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入),以及如何通过编程方式模拟Spring容器的工作原理。...

    实例化Spring bean的两种工厂方法

    在Spring框架中,bean的实例化是其核心功能之一,它允许我们管理应用程序中的对象生命周期。本篇将详细探讨两种工厂方法——实例工厂方法和静态工厂方法,用于创建Spring Bean。 首先,我们要理解Spring Bean的概念...

    Spring————面试题库

    BeanFactory还负责bean的生命周期控制,包括初始化和销毁方法的调用。ApplicationContext在BeanFactory的基础上提供了额外的功能,比如国际化文本消息的支持、统一资源文件的读取方式以及监听器中注册的bean事件等。...

    Spring3.1.3 Ioc在Web容器中的建立

    综上所述,"Spring3.1.3 Ioc在Web容器中的建立"涵盖了Spring的核心特性之一——IoC,以及在Web环境下的具体配置和使用方法。这个过程涉及到Spring容器的初始化、bean的定义与依赖注入,以及Web应用的结构配置。通过...

    Spring学习笔记(9)----让Spring自动扫描和管理Bean

    在Spring中,Bean是一个由Spring IoC容器管理的对象,它代表应用程序中的一个组件或服务。Bean可以通过XML配置文件、注解或Java配置类来定义。而自动扫描和管理Bean则是通过注解或配置文件中的包扫描设置实现的。 #...

    Spring Framework 6 中文文档

    文档详细解释了Bean的概念,包括命名规则、作用域、生命周期和初始化方法等。 此外,文档还涵盖了Bean之间的依赖注入、自动装配以及AOP等高级特性,这些内容对于理解和使用Spring框架进行实际开发至关重要。Spring...

    Java EE 框架整合开发⼊⻔到实战——Spring+Spring MVC+MyBatis(微课版)课后习题答案.pdf

    在Spring框架中,IoC容器管理Java对象的生命周期和对象之间的依赖关系。通过IoC,对象被动地接收依赖关系,而不是主动创建或者查找依赖关系,这种模式也被称为依赖注入。Spring通过BeanFactory接口和...

    三、Spring源码分析——ApplicationContext

    总的来说,ApplicationContext作为Spring的核心组件,扮演着应用程序的“大脑”角色,它负责管理和协调整个Spring容器中的Bean。理解并掌握ApplicationContext的工作原理和使用技巧,对于深度开发和优化Spring应用至...

    Spring入门操作代码,bean

    通过定义DAO(Data Access Object)接口和实现,可以设计查询方法,Spring容器会自动管理这些DAO的生命周期,使得在业务逻辑层可以直接调用查询方法。 修改客户信息:更新操作与新增类似,获取需要修改的Customer ...

    小读spring ioc源码(一)——整体介绍

    Spring的扩展性非常强,支持自定义Bean后处理器(BeanPostProcessor)、Bean工厂后处理器(BeanFactoryPostProcessor)等,允许开发者在特定阶段介入Bean的生命周期。 7. **上下文的层次结构** ...

    撸一撸Spring Framework-IoC-BeanDefinition(csdn)————程序.pdf

    一旦BeanDefinition被创建并注册,Spring容器就可以根据这些信息在需要时创建bean实例,并管理它们的生命周期。 总结来说,BeanDefinition是Spring IoC容器的核心组成部分,它封装了bean的所有配置信息,使容器能够...

    spring源码阅读——1.spring-core-3.2.9

    Spring作为Java领域最广泛应用的框架之一,其核心组件包括依赖注入(Dependency Injection,DI)、AOP(面向切面编程)、资源管理、事件处理以及bean的生命周期管理等。这些组件构成了Spring应用程序的基础,使得...

    《spring in action》中文第三版

    这些对象由Spring IoC容器创建、装配以及管理其生命周期。Bean通常是由XML或Java配置类定义的,并且可以通过不同的方式(如构造器注入、setter注入等)进行属性的注入。 ### Bean的定义 Bean的定义包括了Bean的...

    Spring2.5.6源代码分析(一):IOC容器

    在Spring框架中,Bean的生命周期管理也是IoC容器的重要功能。容器可以控制Bean的初始化、销毁,以及中间过程中的各种回调方法。例如,可以通过`@PostConstruct`和`@PreDestroy`注解标记初始化和销毁方法。 此外,...

    Spring基础:IoC容器(2)

    在本篇博文中,我们将深入探讨Spring框架的基础概念,特别是其核心特性——控制反转(Inversion of Control,IoC)容器。IoC容器是Spring框架的基石,它负责管理对象的生命周期和对象间的依赖关系。通过IoC,我们...

    Spring5 源码分析(第 2 版)-某Tom老师

    Tom老师的文档会详细阐述IoC容器是如何实现DI的,包括Bean的生命周期管理、自动装配以及各种类型的Bean定义。 其次,Spring的AOP(面向切面编程)是另一个重要的特性。AOP允许我们在不修改原有业务逻辑的情况下,对...

Global site tag (gtag.js) - Google Analytics