Logo

郎哥编程

Spring Bean的生命周期及接口回调

2018-09-05 1337

本篇介绍Spring框架为Spring Bean生命周期各阶段提供的回调接口,程序通过实现回调接口,可以在IOC容器实例化或销毁Bean的过程中,得到Bean的控制权,并对Bean进行预处理工作。通过本篇的学习,可以达成如下目标。

● 了解Spring Bean的生命周期

● 掌握和运用Spring Bean生命周期各阶段提供的接口

● 能够对Spring Bean做预处理工作

Spring Bean虽然由IOC容器管理,不需要程序过多干预。但在一些情况下,程序可能需要在容器之外,对Bean进行一些处理工作。如IOC容器实例化Bean时,程序对Bean进行一些初始化工作,或者IOC容器销毁Bean时,程序对Bean做一些数据的保存或清除工作。

Spring Bean从创建、运行到销毁经历了若干阶段,在Bean生命周期的每个阶段,程序都可以通过初始化回调、在配置文件中声明方法、前置或后置处理等技术获取Bean的控制权,对Bean进行处理工作。Bean生命周期的各个阶段如下图所示。

image.png 

图 1 Spring Bean生命周期

一、回调Aware接口

当Spring IOC容器内的Bean对象实例化完成并且相关属性以及依赖设置完成后,IOC容器会检查当前Bean对象是否实现Aware接口,如果实现了Aware接口,则调用Bean已经实现的Aware接口。Bean通过实现这些接口,可以增强Bean的功能,但是也增加了对Spring容器的依赖。

表 1 可以实现的Aware接口列表

image.png

 

例1:实现BeanNameAware接口

修改课程案例Teacher类,实现BeanNameAware接口。

package com.milihua.springprogram.entity;
import org.springframework.beans.factory.BeanNameAware;
public class Teacher implements BeanNameAware{
private String name;
private String classtime;
 
public String getNotify() {
    return name + "在" + classtime;
}
 
public String getName() {
    return name;
}
 
public void setName(String name) {
    this.name = name;
}
 
public String getClasstime() {
    return classtime;
}
 
public void setClasstime(String classtime) {
    this.classtime = classtime;
}
 
 
@Override
public void setBeanName(String arg0) {
    // TODO Auto-generated method stub
     System.out.println("BeanNameAware:Bean name is" +arg0);  
}
}

setBeanName为实现的接口,接口简单输出bean的名称。运行结果如下图所示。

image.png

 

图 2 Teacher类输出Bean的名称

从输出结果可以看出,Teacher类实现了BeanNameAware接口后,IOC容器将回调Bean实现的BeanNameAware接口的setBeanName方法。

前置处理和后置处理器BeanPostProcessor

前置处理是指程序在Spring IOC容器初始化Bean之前、属性设置之后对该Bean先做一些预处理工作。Spring提供了BeanPostProcessors接口,Bean通过实现该接口的postProcessBeforeInitialization和postProcessAfterInitialization方法,可以在Bean初始化之前或初始化之后做前置处理和后置处理操作。

例2:实现BeanPostProcessor的前置和后置接口

修改课程案例Teacher类,实现postProcessBeforeInitialization前置接口和postProcessAfterInitialization后置接口。

package com.milihua.springprogram.entity;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
 
public class Teacher implements BeanNameAware,BeanPostProcessor{
private String name;
private String classtime;
 
public String getNotify() {
    return name + "在" + classtime;
}
 
public String getName() {
    return name;
}
 
public void setName(String name) {
    this.name = name;
}
 
public String getClasstime() {
    return classtime;
}
 
public void setClasstime(String classtime) {
    this.classtime = classtime;
}
 
@Override
public void setBeanName(String arg0) {
    // TODO Auto-generated method stub
    // System.out.println("BeanNameAware:Bean name is" +arg0);  
}
// Bean 实例化之前进行的处理
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
     
    System.out.println("BeanPostProcessor.postProcessBeforeInitialization 初始化前预处理,开始实例化");
    System.out.println("...........");
    System.out.println("...........");
    System.out.println("...........");
    return bean; 
 
} 
 
// Bean 实例化之后进行的处理
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
         System.out.println("BeanPostProcessor.postProcessAfterInitialization 初始化后预处理,实例化完成"); 
   
    return bean; 
}
}

建立beanpost.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"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.2.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
    <bean id="teacher" scope="prototype" class="com.milihua.springprogram.entity.Teacher">
        <property name="name" value="张老师"></property>
    </bean>
</beans>

建立BeanPostTest类文件。

package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.milihua.springprogram.entity.Teacher;
 
public class BeanPostTest {
 
public static void main(String[] args) {
    // TODO Auto-generated method stub
    ApplicationContext context = new ClassPathXmlApplicationContext("config/beanpost.xml");
    //从容器中获取张老师的实例
    Teacher  teacherZhang = context.getBean("teacher",Teacher.class);
 
}
 
}

执行BeanPostTest类文件,输出结果如下图所示。

image.png

 

图 3 实现BeanPostProcessor接口输出结果

二、回调InitializingBean接口

InitializingBean接口为Bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化Bean的时候会执行该方法。

例3:实现InitializingBean接口

修改课程案例Teacher类,实现InitializingBean接口的afterPropertiesSet方法。

package com.milihua.springprogram.entity;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
 
public class Teacher implements BeanNameAware,BeanPostProcessor,InitializingBean{
private String name;
private String classtime;
 
public String getNotify() {
    return name + "在" + classtime;
}
 
public String getName() {
    return name;
}
 
public void setName(String name) {
    this.name = name;
}
 
public String getClasstime() {
    return classtime;
}
 
public void setClasstime(String classtime) {
    this.classtime = classtime;
}
 
@Override
public void setBeanName(String arg0) {
    // TODO Auto-generated method stub
    // System.out.println("BeanNameAware:Bean name is" +arg0);  
}
// Bean 实例化之前进行的处理
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
     
    System.out.println("BeanPostProcessor.postProcessBeforeInitialization 初始化前预处理,开始实例化");
    System.out.println("...........");
    System.out.println("...........");
    System.out.println("...........");
    return bean; 
 
} 
 
// Bean 实例化之后进行的处理
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
     
    System.out.println("BeanPostProcessor.postProcessAfterInitialization 初始化后预处理,实例化完成"); 
   
    return bean; 
}
 
@Override
public void afterPropertiesSet() throws Exception {
    // TODO Auto-generated method stub
    System.out.println("afterPropertiesSet 正在初始化....."); 
   
}
}

配置init-method方法

在Spring配置文件中,可以使用 init-method 属性来指定带有 void 无参数方法的名称,该方法在Bean实例完成创建后调用。

例4:实现init-method方法

修改beanpost.xml配置文件,在配置文件中添加init-method属性。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.2.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
    <bean id="teacher" init-method="init" scope="prototype" class="com.milihua.springprogram.entity.Teacher">
        <property name="name" value="张老师"></property>
    </bean>
</beans>

修改Teacher类,添加init方法。

//init方法
 public void init() {
          // do some initialization work
        System.out.println("init.......");
 }

执行BeanPostTest文件,输出结果如下图所示。

image.png

 

图 4 配置init-method方法输出结果

从上图可以看出,实现InitializingBean接口的afterPropertiesSet方法首先被调用,然后init方法被调用。

三、回调DisposableBean接口

DisposableBean接口为释放Bean提供了释放资源的方法,它只包括destory方法,凡是继承该接口的类,在释放Bean的时候会执行该方法。

例5:实现DisposableBean接口

修改课程案例Teacher类,实现DisposableBean接口的destroy方法。

package com.milihua.springprogram.entity;
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.beans.factory.config.BeanPostProcessor;
 
public class Teacher implements BeanNameAware,BeanPostProcessor,InitializingBean,DisposableBean{
private String name;
private String classtime;
 
public String getNotify() {
    return name + "在" + classtime;
}
 
public String getName() {
    return name;
}
 
public void setName(String name) {
    this.name = name;
}
 
public String getClasstime() {
    return classtime;
}
 
public void setClasstime(String classtime) {
    this.classtime = classtime;
}
 
@Override
public void setBeanName(String arg0) {
    // TODO Auto-generated method stub
    // System.out.println("BeanNameAware:Bean name is" +arg0);  
}
//init方法
public void init() {
      // do some initialization work
    System.out.println("init.......");
}
// Bean 实例化之前进行的处理
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
     
    System.out.println("BeanPostProcessor.postProcessBeforeInitialization 初始化前预处理,开始实例化");
    System.out.println("...........");
    System.out.println("...........");
    System.out.println("...........");
    return bean; 
 
} 
 
// Bean 实例化之后进行的处理
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
     
    System.out.println("BeanPostProcessor.postProcessAfterInitialization 初始化后预处理,实例化完成"); 
   
    return bean; 
}
 
@Override
public void afterPropertiesSet() throws Exception {
    // TODO Auto-generated method stub
    System.out.println("afterPropertiesSet 正在初始化后....."); 
   
}
 
@Override
public void destroy() throws Exception {
    // TODO Auto-generated method stub
    System.out.println("destroy 正在释放资源....."); 
   
}
}

配置destroy-method方法

在Spring配置文件中,可以使用 destroy-method 属性来指定带有 void 无参数方法的名称,该方法在Bean实例销毁后调用。

例5:实现destroy-method方法

修改beanpost.xml配置文件,在配置文件中添加destroy-method属性。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.2.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<bean id="teacher" destroy-method="destroy_mehtod" init-method="init" scope="prototype" class="com.milihua.springprogram.entity.Teacher">
    <property name="name" value="张老师"></property>
</bean>
</beans>

修改Teacher类,添加destroy_mehtod方法。

// destroy_mehtod方法
    public void destroy_mehtod () {
          // do some initialization work
        System.out.println("destory.......");
}

课程小结

IOC容器创建Bean并设置Bean属性后,将执行以下操作:

(1)检查Aware接口,如果Bean实现了Aware接口,则执行回调;

(2)检查和回调BeanPostProcessor的前置处理接口;

(3)执行Bean的初始化工作,并调用InitializingBean接口,如果在配置文件中Bean定义了init-method属性,则同时调用init-method属性指定的方法;

(4)Bean初始化完成后,IOC容器会调用BeanPostProcessor的后置处理接口;

(5)Bean进入运行阶段;

(6)Bean被销毁时调用DisposableBean接口,如果在配置文件中Bean定义了destroy_mehtod属性,则同时调用destroy_mehtod属性指定的方法。

 

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论