spring之bean的生命周期

上篇文章中,详细介绍了spring中bean的scope,scope既是bean在spring容器中的存在方式,如prototype和singleton,且也带了一些存在周期的属性,如 session和request等。spring中 bean从实例化,到依赖注入、再到初始化、到最后消亡,有和完整的生命周期。它和scope一起构成bean完整的生命周期。本篇文章主要简单的描述下bean生命周期中的初始化方法(init())和消亡前(ondestroy(),以后称之为析构)的方法。本文主要讨论scope为prototype和singleton的bean,且由于prototype的bean在返回给客户端后,spring不在由spring进行管理,所以其销毁前的方法不会执行。

spring中bean的生命周期简单的如下图所示:

我们可以在生命周期函数中加入自己的一些定制化处理,比如说在初始化阶段,加载相关的资源,启动线程等,在析构阶段释放资源,关闭线程。需要牢记一点,初始化函数是在所有的依赖已经注入后才开始执行的。

生命周期回调

其中中bean的初始化和消亡前主要由以下几种方式:

1.Spring的接口InitializingBean和DisposableBean。示例如下:

/**
   *   InitializingBean 接口从名字可以看出此方法在 bean的属性被spring赋值之后执行,但是和spring的接口耦合在了一起
   */
   @Override
   public void afterPropertiesSet() throws Exception {
      System.out.println(this+" i am  afterPropertiesSet");
   }

   /* *
    * DisposableBean 接口定义的
    */
   @Override
   public void destroy() throws Exception {
      System.out.println(this+" i am  destroy");
   }

2.采用元数据配置,即在bean的定义中配置,如init-method 和destroy-method属性,直接定义相关方法,另外在根标签<beans>可以配置default-init-method 和default-destroy-method 配置默认的 方法,如果<bean>中有定义,则覆盖默认的定义:

<bean id="user0" class="com.test.service.UserServiceIml" init-method="testInit" destroy-method="testBeforeDesstroy">
        <property name="userDao" ref="userDao"></property>
</bean>

/**
   * @Description: 采用元数据配置,在xml中配置
   * @param
   * @return void
   */
   public void testInit(){
      System.out.println(this+" i am  testInit");
   }

   /**
   * @Description: 采用元数据配置,在xml中配置
   * @param
   * @return void
   */
   public void testBeforeDesstroy(){
      System.out.println(this+" i am  testBeforeDesstroy");
   }

3.采用JSR注解

/**
   * @Description: 采用jsr注解
   * @param
   * @return void
   */
   @PostConstruct
   public void testPostConstruct(){
      System.out.println(this+" i am  testPostConstruct");
   }

   /**
   * @Description: 采用JSR的注解
   * @param
   * @return void
   */
   @PreDestroy
   public void testPreDesstroy(){
      System.out.println(this+" i am  testPreDesstroy");
   }

混合机制

以上有三种回调函数实现的方式,他们可以单独使用,也可以混合使用,混合使用的时候,他们的顺序如下:

对于初始化函数:

1.     @PostConstruct 注解的方法

2.     InitializingBean接口定义的回调afterPropertiesSet()

3.     Bean配置中自定义的初始化函数

对于析构则与上相同:

1.     @PreDestroy注解的方法

2.     DisposableBean接口定义的回调destroy()

3.     Bean配置中自定义析构函数

详细的测试见后面。

startUp和shutDown回调

有时候我们可能需要一些组件的功能随着spring容器的启动而启动(如新开启一个线程来进行监听),容器的销毁而销毁。为此spring提供了一个接口,从方法名字很容易看到方法的作用:

public interface Lifecycle {

    void start();

    void stop();

    boolean isRunning();

}

当启动的时候,由于组件之间的依赖,启动的顺序是相当重要的。depends-on属性可以决定多个lifecycle的实现的顺序,但是有时候依赖是未知的。为此spring定义可一个新的接口,SmartLifecycle:

public interface Phased {

    int getPhase();

}

public interface SmartLifecycle extends Lifecycle, Phased {

    boolean isAutoStartup();

    void stop(Runnable callback);

}

isAutoStartup决定是随着容器的启动自启动,Phased接口定义的方法则决定了启动顺序,其返回值越小启动越早,越大启动越晚。如果一个Lifecycle未实现Phased接口,则默认其值为0.

Stop方法可以异步的执行析构函数,spring默认会为每一个Phase等待30秒钟。这个时间是可以配置的。

测试

在非web环境下,要使析构函数执行,需要执行AbstractApplicationContext的registerShutdownHook()方法,见本文的示例:

本测试准备说明以下:

1.     混合生命周期回调的执行顺序

2.     LifeCycle也可以看做为周期,其中start方法在初始化函数执行后被调用,stop方法在析构函数执行前被调用。Prototype 不会被调用start和 stop方法

3.     Depend-on决定bean加载的顺序

4.     <bean>定义的回调会覆盖<beans>定义的默认的回调。

代码

以下是测试程序,本程序依赖Spring之容器和配置初识这篇文章中的代码,并对其稍加改动:

代码结构如下:

首先是allbean.xml配置文件:

     <!--使JSR注解生效  -->
    <bean id="postsss" class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
   <!-- 也可以使用这个配置  使JSR生效  <context:annotation-config/> -->

   <!-- 改变在容器关闭阶段,smartlifecycle 每个阶段    等待的时间 -->
      <bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
    <!-- timeout value in milliseconds -->
    <property name="timeoutPerShutdownPhase" value="3000"/>
   </bean>
    <import resource="com/test/dao/dao.xml"/>

    <import resource="com/test/service/service.xml"/>

然后是service.xml

<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"
        default-init-method="init"
        default-destroy-method="close"
        >

    <!-- 配置自己的初始化和析构,覆盖默认配置 -->
    <bean id="user0" class="com.test.service.UserServiceIml" init-method="testInit" destroy-method="testBeforeDesstroy">
        <property name="userDao" ref="userDao"></property>
    </bean>
     <!-- 采用默认配置的初始化和析构 -->
     <bean id="user1" class="com.test.service.UserServiceIml">
        <property name="userDao" ref="userDao"></property>
    </bean>

     <!-- 配置scope为 prototype,测试只执行初始化函数,不执行析构 -->
     <bean id="user2" class="com.test.service.UserServiceIml" scope="prototype">
        <property name="userDao" ref="userDao"></property>
    </bean>

     <!-- 以下测试 depend-on -->
    <bean id="t1" class="com.test.service.Test1" depends-on="t2">
    </bean>

       <bean id="t2" class="com.test.service.Test2" >
    </bean>

</beans>

然后是UserServiceIml实现了相关的接口,使用了jsr注解和实现了bean中配置的初始化和析构函数:

package com.test.service;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.SmartLifecycle;

import com.test.bo.User;
import com.test.dao.UserDao;

/**
 *实现类,有个字段引用了UserDao接口,其具体的业务逻辑调用  {@link UserDao#getUser()}实现
 *
 *且有一个set方法,此set方法由spring 容器注入使用,如果没有回报错,
 *这是spring容器依赖注入的一种方法--setter注入
 */
public class UserServiceIml implements UserService,InitializingBean,DisposableBean,SmartLifecycle{

   private volatile boolean isRunning = false;
   private UserDao userDao;
   @Override
   public List<User> getUser() {
      return userDao.getUser();
   }
   public void setUserDao(UserDao userDao) {
      this.userDao = userDao;
      System.out.println(this+" i am  setMethod");
   }

   /**
   *   InitializingBean 接口从名字可以看出此方法在 bean的属性被spring赋值之后执行,但是和spring的接口耦合在了一起
   */
   @Override
   public void afterPropertiesSet() throws Exception {
      System.out.println(this+" i am  afterPropertiesSet");
   }

   /* *
    * DisposableBean 接口定义的
    */
   @Override
   public void destroy() throws Exception {
      System.out.println(this+" i am  destroy");
   }

   /**
   * @Description: 采用jsr注解
   * @param
   * @return void
   */
   @PostConstruct
   public void testPostConstruct(){
      System.out.println(this+" i am  testPostConstruct");
   }

   /**
   * @Description: 采用JSR的注解
   * @param
   * @return void
   */
   @PreDestroy
   public void testPreDesstroy(){
      System.out.println(this+" i am  testPreDesstroy");
   }

   /**
   * @Description: 采用元数据配置,在xml中配置
   * @param
   * @return void
   */
   public void testInit(){
      System.out.println(this+" i am  testInit");
   }

   /**
   * @Description: 采用元数据配置,在xml中配置
   * @param
   * @return void
   */
   public void testBeforeDesstroy(){
      System.out.println(this+" i am  testBeforeDesstroy");
   }

   public void init(){
      System.out.println(this+" i am  init");
   }

   public void close(){
      System.out.println(this+" i am  close");
   }

   @Override
   public boolean isRunning() {
      returnisRunning;
   }

   @Override
   public void start() {
      System.out.println(this+"spring容器启动啦");
      isRunning = true;
   }

   /**
   *
   */
   @Override
   public void stop() {
      System.out.println(this+"spring容器关闭啦");
      isRunning = false;
   }

   @Override
   public int getPhase() {
      return 0;
   }

   @Override
   public boolean isAutoStartup() {
      return true;
   }

   @Override
   public void stop(Runnable arg0) {
      arg0.run();
      isRunning = false;
      System.out.println(this+"  this is stop");
   }
}

主程序:

public class TestMain {
   public static void main(String[] args) {

      AbstractApplicationContext  context = new ClassPathXmlApplicationContext("allbean.xml");
      context.registerShutdownHook();

UserService userService0 = context.getBean("user0", UserService.class);
      System.out.println(userService0.getUser());
      System.out.println("--------------user1采用默认的初始化函数--------------");
//
      UserService userService1 = context.getBean("user1", UserService.class);
//
      System.out.println(userService1.getUser());
//
      UserService userService2 = context.getBean("user2", UserService.class);
//
      System.out.println(userService2.getUser());

   }

}

测试结果

以上测试结果就不分析了。需要注意的的上面的测试结果第一行由于截图的关系空缺了。

结束语

Bean的生命周期spring是采用beanpostProcessor(称之为spring扩展点)来进行管理和扩展的,spring定义了很多内置的beanpostProcessor,它们的一些回调在bean的实例化(这里指返回客户端调用前,而不是new)过程中被调用,且如果bean实现了一些aware接口(如ApplicationContextAware 和 beanNameAwre

),这些接口的回调也会进入到生命周期中,这里暂且不讨论。见文章:http://developer.51cto.com/art/201104/255961.htm。而且,spring广泛采用代理机制,需要注意的是 生命周期函数运行在代理创建之前。本文的测试代码下载:本文代码完整下载

时间: 2024-11-02 23:40:02

spring之bean的生命周期的相关文章

Spring中Bean的生命周期

Spring中Bean的生命周期过程: 1.Spring对Bean进行实例化(相当于程序中的new Xx()) 2.Spring将值和Bean的引用注入进Bean对应的属性中 3如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()方法 (实现BeanNameAware清主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有在Bean的ID的) 4.如果Bean实现了BeanFactoryAware接口,Spring将调用se

JAVA面试题:Spring中bean的生命周期

Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象使用Singleton模式产生单一实例,对单线程的程序说并不会有什么问题,但对于多线程的程序,就必须注意安全(Thread-safe)的议题,防止多个线程同时存取共享资源所引发的数据不同步问题. 然而在spring中 可以设定每次从BeanFactory或Appl

Spring:Spring中bean的生命周期

Spring中,从BeanFactory或ApplicationContext取得的实例为Singleton(单例模式),就是预设为每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象使用Singleton模式产生单一实例,对单线程的程序说并不会有什么问题,但对于多线程的程序,就必须注意安全(Thread-safe)的议题,防止多个线程同时存取共享资源所引发的数据不同步问题. 然而在spring中 可以设定每次从BeanFactory或ApplicationContext指定别名并

深究Spring中Bean的生命周期

一.Bean 的完整生命周期 在传统的Java应用中,bean的生命周期很简单,使用Java关键字 new 进行Bean 的实例化,然后该Bean 就能够使用了.一旦bean不再被使用,则由Java自动进行垃圾回收. 相比之下,Spring管理Bean的生命周期就复杂多了,正确理解Bean 的生命周期非常重要,因为Spring对Bean的管理可扩展性非常强,下面展示了一个Bean的构造过程 Bean 的生命周期 如上图所示,Bean 的生命周期还是比较复杂的,下面来对上图每一个步骤做文字描述:

深入剖析Spring(三)——Bean的生命周期

对于普通的Java对象,当new的时候创建对象,当它没有任何引用的时候被垃圾回收机制回收.而由Spring IoC容器托管的对象,它们的生命周期完全由容器控制.Spring中每个Bean的生命周期如下: 1. 实例化Bean 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化. 对于ApplicationContext容器,当容器启动结束后,便实例化所有的bean. 容器通

Spring中Bean的生命周期方法

Bean的生命周期方法 src\dayday\Car.java package dayday; import com.sun.org.apache.xpath.internal.SourceTree; import javax.sound.midi.Soundbank; /** * Created by I am master on 2016/11/28. */public class Car { private String name; public void setName(String n

Spring的Bean的生命周期以及Bean的后置处理器

Bean的生命周期: Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务. Spring IOC 容器对 Bean 的生命周期进行管理的过程: 1通过构造器或工厂方法创建 Bean 实例 2为 Bean 的属性设置值和对其他 Bean 的引用 3调用 Bean 的初始化方法(可以人为指定,利用Bean标签的inti-method属性指定初始化方法,不指定就默认忽略这步骤) Bean 可以使用了 4当容器关闭时, 调用 Bea

Spring -- spEL&amp;Bean的生命周期&amp;工厂方法配置Bean

对于学习spring有帮助的网站:http://jinnianshilongnian.iteye.com/blog/1482071 Spring表达式语言:SpEL Spring 表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言. 语法类似于 EL:SpEL 使用 #{-} 作为定界符,所有在大框号中的字符都将被认为是 SpEL SpEL 为 bean 的属性进行动态赋值提供了便利 通过 SpEL 可以实现: 1.通过 bean 的 id 对 bean 进行引用 2

Spring中Bean的生命周期解读

Spring容器中的Bean拥有明确的生命周期,由多个特定的生命阶段组成,每个生命阶段都允许外界对Bean施加控制.在Spring中,我们从Bean的作用范围和实例化Bean时所经历的一系列阶段来描述Bean的生命周期: BeanFactory中的Bean的生命周期 简单可分为三类 1.Bean自身的方法 (调用Bean的构造函数实例化Bean,调用setter方法设置Bean的属性值,以及通过配置文件当中的Bean的Init-method和Destory-method方法) 2.Bean生命周