本篇思考:
- 当 bean 初始化完成之后,执行某个方法,应该如何做?
- 当容器初始化完成之后,执行某个方法,应该如何做?
生命周期回调,对于程序员来说,生命周期这个词肯定不会陌生,生命周期回调,也就是在某一个时刻,当触发了生命周期种的某个点时,及时通知我们程序员是否需要做一些处理或业务,这就是生命周期回调
对于 spring 来说,说到生命周期,会有两个生命周期,一个是 bean 的生命周期,一个是容器的生命周期,那么回调也就会有两种情况,一个是 bean 的生命周期回调,一个是容器的生命周期回调
bean 的生命周期回调
对于 bean 的生命周期回调来说,有 bean 初始化后回调(Initialization Callbacks)和 bean 销毁前回调(Destruction Callbacks),这里我们要注意一下,我说的是 bean 并没有说对象,bean 和对象的含义,这里就不再解释了。
bean 的生命周期回调方法
生命周期回调方法在属性注入(populateBean)之后,开始执行,也就是说,bean 初始化回调时,所有的属性都已经填充完毕,可以正常使用这些属性完成某些特定业务,我们可以从源码的角度看出时在 populateBean 之后执行的 initializeBean 方法,这个方法中处理了 @PostConstruct 方法
// Initialize the bean instance.
Object exposedObject = bean;
try {
// ★★★ 关键代码:填充属性,也就是我们常常说的自动注入
// 里面会完成第五次,第六次的后置处理器的调用
populateBean(beanName, mbd, instanceWrapper);
// ★★★ 初始化 spring,开始执行生命周期回调参数
// 从这里可以看出,是将数据填充完毕后,开始执行生命周期回调方法
// 关键代码:里面会完成第七次、第八次的后置处理器调用
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
那么如何实现 bean 的生命周期回调呢?
以下引用 spring 官方文档,1.6.1. Lifecycle Callbacks
- The
InitializingBean
andDisposableBean
callback interfaces - Custom
init()
anddestroy()
methods - The
@PostConstruct
and@PreDestroy
annotations. You can combine these mechanisms to control a given bean.
从官方文档来看,有三种方式可以实现(推荐使用注解),但是最后有一句话是 You can combine these mechanisms to control a given bean.,也就是说,你可以组合以上三种回调机制来控制 bean
那么问题来了,如果我组合了多个生命周期方法,那么顺序是应该怎么执行呢?
**
我们继续在官网中寻求答案
以下引用 spring 官方文档,Combining Lifecycle Mechanisms
If multiple lifecycle mechanisms are configured for a bean and each mechanism is configured with a different method name, then each configured method is executed in the order listed after this note. However, if the same method name is configured — for example, init() for an initialization method — for more than one of these lifecycle mechanisms, that method is executed once, as explained in the preceding section. |
---|
Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows:
- Methods annotated with
@PostConstruct
afterPropertiesSet()
as defined by theInitializingBean
callback interface- A custom configured
init()
method
Destroy methods are called in the same order:
- Methods annotated with
@PreDestroy
destroy()
as defined by theDisposableBean
callback interface- A custom configured
destroy()
method
按照官方的给的解释,首先执行 @PostConstruct 标记的方法,再执行 InitializingBean 接口的 afterPropertiesSet() 方法,最后执行 XML 中自定义的 init-method 方法,我们也源码来证明一下上述理论。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 省略代码无数...
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 执行 spring 当中的后置处理器
// ★ 如果生命周期回调是 @PostConstruct,则会在这里执行
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 执行 InitializingBean 接口
// ★ 如果生命周期的回调,是实现了 InitializingBean 或 init-method 则会在这里执行
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 开始执行对象的代理(AOP)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// ★ 执行直接实现了 BeanPostProcessor 的实现类的 postProcessBeforeInitialization 方法
// 这里处理生命周期方法的实现类是 CommonAnnotationBeanPostProcessor 类的 postProcessMergedBeanDefinition 方法
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// ★ 这里执行了 InitializingBean 的 afterPropertiesSet 方法
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// ★ 这里执行了 XML 配置中自定义的 init-method 方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
非常棒!完美的验证了官网的解释
容器的生命周期回调(SmartLife)
这里的容器指的就是 context,如果时注解就是 AnnotationConfigApplicationContext,如果时 XML 就是 ClassPathXmlApplicationContext
以下引用 spring 官方文档,Startup and Shutdown Callbacks
The Lifecycle
interface defines the essential methods for any object that has its own lifecycle requirements (such as starting and stopping some background process):
Any Spring-managed object may implement the Lifecycle
interface. Then, when the ApplicationContext
itself receives start and stop signals (for example, for a stop/restart scenario at runtime), it cascades those calls to all Lifecycle
implementations defined within that context. It does this by delegating to a LifecycleProcessor
, shown in the following listing:
意思是说,容器的生命周期接口可以实现一些在容器启动或停止时进行一些必要操作,任何 spring 管理的bean 都可以实现 Lifecycle 接口,此时就可以通过接口提供的一些方法来接收容器启动和停止的信号
容器的生命周期回调方法
容器的生命周期回调,也分为启动(start)和停止(stop),但是基于容器的回调,需要判断容器时否正在运行(isRunning),也就是说在调用 start 方法的时候,必须修改 isRunning 的值为 true,表示容器已经启动,在调用 stop 方法的时候,也需要判断 isRunning,如果 isRunning= true,就会调用停止方法,反之则不会调用,这样我们可以看出来,基于容器的生命周期方法调用,依赖于 isRunning 开关
@Component
public class Life implements Lifecycle {
private boolean isRunning = false;
// 容器启动完就会调用:isRunning = true
@Override
public void start() {
System.out.println("start");
isRunning = true;
}
// 容器停止就会调用:isRunning = false
@Override
public void stop() {
System.out.println("stop");
isRunning = false;
}
// start 和 stop 的调用前提
@Override
public boolean isRunning() {
return isRunning;
}
}
而调用 start 的方法,必须显式的通过 context 进行调用
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
// 必须显式的调用 start 方法
ac.start();
}
这样看来这个 Lifecycle 接口就非常的鸡肋了,那么有没有智能一点的容器生命周期调用方法呢?
还有一个接口叫 SmartLifecycle,见名知意,这个接口时聪明的生命周期回调,那么聪明在什么地方呢?没错,不需要我们手动调用 ac.start() 方法,但是需要一些配置,我们需要把 isAutoStartup 的值修改为 true,表示允许自动调用;还有一个 getPhase 方法,返回一个 int 数据,表示优先级的意思,返回值越小,表示启动顺序越先执行,停止顺序越后执行;最后一个方法 stop(Runnable callback),当我们实现了 SmartLifecycle 接口时,当容器停止时,就会调用 stop(Runnable callback) 这个方法,而不会在调用 stop() 方法了
@Component
public class SmartLife implements SmartLifecycle {
// 是否自动调用
@Override
public boolean isAutoStartup() {
return true;
}
@Override
public void stop(Runnable callback) {
System.out.println("smart callback stop");
}
// 优先级,如果有多个生命周期监控
// 启动时,值越小,优先级越高
// 停止时,值越大,优先级越高
@Override
public int getPhase() {
return 0;
}
@Override
public void start() {
System.out.println("smart start");
}
@Override
public void stop() {
System.out.println("smart stop");
}
@Override
public boolean isRunning() {
return false;
}
}