我们可能经常会碰到一些奇奇怪怪的需求,比如在IOC容器初始化完成前实例化一些bean,bean的初始化回调等等等。今天来讲一下如何实现Spring IOC容器如何在完成初始化后回调某个方法。
这是Spring IOC容器的初始化方法,可以看到,它完成了,初始化的准备,beanFactory的初始化,beanDefinition的定位,加载,注册,beanFactory的后处理等。而我们要的是在初始化完成后回调某个方法,那如何实现呢?
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
初始化完成,那么肯定是在最后一个方法里咯,我们来看finishRefresh()方法:
第三个方法是将将初始化完成的事件推送给listener,那么就意味着,它会调用listener的某个方法,这不是正好满足我们的需求吗?
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
@Override
public void publishEvent(ApplicationEvent event) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
getApplicationEventMulticaster().multicastEvent(event);
if (this.parent != null) {
this.parent.publishEvent(event);
}
}
可以发现,它会先获取listener的集合,然后依次调用它们的onApplicationEvent(event)方法,如果它有存在父容器,会递归调用publishEvent(event)方法来通知所有容器中的listener,Spring提供了这个ApplicationListener接口来供我们进行功能的扩展。
@Override
public void multicastEvent(final ApplicationEvent event) {
for (final ApplicationListener<?> listener : getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
listener.onApplicationEvent(event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
listener.onApplicationEvent(event);
}
}
那么我们实现这个接口
@Component
public class Test implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("我在bean初始化完之后执行 "+event.toString());
}
}
输入如下,其是在IOC容器初始化完毕后进行通知listener来进行某些功能的实现的。
我在bean初始化完之后执行 org.springframework.context.event.ContextRefreshedEvent[source=cn.blingfeng.MyClassPathXmlApplicationContext@246b179d: startup date [Wed Apr 25 13:47:46 CST 2018]; root of context hierarchy]
那么问题来了,它是在什么时候将这些listener注册进容器的呢?
当然是上面的 registerListeners(); 这个方法啦
这里实现了将实现了ApplicationListener接口的Bean放入Set集合,那么就可以轻松实现这批listener的方法回调
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String lisName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(lisName);
}
}
Spring中提供了很多IOC/Bean不同生命周期的方法回调,开放性很高,扩展性很强,我们可以根据自己的业务场景,实现不同的需求。
ps:本博近期会一直更新Spring源码系列内容
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。