Spring框架本身提供了许多接口,允许用户使用这些接口自定义bean的性质。归结如下:
- 生命周期回调
- ApplicationContextAware 和BeanNameAware
- 其他的Aware 接口
1. 生命周期回调(Lifecycle Callbacks)
1.1 初始化回调
初始化回调可以实现InitializingBean,其中InitializingBean接口只有afterPropertiesSet方法(容器set好所有属性后调用)。但是Spring官方不建议使用InitializingBean接口,因为InitializingBean接口将代码与Spring耦合在了一起,而这是不必要的。建议使用 @PostConstruct注解,或者干脆指定初始化方法。
(1)当指定初始化方法时,代码如下:
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
public void init() {
// do some initialization work
}
}
或
public class BeanOne {
public void init() {
// initialization logic
}
}
public class BeanTwo {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne() {
return new BeanOne();
}
@Bean(destroyMethod = "cleanup")
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
(2)当使用InitializingBean实现同等效果时,代码如下:
public class AnotherExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// do some initialization work
}
}
不过,第一种指定初始化的方式并没有将代码和Spring耦合。
1.2 销毁回调
销毁回调可以实现DisposableBean,其中DisposableBean接口只有destroy方法(容器销毁前调用)。Spring官方依旧不建议使用DisposableBean方法,理由和使用InitializingBean相同,“不必要地”将代码和Spring进行了耦合。建议使用 @PreDestroy或指定bean定义支持的泛型方法。
(1)当指定销毁方法时,代码如下(@Bean(destroyMethod = “cleanup”)见上):
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
(2)当使用DisposableBean实现同等效果时,代码如下:
public class AnotherExampleBean implements DisposableBean {
@Override
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
1.3 初始化/销毁回调的调用顺序
在1.1和1.2中,提到初始化/销毁回调的机制有三种:
- 实现InitializingBean 和DisposableBean
- 自定义/指定init() 和destroy()方法
- 使用注解@PostConstruct 和@PreDestroy
以上三种,可以使用其中一种,也允许多种混合使用。当多种机制进行混合使用,并且每种机制都配置了不同的方法名,那么每个配置的方法都将按照下面列出的顺序运行。但是,如果为多个生命周期机制配置了相同的方法名(例如,机制的初始化方法都叫init()),则该方法只运行一次。
初始化机制调用循序如下:
- 使用@PostConstruct注解的方法
- 实现InitializingBean 的afterPropertiesSet()方法
- 自定义/指定的init()方法
初始化机制调用循序如下:
- 使用@PreDestroy注解的方法
- 实现DisposableBean 的destroy()方法
- 自定义/指定的destroy()方法
1.4 启动和关闭的回调
被Spring管理的对象都可以实现Lifecycle接口(实现启动/关闭)。当ApplicationContext 收到start 或者stop 命令时,它将这些调用级联到该上下文中定义的所有生命周期实现,做法为:会委托给到LifecycleProcessor类,LifecycleProcessor 是对Lifecycle 的扩展,代码如下:
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
而Lifecycle 接口定义如下:
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
常规的org.springframework.context.Lifecycle接口是一个显式的启动和停止通知的简单契约,并不意味着在上下文刷新时自动启动。对于特定bean的自动启动(包括启动阶段)的细粒度控制,可以考虑实现org.springframework.context.SmartLifecycle。
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
SmartLifecycle 除了继承Lifecycle,还继承了Phased 接口,Phased 只有一个方法getPhase(),这个方法主要是给一个启动/关闭的“顺序”。getPhase()的值越小,越早启动,越晚关闭。
public interface Phased {
int getPhase();
}
1.5 非web应用程序中优雅地关闭Spring IoC容器
做法:在ConfigurableApplicationContext 中,调用registerShutdownHook()方法。
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
public static void main(final String[] args) throws Exception {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
// app runs here...
// main method exits, hook is called prior to the app shutting down...
}
}