- 首先看看在Spring如何实现自定义事件监听,首先定义事件:
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
- 然后定义一个事件监听器,注意监听器需要交给容器管理,所以需要标注@Component注解
@Component
public class MyListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof MyEvent){
System.out.println("事件开始了");
}
}
}
- 在具体的场景中发布一个事件, 注意这里发布事件需要通过ApplicatonContext发布,所以这里继承ApplicationContextAware, 这样在类实例化后会调用ApplicationContextAware的setApplicationContext()方法拿到ApplicationContext实例
@Component
public class Animal implements ApplicationContextAware{
private ApplicationContext ac;
public void speak(){
//必须通过ApplicationContext发布事件
ac.publishEvent(new MyEvent(ac));
}
@Override
public void setApplicationContext(ApplicationContext arg0)
throws BeansException {
this.ac = arg0;
}
}
到此处,自定义监听器已经完成,那么问题来,spring到底是怎么实现的,为什么在调用applicationContext的publishEvent()方法就能做到事件监听呢?下边采用问答的方式讲述实现原理
问题:applicationContext是怎么通过setApplicationContext()方法被设置到Animal对象中的呢?
对于这个问题,我们需要看Spring关于Bean的实例化过程,在Bean对象被实例化后,会调用各种后置处理器方法,找到Spring bean创建方法doCreateBean,我们会找到下边这样一段代码; populateBean()是属性填充,initializeBean()方法对bean做一些初始化工作,其实就是执行一些列的后置处理器方法, 然后我们在这个方法内部可以看到invokeAwareMethods(beanName, bean);方法调用,也正是通过这段代码实现applicationContext设置的
try {
//属性添加,给实例对象填充属性
populateBean(beanName, mbd, instanceWrapper);
//初始化bean, 也就是生命周期回到,@PostConstruct,InitializingBean SmartInitializingSingleton,
// 拿出所有的后置处理,进行调用
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
...
//------------------------------------------------------------------
//initializeBean方法的实现
//------------------------------------------------------------------
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 {
//这个地方调用接口Aware的方法,
//例如当前bean实现了ApplicationContextAware接口,那么这个地方会调用这个接口的
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//执行bean后置处理,包括自定义的还有系统定义的0,
// @PostCounstruct由系统提供的CommonAnnotationBeanPostProcessor进行处理
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//这里执行实现InitializingBean接口的方法
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()) {
//执行beanPostProcessor的applyBeanPostProcessorsAfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
//----------------------------------------------------------------
//如果当前类实现了Aware接口,或者该接口的字类,那么在这个地方会执行其对应的一些方法setBeanFactory()方法
//------------------------------------------------------------------
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
问题:通过applicationContext.publishEvent(new Event())发布事件后,监听器是如何监听到这个事件的?
在回答这个问题之前,我们先考虑一个问题,我们自定义了一个监听器类,而且在这个监听器类上添加了@Component注解,Spring是如何处理这个类的,会不会和普通bean的处理方式一样?
其实答案肯定是不一样,spring会判断这个bean是不是一个监听器,如果是监听器,会把这个bean放到applicationLisenters中。那么spring到底是如何处理的?
其实这个还是在bean实例化的时候处理器的,我们接着看initializeBean()方法,在这个方法类会执行一些列的后置处理器方法,我们发现在Spring中,提供了一个后置处理器为ApplicationListenerDetector,我们看看它提供了什么方法,我们看到,方法一开始就判断当前bean是不是一个ApplicationListener,最后把它添加到了applicaitonListentors中
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}
最后我们看看通过publishEvent()后又是怎么监听到这个事件的,getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);我们看到这个代码将事件传递给所有的监听器,在multicastEvent()方法中,会发现spring取出了所有的监听器,然后分别把事件传递给他们,然后调用invokeListener(listener, event);方法, 接着往里看, 最终发现调用了listener.onApplicationEvent(event)方法,发现了吧,我们自定义的监听就是重写了ApplicationListener的这个方法,所以最后事件就者被传递到我们自定的监听器了。
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
//把事件传递给所有的监听器
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
//如果存在父事件,还要进行向上传播
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
//------------------------------------------------------------------
//事件处理
//------------------------------------------------------------------
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//在这里去执行具体监听执行方法
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}