Spring Bean生命周期回调方法

时间:2020-01-09 10:44:30  来源:igfitidea点击:

在Spring框架中,Spring容器负责实例化bean,设置bean属性,连接依赖关系以及管理从实例化到销毁bean的完整bean生命周期。

Spring bean生命周期回调

为了与容器对bean生命周期的管理进行交互,以自定义bean的性质,Spring Framework提供了许多接口,这些接口可以分为以下几类:

  • 生命周期回调

  • ApplicationContextAware和BeanNameAware

  • 其他感知接口

Spring bean生命周期回调方法

Spring框架提供了回调方法,可以将其配置为

1初始化bean之后,即发布初始化回调方法。
2在销毁Bean之前,即销毁前的回调方法。

在Spring bean生命周期中,初始化后的回调方法是

  • InitializingBean回调接口提供了afterPropertiesSet()方法,可用于初始化工作。

  • 用@PostConstruct注释的方法

  • 自定义init()方法

在Spring bean生命周期中,销毁前的回调方法是

  • DisposableBean回调接口提供了destroy()方法,当包含它的容器被销毁时,该方法可使bean获得回调。

  • 用@PreDestroy注释的方法

  • 自定义destroy()方法

Spring bean生命周期回调方法执行顺序

如果为同一个bean配置了多个生命周期回调,则将调用不同的初始化方法,如下所示:

1.用@PostConstruct注释的方法
2.由InitializingBean回调接口定义的afterPropertiesSet()
3.自定义配置的init()方法

销毁方法按以下顺序调用:

1.用@PreDestroy注释的方法
2. DisposableBean回调接口定义的destroy()
3.一个自定义配置的destroy()方法

在设置bean属性之后但在初始化回调(如InitializingBean或者自定义init-method)之前,调用ApplicationContextAware和BeanNameAware接口的回调。

InitializingBean和DisposableBean回调接口

org.springframework.beans.factory.InitializingBean接口在afterPropertiesSet()之后有一个方法。通过实现此方法,我们提供了一个初始化后回调方法,该方法使容器在容器上设置了所有必需的属性后,bean可以执行初始化工作。

org.springframework.beans.factory.DisposableBean接口具有单个方法destroy()。通过实现此方法,我们提供了销毁前回调方法,该销毁方法在包含bean的容器被销毁时被调用。

根据Spring文档,不建议使用InitializingBean和DisposableBean回调接口,因为它不必要地将代码耦合到Spring。应该首选使用注释@PostConstruct和@PreDestroy或者自定义init()和destroy()方法。

InitializingBean和DisposableBean接口示例

在示例中,有一个OrderServiceImpl类,它依赖于Store。 OrderServiceImpl类实现InitializingBean和DisposableBean接口,并提供回调方法。

public interface OrderService {
	public void buyItems();
}
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

public class OrderServiceImpl implements OrderService, InitializingBean, DisposableBean {
  private IStore store;
  @Autowired
  public OrderServiceImpl(IStore store){
      this.store = store;
  }
  // post initialization callback
  public void afterPropertiesSet() throws Exception {
    System.out.println("In afterPropertiesSet method for bean initialization work");
  }
  // pre destruction callback
  public void destroy() throws Exception {
    System.out.println("In destroy() method, cleaning up resources");
  }
  public void buyItems() {
    store.doPurchase();
  }
}
public interface IStore {
	public void doPurchase();
}
public class RetailStore implements IStore {
	public void doPurchase() {
		System.out.println("Doing purchase from Retail Store");
	}
}

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"
      xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd">
    
  <context:annotation-config />
  <!-- Store bean -->
  <bean id="store" class="com.theitroad.springproject.service.RetailStore" />

  <!-- OrderServiceImpl bean with store bean dependency -->
  <bean id="orderBean" class="com.theitroad.springproject.service.OrderServiceImpl" />
</beans>

我们可以将以下类与main方法一起使用以读取配置并调用bean方法。

public class App {
  public static void main( String[] args ){
    // create context using configuration
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
    OrderService order = context.getBean("orderBean", OrderServiceImpl.class);
    order.buyItems();
    context.close();
  }
}

输出:

10:58:24.120 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
10:58:24.128 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
10:58:24.156 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'store'
10:58:24.187 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderBean'
10:58:24.287 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'orderBean' via constructor to bean named 'store'
In afterPropertiesSet method for bean initialization work
Doing purchase from Retail Store
In destroy() method, cleaning up resources

从输出中可以看到,在调用afterPropertiesSet()回调方法之后,实例化了第一个bean,并连接了依赖项。那时关闭容器时,将在bean上调用destroy()方法。

Spring bean生命周期中的自定义init和destroy方法

我们还可以使用元素的init-method和destroy-method属性配置自定义init和destroy回调方法。

例如

<bean id="orderBean" class="com.theitroad.springproject.service.OrderServiceImpl" 
	      init-method="initMethod" destroy-method="destroyMethod" />

默认的初始化和销毁方法

我们还可以全局配置自定义init并销毁回调方法,以使用in元素定义的所有bean都被调用。这样,我们无需使用每个bean定义来配置init并销毁属性。同时,对于每个bean类中的后期初始化和销毁,我们确实需要具有相同的方法名称。

例如

<beans default-init-method="init" default-destroy-method="destroy">
  <bean id="orderBean" class="com.theitroad.springproject.service.OrderServiceImpl" 
    <property name="store" ref="storeBean" />
  </bean>
  <bean>.....</bean>
  ....
  ....
</beans>

Spring bean生命周期中的@PostConstruct和@PreDestroy注释

用@PostConstruct注释的方法被认为是后初始化方法,其中用@PreDestroy注释的方法被认为是预破坏方法。

Spring bean生命周期回调方法示例

在此示例中,我们将看到三种初始化和一次性方法的全部使用,我们可以通过它们检查这些方法的调用顺序。

请注意,使用@PostConstruct和@PreDestroy注释需要javax注释API。我们需要为此从Java 9开始添加依赖项。

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

这是一类具有所有类型的初始化和一次性方法的类。

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class OrderServiceImpl implements OrderService, InitializingBean, DisposableBean {
  private IStore store;
  @Autowired
  public OrderServiceImpl(IStore store){
    this.store = store;
  }
  // post initialization callback
  public void afterPropertiesSet() throws Exception {
    System.out.println("In afterPropertiesSet method for bean initialization work");
  }
  // pre destruction callback
  public void destroy() throws Exception {
    System.out.println("In destroy() method, cleaning up resources");
  }
  public void initMethod() {
    System.out.println("call init method");
  }
  public void destroyMethod() {
    System.out.println("call destroy method");
  }
  @PostConstruct
  public void initAnnotationMethod() {
    System.out.println("call init method for post construct");
  }
  @PreDestroy
  public void destroyAnnotationMethod() {
    System.out.println("call destroy method for pre destroy");
  }
  public void buyItems() {
    store.doPurchase();
  }
}

输出:

call init method for post construct
In afterPropertiesSet method for bean initialization work
call init method
Doing purchase from Retail Store
call destroy method for pre destroy
In destroy() method, cleaning up resources
call destroy method

如我们所见,首先调用带有@PostConstruct和@PreDestroy注释的方法。之后,调用afterPropertiesSet()和destroy()方法,并在最后一个自定义配置的init()和destroy()方法被调用。

Spring框架中的感知接口

在Spring框架中,有许多Aware回调接口,它们使Bean向容器指示它们需要某种基础结构依赖性。

一些最重要的Aware接口是

  • ApplicationContextAware此接口具有setApplicationContext()方法,该方法将ApplicationContext依赖项注入到Bean中。使用此ApplicationContext参考bean可以以编程方式操纵创建它们的ApplicationContext。

  • BeanNameAware此接口具有setBeanName()方法。为实现org.springframework.beans.factory.BeanNameAware接口的类提供了对其关联对象定义中定义的名称的引用。

  • BeanFactoryAware通过实现此接口,bean将与声明的BeanFactory一起注入。使用它可以获取bean定义及其属性。

  • ServletConfigAware此接口仅在可感知网络的Spring ApplicationContext中有效,并注入运行容器的Current ServletConfig。

  • ServletContextAware此接口仅在可感知网络的Spring ApplicationContext中有效,并注入运行容器的Current ServletContext。

Spring Aware接口示例

在以下示例中,bean类实现ApplicationContextAware,BeanNameAware和BeanFactoryAware接口。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class ExampleBean implements ApplicationContextAware, BeanNameAware, BeanFactoryAware{

  public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    System.out.println("In setBeanFactory method");
    // Getting another bean and calling its method
    OrderService orderService = (OrderService)beanFactory.getBean("orderBean");
    orderService.buyItems();		
  }

  public void setBeanName(String name) {
    System.out.println("In setBeanName method");
    System.out.println("Bean's name- " + name);		
  }

  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    System.out.println("In setApplicationContext");
    OrderService orderService = (OrderService)applicationContext.getBean("orderBean");
    orderService.buyItems();
  }
}

输出:

In setBeanName method
Bean's name- exampleBean
In setBeanFactory method
14:33:52.227 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderBean'
14:33:52.300 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'orderBean' via constructor to bean named 'store'
call init method for post construct
In afterPropertiesSet method for bean initialization work
call init method
Doing purchase from Retail Store
In setApplicationContext
Doing purchase from Retail Store
Doing purchase from Retail Store
call destroy method for pre destroy
In destroy() method, cleaning up resources
call destroy method