Spring 提供了一些接口方便用户自定义bean的特性。比如:
- Lifecycle Callbacks
-
ApplicationContextAware
&BeanNameAware
- Other
Aware
Interfaces
一、生命周期回调
为了配合容器管理bean,我们可以实现比如InitializingBean
和DisposableBean
接口,使得容器在初始化和销毁bean时执行指定操作。也可以实现比如LifeCycle
接口使bean参与容器的启动和关闭过程。
1. 初始化回调(Initialization Callbacks)
定义初始化回调可以使容器在创建完bean后执行自定义的初始化回调动作。
方式一:
在代码中实现org.springframework.beans.factory.InitializingBean
接口并重写其afterPropertiesSet()
方法。这种方式使代码与Spring耦合,不推荐使用。
public class AnotherExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
}
}
方式二:
在基于注解的配置中使用@PostConstruct
注解
方式三:
在基于XML的配置中定义init-method
public class ExampleBean {
public void init() {
}
}
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
方式四:
在基于Java的配置中为@Bean
设置initMethod
属性值
2. 销毁回调(Destruction Callbacks)
定义销毁回调可以使bean在容器销毁时执行指定回调操作。
方式一:
在代码中实现org.springframework.beans.factory.DisposableBean
接口并重写其destroy()
方法。
public class AnotherExampleBean implements DisposableBean {
@Override
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
方式二:
在基于注解的配置中使用@PreDestroy
注解
方式三:
在基于XML的配置中定义destroy-method
public class ExampleBean {
public void cleanup() {
}
}
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
方式四:
在基于Java的配置中为@Bean
设置destroyMethod
属性值
3. 默认的初始化和销毁回调
可以通过default-init-method
给需要执行回调的bean统一命名回调方法:
<beans default-init-method="init">
<bean id=xxx, class=xxx > </bean>
<bean id=xxx, class=xxx > </bean>
</beans>
这样需要回调的bean在自己的类定义中实现名称为init()
的方法,就会被容器识别并触发此回调方法;
同理销毁回调使用<beans default-destroy-method="destroy">
4. 组合使用生命周期回调机制
如果同时使用多种方式的生命周期机制,会按照以下顺序执行:
初始化回调的执行顺序:
-
@PostConstruct
标注的方法 - 实现
InitializingBean
时重写的afterPropertiesSet()
方法 - xml中指定的
init()
方法
销毁回调的执行顺序:
-
@PreDestroy
标注的方法 - 实现
DisposableBean
时重写的destroy()
方法 - xml中指定的
destory()
方法
5. 启动&关闭回调(Startup & Shutdown Callbacks)
Spring提供了LifeCycle
接口,使得bean可以实现此接口来启动和停止一些后台处理过程。当ApplicationContext
接收到启动和停止信号时,会委托LifecycleProcessor
接口去调用这些bean的start()
/stop()
方法。
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
LifecycleProcessor
在LifeCycle
接口的基础上扩展了两个方法:
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
注意:
- 实现
LifeCycle
接口并不会实现上下文刷新时自启动。对于想要控制某些特定的bean在自启动(包括启动)阶段的情况,应考虑使用SmartLifeCycle
来代替。 - 容器销毁时并不能保证bean一定能接收到
stop
信号。在容器正常的关闭情况下,生命周期bean会在销毁回调(destruction callback
)执行前收到一个stop
信号,但是当上下文热刷新时,或者尝试终止刷新时,仅仅执行destruction()
回调。
起停执行顺序:
- 对于相互依赖的bean, 依赖先启动后关闭。
- 对于没有明确约定依赖关系的bean, 可以通过
smartLifeCycle
的getPhase()
(SmartLifeCycle
实现了Phase
接口)获取bean的启停阶段。phase越小越先执行启动,越后执行关闭。没有实现smartLifecycle
的bean的phase默认是0
。
SmartLifeCycle
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
SmartLifeCycle
的stop(..)
方法需要传入一个回调。实现此接口的bean会在执行完关闭过程后执行此回调。并且实现SmartLifeCycle
接口的bean对象的isAutoStartup()
若为true,则在LifecycleProcessor
执行onRefresh ()
时,会调用此对象的start()
方法。
这里在源码中查看DefaultLifecycleProcessor
的onRefresh()
方法:
DefaultLifecycleProcessor#startBeans()
由以上方法可以看出上下文刷新时会调用DefaultLifecycleProcessor#startBeans(true)
,在startBean()
方法中遍历所有实现了LifeCycle
接口的bean,如果实现的是SmartLifeCycle
接口并且设置了自启动为true
,则将其放入map
中,通过各个bean定义的起停阶段值分组。再根据顺序依次执行bean的start()
。
二、ApplicationContextAware & BeanNameAware
ApplicationContextAware:
当容器创建了一个实现ApplicationContextAware
接口的对象时,该对象便有了对ApplicationContext
的引用。因此bean可以通过编程操作ApplicationContext
。比如获取一些容器相关的信息:
public class Aware implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext)applicationContext;
configurableApplicationContext.getApplicationName();
configurableApplicationContext.getEnvironment();
}
}
除此之外,还可以通过@Autowired
注解注入ApplicationContext
来对其进行操作:
public class AwareAnotation {
@Autowired
private ApplicationContext applicationContext;
}
BeanNameAware:
当bean实现BeanNameAware
接口时,同理也能获取bean的名称:
public interface BeanNameAware {
void setBeanName(String name) throws BeansException;
}
网友评论