详解Spring中bean生命周期回调方法

生命周期回调方法

对于spring bean来讲,我们默认可以指定两个生命周期回调方法。一个是在ApplicationContext将bean初始化,包括注入对应的依赖后的回调方法;另一个是在ApplicationContext准备销毁之前的回调方法。要实现这种回调主要有三种方式:实现特定的接口、在XML配置文件中指定回调方法和使用JSR-250标准的注解。

1 实现特定接口

针对bean初始化后的回调和ApplicationContext销毁前的回调,Spring分别为我们了提供了InitializingBean和DisposableBean接口供用户实现,这样Spring在需要进行回调时就会调用对应接口提供的回调方法。

1.1 InitializingBean

InitializingBean是用来定义ApplicationContext在完全初始化一个bean以后需要需要回调的方法的,其中只定义了一个afterPropertiesSet()方法。如其名称所描述的那样,该方法将在ApplicationContext将一个bean完全初始化,包括将对应的依赖项都注入以后才会被调用。InitializingBean的完全定义如下。

public interface InitializingBean {

 void afterPropertiesSet() throws Exception;

}

由于InitializingBean的afterPropertiesSet()方法会在依赖项都进行注入以后再回调,所以该方法通常会用来检查必要的依赖注入,以使我们能够在bean被初始化时就发现其中的错误,而不是在很长时间使用以后才发现。如果你去看Spring的源码,你就会发现源码中有很多InitializingBean的使用,而且基本都是用来检查必要的依赖项是否为空的。

public class Hello implements InitializingBean {

 private World world;

 /**
 * 该方法将在当前bean被完全初始化后被调用
 */
 public void afterPropertiesSet() throws Exception {
 Assert.notNull(world, "world should not be null.");
 }

 public void setWorld(World world) {
 this.world = world;
 }

}

9.1.2 DisposableBean

DisposableBean是用来定义在ApplicationContext销毁之前需要回调的方法的。DisposableBean接口中只定义了一个destroy()方法,在ApplicationContext被销毁前,Spring将依次调用bean容器中实现了DisposableBean接口的destroy()方法。所以,我们可以通过实现该接口的destroy()方法来达到在ApplicationContext销毁前释放某些特定资源的目的。

public interface DisposableBean {

 void destroy() throws Exception;

}

在Spring的源码中,也有很多实现了DisposableBean接口的类,如我们熟悉的ApplicationContext实现类、SingleConnectionDataSource等。

2 在XML中配置回调方法

在XML配置文件中通过bean元素定义一个bean时,我们可以通过bean元素的init-method属性和destroy-method属性来指定当前bean在初始化以后和ApplicationContext销毁前的回调方法。需要注意的是所指定的回调方法必须是没有参数的。

通过init-method属性来指定初始化方法时所对应的方法必须是该bean中所拥有的方法,所以首先我们需要在对应的bean中定义对应的初始化方法,这里假设我们需要在bean中定义一个init()方法作为该bean的初始化方法,那么我们可以对我们的bean进行类似如下定义。

public class Hello {

 private World world;

 /**
 * 该方法将被用来作为初始化方法,在当前bean被完全初始化后被调用
 */
 public void init() {
 Assert.notNull(world, "world should not be null.");
 }

 public void setWorld(World world) {
 this.world = world;
 }

}

接下来就是在XML配置文件中定义该bean时通过init-method属性定义对应的初始化方法为init()方法,init-method属性的属性值就对应初始化方法的名称,所以我们的bean应该是如下定义。

 <bean name="world" class="com.app.World"/>
 <!-- 通过init-method属性指定初始化方法名称 -->
 <bean id="hello" class="com.app.Hello" init-method="init">
 <property name="world" ref="world"/>
 </bean>

init-method和destroy-method的用法和配置等基本上都是一样的,所以对于使用destroy-method来指定ApplicationContext销毁前的回调方法的用法就不再赘述了。

如果我们的初始化方法或销毁方法的名称大都是一样的,在通过init-method和destroy-method进行指定的时候我们就没有必要一个个bean都去指定了,Spring允许我们在最顶级的beans元素上指定默认的初始化后回调方法和销毁前的回调方法名称,这样对于没有指定init-method或destroy-method的bean将默认将其中default-init-method或default-destroy-method属性值对应名称的方法(如果存在的话)视为初始化后的回调方法或销毁前的回调方法。这是通过default-init-method和default-destroy-method属性来定义的。

<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="destroy">

</beans>

以上表示定义默认的初始化后回调方法名称为init,默认的销毁前回调方法名称为destroy。

当定义了default-init-method或default-destroy-method以后,如果我们的某个bean对应的初始化后回调方法名称或销毁前的回调方法名称与默认定义的不一样,则我们可以在对应的bean上通过init-method或destroy-method指定该bean自身的回调方法名称,即bean上定义的回调方法名称将会比默认定义拥有更高的优先级。

3 使用JSR-250标准的注解

关于bean的生命周期回调方法,Spring也会JSR-250标准注解做了支持,即在bean完全初始化后将回调使用@PostConstruct标注的方法,在销毁ApplicationContext前将回调使用@PreDestroy标注的方法。
针对之前的示例,如果我们现在把定义的bean定义成如下这样,即没有在bean上通过init-method和destroy-method指定初始化方法和销毁方法。

 <bean name="world" class="com.app.World"/>
 <bean id="hello" class="com.app.Hello">
 <property name="world" ref="world"/>
 </bean>

当然,这里也不考虑全局性的init-method和destroy-method方法,如果我们希望在id为“hello”的bean被初始化后回调其中的init()方法,在销毁前回调其中的destroy()方法,我们就可以通过@PostConstruct和@PreDestroy进行如下定义。

public class Hello {

 private World world;

 /**
 * 该方法将被用来作为初始化方法,在当前bean被完全初始化后被调用
 */
 @PostConstruct
 public void init() {
 Assert.notNull(world, "world should not be null.");
 }

 @PreDestroy
 public void destroy() {
 System.out.println("---------destroy-----------");
 }

 public void setWorld(World world) {
 this.world = world;
 }

}

使用JSR-250标准指定初始化后的回调方法以及销毁前的回调方法时,如果我们希望将多个方法都作为对应的回调方法进行回调,则可以在多个方法上同时使用对应的注解进行标注,Spring将依次执行对应的方法。

public class Hello {

 private World world;

 @PostConstruct
 public void init() {
 System.out.println("-----------init-------------");
 }

 /**
 * 该方法将被用来作为初始化方法,在当前bean被完全初始化后被调用
 */
 @PostConstruct
 public void init2() {
 Assert.notNull(world, "world should not be null.");
 }

 @PreDestroy
 public void destroy() {
 System.out.println("------------destroy----------------");
 }

 @PreDestroy
 public void destroy2() {
 System.out.println("---------destroy2-----------");
 }

 public void setWorld(World world) {
 this.world = world;
 }

}

4 混合使用三种方式

Spring允许我们混合使用上述介绍的三种方式来指定对应的回调方法。当对于同一个bean使用三种方式指定了同一个方法作为初始化后的回调方法或销毁前的回调方法,则对应的回调方法只会被执行一次。然而,当对于同一个bean使用两种或三种方式指定的回调方法不是同一个方法时,Spring将依次执行使用不同的方式指定的回调方法。对于初始化后的回调方法而言,具体规则如下:

  1. 使用@PostConstruct标注的方法。
  2. 实现InitializingBean接口后的回调方法afterPropertiesSet()方法。
  3. 通过init-method或default-init-method指定的方法。

对于销毁前的回调方法而言,其规则是一样的:

  1. 使用@PreDestroy标注的方法。
  2. 实现DisposableBean接口后的回调方法destroy()方法。
  3. 通过destroy-method或default-destroy-method指定的方法。

(注:本文是基于Spring4.1.0所写)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Spring配置使用之Bean生命周期详解

    基本概念 Spring 中的 Bean 的生命周期,指的是 Bean 从创建到销毁的过程. 下面来探究下几个有关 Bean 生命周期配置的属性. lazy-init lazy-init 表示延迟加载 Bean,默认在 Spring IoC 容器初始化时会实例化所有在配置文件定义的 Bean,若启用了 lazy-init 则在调用 Bean 时才会去创建 Bean. 定义 Bean: public class Animals { public Animals(){ System.out.print

  • 浅谈Spring bean 生命周期验证

    一.从源码注释看bean生命周期 从JDK源码上看,BeanFactory实现类需要支持Bean的完整生命周期,完整的初始化方法及其标准顺序(格式:接口 方法)为: 1.BeanNameAware setBeanName 设置bean名称 2.BeanClassLoaderAware setBeanClassLoader 设置bean类加载器 3.BeanFactoryAware setBeanFactory 设置bean工厂 4.EnvironmentAware setEnvironment

  • 详解Java的Spring框架中bean的定义以及生命周期

    bean的定义 形成应用程序的骨干是由Spring IoC容器所管理的对象称为bean.bean被实例化,组装,并通过Spring IoC容器所管理的对象.这些bean由容器提供,例如,在XML的<bean/>定义,已经看到了前几章的形式配置元数据创建. bean定义包含所需要的容器要知道以下称为配置元数据的信息: 如何创建一个bean Bean 生命周期的详细信息 Bean 依赖关系 上述所有配置元数据转换成一组的下列属性构成每个bean的定义. Spring配置元数据 Spring IoC

  • 详解Spring中Bean的生命周期和作用域及实现方式

    前言 在applicationContext.xml中配置完bean之后,Bean的声明周期状态有哪些.生命周期的各个阶段可以做什么.在applicationContext.xml配置bean的作用域有哪些.其中各个作用域代表的是什么.适用于什么情况.这篇文章做一个记录. 生命周期 初始化 可以直接查看图片,图片来自Spring Bean Life Cycle 从上图看出,Bean初始化完成包括9个步骤.其中一些步骤包括接口的实现,其中包括BeanNameAware接口,BeanFactoryA

  • 深入理解Spring中bean的生命周期介绍

    1.以ApplocationContext上下文单例模式装配bean为例,深入探讨bean的生命周期: (1).生命周期图: (2).具体事例: person类实现BeanNameAware,BeanFactoryAware接口 public class Person implements BeanNameAware ,BeanFactoryAware{ private String name; public Person(){ System.out.println("调用构造器为属性值初始化&

  • Spring Bean的生命周期详细介绍

    Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring容器.这里,我们讲的也是 ApplicationContext中Bean的生命周期.而实际上BeanFactory也是差不多的,只不过处理器需要手动注册. 一.生命周期流程图: Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean,这其中包含了一系列关

  • spring之Bean的生命周期详解

    Bean的生命周期: Bean的定义--Bean的初始化--Bean的使用--Bean的销毁 Bean的定义 Bean 是 spring 装配的组件模型,一切实体类都可以配置成一个 Bean ,进而就可以在任何其他的 Bean 中使用,一个 Bean 也可以不是指定的实体类,这就是抽象 Bean . Bean的初始化 Spring中bean的初始化回调有两种方法 一种是在配置文件中声明init-method="init",然后在一个实体类中用init()方法来初始化 另一种是实现Ini

  • 详解Spring中bean生命周期回调方法

    生命周期回调方法 对于spring bean来讲,我们默认可以指定两个生命周期回调方法.一个是在ApplicationContext将bean初始化,包括注入对应的依赖后的回调方法:另一个是在ApplicationContext准备销毁之前的回调方法.要实现这种回调主要有三种方式:实现特定的接口.在XML配置文件中指定回调方法和使用JSR-250标准的注解. 1 实现特定接口 针对bean初始化后的回调和ApplicationContext销毁前的回调,Spring分别为我们了提供了Initia

  • 详解Spring 中 Bean 的生命周期

    前言 这其实是一道面试题,是我在面试百度的时候被问到的,当时没有答出来(因为自己真的很菜),后来在网上寻找答案,看到也是一头雾水,直到看到了<Spring in action>这本书,书上有对Bean声明周期的大致解释,但是没有代码分析,所以就自己上网寻找资料,一定要把这个Bean生命周期弄明白! ​ 网上大部分都是验证的Bean 在面试问的生命周期,其实查阅JDK还有一个完整的Bean生命周期,这同时也验证了书是具有片面性的,最fresh 的资料还是查阅原始JDK!!! 一.Bean 的完整

  • 详解Spring中Bean的作用域与生命周期

    目录 一.Bean的作用域 二.Bean的生命周期 使用代码演示Bean的生命周期 一.Bean的作用域 通过Spring容器创建一个Bean的实例时,不仅可以完成Bean的实例化,还可以使用Bean的scope属性为bean设置作用域. 语法格式:<bean id="别名" scope="作用域" class="对应实现类"> 作用域的种类:(sing) singleton和prototype区别:(该两种比较常用) ① singl

  • 详解Spring中Bean后置处理器(BeanPostProcessor)的使用

    目录 一.BeanPostProcessor接口 二.案例 三.总结 一.BeanPostProcessor接口 Bean后置处理:对Spring 工厂创建的对象进行二次加工处理,即预初始化和后初始化. PostProcessor中文意思就是后置处理器. BeanPostProcessor 接口也被称为Bean后置处理器,通过该接口可以自定义调用初始化前后执行的操作方法. 该接口中包含了两个方法:before方法(预初始化)和after方法(后厨是化) postProcessBeforeInit

  • 详解Spring中bean的几种注入方式

    首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入.依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖. Spring容器中支持的依赖注入方式主要有属性注入.构造函数注入.工厂方法注入.接下来将为大家详细介绍这三种依赖注入的方式以及它们的具体配置方法. 1.属性注入 属性注入即通过setXXX( )方法注入bean的属性值或依赖对象.由于属性注入方式具有可选择性和灵活性高的特点,因此它也是实际开发中最常用的注入方式

  • 详解Spring中Bean的加载的方法

    之前写过bean的解析,这篇来讲讲bean的加载,加载要比bean的解析复杂些,从之前的例子开始. Spring中加载一个bean的方式: TestBean bean = factory.getBean("testBean"); 来看看getBean(String name)方法源码, @Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, nul

  • 详解Spring中bean实例化的三种方式

    今天我想来说说如何通过xml配置来实例化bean,其实也很简单. 使用xml配置来实例化bean共分为三种方式,分别是普通构造方法创建.静态工厂创建.实例工厂创建,OK,那么接下来我们来分别看看这几种方式. 普通构造方法创建 这种创建方式使我们使用最多的一种创建方式,直接配置bean节点即可,比如我有一个User类,如下: public class User { public void add() { System.out.println("add()---------"); } }

  • 详解Spring中接口的bean是如何注入的

    Question: 这个问题困扰了我好久,一直疑问这个接口的bean是怎么注入进去的?因为只看到使用@Service注入了实现类serviceImpl,使用时怎么能获取的接口,而且还能调用到实现类的方法,难道这个接口是在什么时候自动注入了进去,且和实现类关联上了? 接口 public interface TestService { public String test(); } 实现类impl @Service public class TestServiceImpl implements Te

  • Spring中bean集合注入的方法详解

    目录 Map注入 List注入 Set注入 数组注入 应用 哈喽大家好啊,我是Hydra. Spring作为项目中不可缺少的底层框架,提供的最基础的功能就是bean的管理了.bean的注入相信大家都比较熟悉了,但是有几种不太常用到的集合注入方式,可能有的同学会不太了解,今天我们就通过实例看看它的使用. 首先,声明一个接口: public interface UserDao { String getName(); } 然后定义两个类来分别实现这个接口,并通过@Component注解把bean放入s

随机推荐