当使用术语“生命周期”时,Spring的家伙指的是您的bean的构造和破坏,通常这与Spring Context的构造和破坏有关。 在某些情况下,Bean生命周期的管理不是一件容易的事,因为需要它执行自己的内部设置。 当您的bean必须与外部系统进行交互时,通常包括:加载文件,打开套接字或从数据库中读取一些数据,这通常是正确的。 它到底有什么关系,要解决这个问题,您所需要的只是让Spring在加载Spring Context并将其关闭时调用您的bean。
为此,Spring提供了三种在初始化和关闭期间调用代码的方式。 这些是:
- 以编程方式,通常称为“接口回调”。
- 以每个bean为基础进行声明,称为“方法回调”。
- 通过对所有bean应用相同的默认方法回调进行声明。
接口回调是我之前所描述的。 但是,为了总结该技术并确保Spring在设置和删除Spring Context期间调用您的bean,您的bean必须实现特定的接口。 在初始化的情况下,它是InitializingBean
;在关闭的情况下,它是DisposableBean
。 如果您需要更多有关这些技术的知识,那么这里是有关InitializingBean
的博客和有关DisposableBean
的博客 。
我实际上认为“方法回调”这个名称有些误导,因为它并未真正描述正在发生的事情。 使用方法回调时,您正在做的是将方法添加到bean中,然后在XML配置中引用该方法。 当Spring读取配置文件时,它会发现有一个类型为X的bean,其中有一个方法需要在启动时调用,而另一个方法则需要在关闭时调用。
现在我们需要一个方案,并且因为使用bean回调方法的原因之一是您可以初始化外部系统,所以我建议您正在为一家直销公司工作,并且已经获得编写其中一个烦人的应用程序的工作,该应用程序在半夜拨打随机数字并向接收方播放一条记录的消息,告诉接收方如何通过起诉某家公司来获得意外伤害赔偿(又名现金)他们从未有过。
这个想法是Dialer是一个外部系统,您必须为其编写控制器。 当控制器启动时,它必须连接至拨号器,而在其关闭时,请断开连接。
/*** Dial the number** @param phoneNumber* the phone number as a string* @return true if the number is dialed successfully*/public boolean dial(String phoneNumber);/*** Play a message*/public void playMessge();/*** Hang up the line...*/public boolean hangUp();
DialerController
由上面的接口定义,并且您可以期望它具有一些电话类型的方法,例如playMessage()
dial(...)
, playMessage()
和hangUp()
。 接下来要做的是创建一个实现这些方法的bean,我将在下面完成。
@Component
public class DialerControllerImpl implements DialerController {private boolean connected;@Overridepublic boolean dial(String phoneNumber) {boolean retVal = false;if (isMiddleOfTheNight()) {testConnection();System.out.println("Dialing number: " + phoneNumber);retVal = true;}return retVal;}private boolean isMiddleOfTheNight() {return true;}@Overridepublic void playMessge() {testConnection();System.out.println("Hello, do not hang up you may be entitled to...");}@Overridepublic boolean hangUp() {testConnection();System.out.println("Hangup!");return true;}public void init() {connected = true;System.out.println("Connect to dialer");}public void destroy() {connected = false;System.out.println("Close connection to dialer");}private void testConnection() {if (connected == false) {throw new RuntimeException("Not connected to external system error");}}
}
playMessage()
dial(...)
, playMessage()
和hangUp()
方法没什么特别的; 他们检查Bean是否已连接到它正在对接的外部拨号程序,然后执行其工作。 此类的有趣之处在于init()
和destroy()
方法,因为这是我们希望Spring在启动和关闭期间分别调用的方法。
为了确保Spring确实调用了我们的bean,我们需要在Spring配置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.1.xsd"><bean id="dialerController" class="example_2_lifecycle_management.method_based.DialerControllerImpl" init-method="init" destroy-method="destroy" /></beans>
在此示例中,我使用了显式的bean配置(这意味着您可以忽略上面代码中的@Component
属性,因为它目前尚未使用,但稍后需要使用),并且需要注意的是bean配置附加属性init-method
和destroy-method
。 这些用于定义Spring初始化和关闭时要调用的bean方法的名称。 在此示例中,它们对应于上面DialerControllerImpl
类中的init()
和destroy()
方法。
@Testpublic void testLifeCycle_using_per_bean_declaration() {ctx = new ClassPathXmlApplicationContext("dialer.xml");ctx.registerShutdownHook();instance = ctx.getBean(DialerControllerImpl.class);if (instance.dial("555-1234")) {instance.playMessge();instance.hangUp();}}
上面的代码演示了运行代码的简单单元测试(这不是真正的测试,因为它没有声明任何内容)。 这里要注意的要点是,在创建Spring Application Context之后,我添加了一个调用
registerShutdownHook()
。 这是因为您需要告诉JVM告诉Spring调用您的destroy()
方法。 就像我在DisposableBean
博客中所做的那样,您可以自己创建和处理shutdown钩子,有时这样做有很多好处,但在以后的日子里,还会有更多好处。
我现在听到的问题是“如果我使用自动装配会怎样?” 事实证明,Spring的Guys在Spring 3.1中添加了一种新的声明性方法回调技术,称为“默认方法回调”。 这里的一个大想法是,您在XML配置文件顶部的<beans/>
元素中声明初始化和关闭方法的名称,如下所示:
<?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-3.1.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"default-init-method="init" default-destroy-method="destroy"><!-- Enable autowiring --><context:component-scan base-package="example_2_lifecycle_management.method_based" />
</beans>
选择bean生命周期技术时,请记住Spring专家建议您选择基于方法的回调而不是基于接口的回调。 原因是在选择接口回调路由时,您将bean绑定到了Spring。 这可能是(也可能不是)问题,而这实际上取决于您的应用程序的其余部分,因为使用其他许多Spring技术也会将您的应用程序绑定到Spring。
参考: Spring框架: Captain Debug博客博客中来自JCG合作伙伴 Roger Hughes的三种Spring Bean生命周期技术 。
翻译自: https://www.javacodegeeks.com/2013/02/spring-framework-three-spring-bean-lifecycle-techniques.html