有时候我们需要在系统启动后自动执行一些初始化动作,如加载自定义的资源,启动业务相关定时器,或是在bean初始化后执行一些其他的注册动作。这里面有个核心的要素就是方法的执行时机,总结来讲spring里面有两大类的方法执行时机:
- 生命周期回调触发。
spring
事件触发。
通过生命周期回调触发
spring官网中的有对生命周期回调的总结了初始化回调的三种方式:
- Methods annotated with
@PostConstruct
afterPropertiesSet()
as defined by theInitializingBean
callback interface- A custom configured
init()
method,通常用在xml
配置中,在bean标签中配置一个init-method
实现
对应的注销回调的三种方式:
- Methods annotated with
@PreDestroy
destroy()
as defined by theDisposableBean
callback interface- A custom configured
destroy()
method,通常用在xml
配置中,在bean标签中配置一个destroy-method
实现
这三种方式的执行时机如上述的顺序。
PostConstruct
的执行时机
afterPropertiesSet
的执行时机
afterPropertiesSet
是在AbstractAutowireCapableBeanFactory
的initializeBean
中调用的,也就是bean
的实例化流程中的初始化bean的时候,这个时候spring
已经对bean
完成了代理、依赖注入,开始执行一些初始化方法。
具体执行的方法如下,注意启动的invokeInitMethods
,就是调用afterPropertiesSet
的入口,这个方法的执行时机是后置处理器执行postProcessBeforeInitialization
和applyBeanPostProcessorsAfterInitialization
之间。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
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()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
再看看invokeInitMethods
的具体实现
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 (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
}
通过spring事件来触发
这种触发方式是通过使用@EventListener
注解来监听spring发布的事件,收到事件后执行某些业务操作。比如希望spring容器初始化完成后才开始我们的业务逻辑,如下是一个代码示例:
@EventListener(classes = ContextRefreshedEvent.class)
public void enableSchedule() {
this.scheduleFlag = true;
}
spring
官网的1.15.2 standard and custom events
中提到了spring的內建事件,详细介绍如下:
ontextRefreshedEvent |
Published when the ApplicationContext is initialized or refreshed (for example, by using the refresh() method on the ConfigurableApplicationContext interface). Here, “initialized” means that all beans are loaded, post-processor beans are detected and activated, singletons are pre-instantiated, and the ApplicationContext object is ready for use. As long as the context has not been closed, a refresh can be triggered multiple times, provided that the chosen ApplicationContext actually supports such “hot” refreshes. For example, XmlWebApplicationContext supports hot refreshes, but GenericApplicationContext does not. |
---|---|
ContextStartedEvent |
Published when the ApplicationContext is started by using the start() method on the ConfigurableApplicationContext interface. Here, “started” means that all Lifecycle beans receive an explicit start signal. Typically, this signal is used to restart beans after an explicit stop, but it may also be used to start components that have not been configured for autostart (for example, components that have not already started on initialization). |
ContextStoppedEvent |
Published when the ApplicationContext is stopped by using the stop() method on the ConfigurableApplicationContext interface. Here, “stopped” means that all Lifecycle beans receive an explicit stop signal. A stopped context may be restarted through a start() call. |
ContextClosedEvent |
Published when the ApplicationContext is being closed by using the close() method on the ConfigurableApplicationContext interface or via a JVM shutdown hook. Here, “closed” means that all singleton beans will be destroyed. Once the context is closed, it reaches its end of life and cannot be refreshed or restarted. |
RequestHandledEvent |
A web-specific event telling all beans that an HTTP request has been serviced. This event is published after the request is complete. This event is only applicable to web applications that use Spring’s DispatcherServlet . |
ServletRequestHandledEvent |
A subclass of RequestHandledEvent that adds Servlet-specific context information. |
spring应用上下文启动事件——ontextRefreshedEvent
这个事件是在AbstractApplicationContext
#finishRefresh
方法中执行,执行到这里的时候整个spring容器的初始化、实例化(单例)已经完成,具体代码如下:
protected void finishRefresh() {
......
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
如果应用系统中,需要在容器初始化完成后(对应用bean有依赖)立即执行某些操作,可以监听这个事件,绝对不会出现依赖的bean
未初始化的问题。
今天的文章Spring Bean 方法自动触发的N种方式分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/23256.html