06_Spring Bean的生命周期 BeanPostProcessor接口 init-method 和 destroy-method InitializingBean DisposableBean

Spring Bean的生命周期(作用域singleton 、prototype )

  • Spring 容器可以管理 singleton 作用域 Bean 的生命周期,在此作用域下,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁。

  • prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。
    每次客户端请求 prototype 作用域的 Bean 时,Spring 容器都会创建一个新的实例,并且不会管那些被配置成 prototype 作用域的 Bean 的生命周期。

Bean 生命周期的整个执行过程描述如下。

当一个 Bean 被加载到 Spring 容器时,它就具有了生命,而 Spring 容器在保证一个 Bean 能够使用之前,会进行很多工作。
Spring 容器中 Bean 的生命周期流程

  1. 根据xml配置情况调用 Bean 构造方法或工厂方法实例化 Bean。
  2. 利用依赖注入完成 Bean 中所有属性值的配置注入。
  3. Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。
  4. Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。
  5. Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。
  6. BeanPostProcessor 和 Bean 关联,则 Spring 将==调用该接口的预初始化方法 postProcessBeforeInitialzation() ==对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。
  7. Bean 实现了 InitializingBean 接口,则 Spring 将调用 ==afterPropertiesSet() ==方法。
  8. 在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
  9. BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。
  10. 在 中指定了该 Bean 的作用范围为 scope=“singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为 scope=“prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。
  11. Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

这两个方法很重要(面试经常问): postProcessBeforeInitialzation() afterPropertiesSet()

Spring 为 Bean 提供了细致全面的生命周期过程,通过实现特定的接口或 的属性设置,都可以对 Bean 的生命周期过程产生影响。虽然可以随意配置 的属性,但是建议不要过多地使用 Bean 实现接口,因为这样会导致代码和 Spring 的聚合过于紧密。

init-method 和 destroy-method

安装和拆卸一个 bean,只要声明带有 init-method 和/或 destroy-method 参数的 。

  • init-method 属性指定一个方法,在实例化 bean 时,立即调用该方法。
  • destroy-method 指定一个方法,只有从容器中移除 bean 之后,才能调用该方法。

初始化回调

org.springframework.beans.factory.InitializingBean 接口指定一个单一的方法

void afterPropertiesSet() throws Exception;

1:实现上述接口和初始化工作可以在 afterPropertiesSet() 方法中执行

public class ExampleBean implements InitializingBean {
   public void afterPropertiesSet() {
   }
}

2:基于 XML 的配置元数据的情况下,你可以使用 init-method 属性来指定带有 void 无参数方法的名称。

<bean id="exampleBean"  class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
   public void init() {
   }
}

销毁回调

org.springframework.beans.factory.DisposableBean 接口指定一个单一的方法

void destroy() throws Exception;

1:实现上述接口并且结束工作可以在 destroy() 方法中执行

public class ExampleBean implements DisposableBean {
   public void destroy() {
   }
}

2:基于 XML 的配置元数据的情况下,你可以使用 destroy-method 属性来指定带有 void 无参数方法的名称。

<bean id="exampleBean" class="examples.ExampleBean" destroy-method="destroy"/>
public class ExampleBean {
   public void destroy() {
   }
}

一般不要使用 InitializingBean 或者 DisposableBean 的回调方法,因为 XML 配置在命名方法上提供了极大的灵活性。

默认的初始化和销毁方法

如果有太多具有相同名称的初始化或者销毁方法的 Bean,那么你不需要在每一个 bean 上声明初始化方法和销毁方法。框架使用 元素中的 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-3.0.xsd"
    default-init-method="init" 
    default-destroy-method="destroy">

   <bean id="..." class="..."> </bean>
</beans>

Spring Bean 后置处理器

Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。
  • BeanPostProcessor ​接口定义回调方法,可以实现该方法来提供自己的实例化逻辑,依赖解析逻辑等。也可以在 ​Spring​ 容器通过插入一个或多个 ​BeanPostProcessor​ 的实现来完成实例化,配置和初始化一个​bean​之后实现一些自定义逻辑回调方法。

  • 可以配置多个 ​BeanPostProcessor ​接口,通过设置 ​BeanPostProcessor ​实现的​ Ordered ​接口提供的​ order​ 属性来控制这些​ BeanPostProcessor​ 接口的执行顺序。

  • ​BeanPostProcessor​ 可以对​ bean​(或对象)实例进行操作,这意味着 ​Spring IoC​ 容器实例化一个 ​bean​ 实例,然后 ​BeanPostProcessor​ 接口进行它们的工作。

注意:
​ApplicationContext​ 会自动检测由 ​BeanPostProcessor​ 接口的实现定义的 ​bean​,注册这些​ bean​ 为后置处理器,然后通过在容器中创建​ bean​,在适当的时候调用它。

在你自定义的的​ BeanPostProcessor​ 接口实现类中,要实现以下的两个抽象方法

  • BeanPostProcessor.postProcessBeforeInitialization(Object, String)​
  • BeanPostProcessor.postProcessAfterInitialization(Object, String)​

出现: ​

The type InitHelloWorld must implement the inherited abstract method
BeanPostProcessor.postProcessBeforeInitialization(Object, String)

”​之类的错误。说明postProcessBeforeInitialization和postProcessBeforeInitialization命名要不准确。

示例

HelloWorld类

package com.tutorialspoint;
public class HelloWorld {
   private String message;
   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}

实现​ BeanPostProcessor ​的非常简单的例子,它在任何 ​bean​ 的初始化的之前和之后输入该 ​bean​ 的名称。可以在初始化 ​bean ​的之前和之后实现更复杂的逻辑,因为你有两个访问内置 ​bean​ 对象的后置处理程序的方法。

InitHelloWorld.java

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
public class InitHelloWorld implements BeanPostProcessor {
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("BeforeInitialization : " + beanName);
      return bean;  
   }
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("AfterIntialization : " + beanName);
      return bean;  
   }
}

MainApp.java 需要注册一个在 ​AbstractApplicationContext​ 类中声明的关闭​ hook​ 的 ​registerShutdownHook() ​方法。它将确保正常关闭,并且调用相关的 ​destroy​ 方法。

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();
   }
}

Beans.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-3.0.xsd"><bean id="helloWorld" class="cn.lingyiwin.bean.HelloWorld"
		init-method="init" destroy-method="destroy">
		<property name="message" value="Hello World!" />
	</bean>
	<bean class ="cn.lingyiwin.bean.InitHelloWorld"/></beans>

输出以下信息:

BeforeInitialization : helloWorld
Bean is going through init.
AfterInitialization : helloWorld
Your Message : Hello World!
Bean will destroy now.

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EngineerForSoul

你的鼓励是我孜孜不倦的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值