详解Spring中的Event事件处理机制和原理
本文内容纲要:
- Spring里的5种标准事件- 好处
- 示例
- 自定义事件类
- 事件监听类
- 事件发布类
- 测试类
- 结果
- Spring Event事件通知原理
- 异步响应Event
- 自定义SimpleApplicationEventMulticaster
- 添加AsyncTaskConfig配置类
- @Async原理
- 总结
我们都知道 Spring 的核心是 ApplicationContext,它负责管理 bean 的完整生命周期。当spring加载 bean 时,ApplicationContext 会发布某些类型的事件。例如,当上下文启动时,会发布ContextStartedEvent,当上下文停止时,会发布ContextStoppedEvent。
Spring里的5种标准事件
上下文更新事件(ContextRefreshedEvent) | 在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发 |
上下文开始事件(ContextStartedEvent) | 当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件 |
上下文停止事件(ContextStoppedEvent) | 当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件 |
上下文关闭事件(ContextClosedEvent) | 当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁 |
请求处理事件(RequestHandledEvent) | 在Web应用中,当一个http请求(request)结束触发该事件 |
如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。
注意:由于 Spring 的事件处理是单线程的,所以如果一个事件被发布,直至并且除非所有的接收者得到的该消息,该进程被阻塞并且流程将不会继续。因此,如果事件处理被使用,在设计应用程序时应注意。
好处
Spring的事件通知机制是一项很有用的功能,使用事件机制我们可以将相互耦合的代码解耦,从而方便功能的修改与添加。
示例
除了上面介绍的5个spring已经帮我们实现的事件,我们还可以实现自定义事件。
举个例子,假设有一个添加评论的方法,在评论添加成功之后需要进行修改redis缓存、给用户添加积分等等操作。当然可以在添加评论的代码后面假设这些操作,但是这样的代码违反了设计模式的多项原则:单一职责原则、迪米特法则、开闭原则。一句话说就是耦合性太大了,比如将来评论添加成功之后还需要有另外一个操作,这时候我们就需要去修改我们的添加评论代码了。
自定义事件类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /** * 自定义的事件类 */ @Getter @Setter publicclassCustomEventextendsApplicationEvent{
privateStringmessage;
/** * Create a new ApplicationEvent. * * @param source the object on which the event initially occurred (never {@code null}) */ publicCustomEvent(Objectsource,Stringmessage){ super(source); this.message=message; }
} |
事件监听类
1 2 3 4 5 6 7 8 9 10 11 | /** * 事件监听类 */ @Component @Slf4j publicclassCustomEventListenerimplementsApplicationListener<CustomEvent>{ @Override publicvoidonApplicationEvent(CustomEvent event){ log.info("get msg:{}",event.getMessage()); } } |
事件发布类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** * 事件发布类 */ @Component publicclassCustomEventPublish{
@Autowired privateApplicationEventPublisher eventPublisher;
publicvoidpublish(Stringmessage){ CustomEvent event=newCustomEvent(this,message); eventPublisher.publishEvent(event); }
} |
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /** * 测试类 */ @RunWith(SpringRunner.class) @SpringBootTest publicclassSpringeventApplicationTests{
@Autowired privateCustomEventPublish eventPublish;
@Test publicvoidtest(){ eventPublish.publish("888888888888888888"); }
}
|
结果
1 | INFO15108---[ main]c.e.s.e.listener.CustomEventListener :get msg:888888888888888888 |
Spring Event事件通知原理
首先我们跟踪publishEvent方法,这个方法在AbstractApplicationContext类中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | protectedvoidpublishEvent(Objectevent,@Nullable ResolvableType eventType){ Assert.notNull(event,"Event must not be null");
// Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if(event instanceofApplicationEvent){ // 如果event是ApplicationEvent对象 applicationEvent=(ApplicationEvent)event; } else{ // 如果event不是ApplicationEvent对象,则将其包装成PayloadApplicationEvent事件,并获取对应的事件类型 applicationEvent=newPayloadApplicationEvent<>(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{ // 获取ApplicationEventMulticaster,调用`multicastEvent`方法广播事件 getApplicationEventMulticaster().multicastEvent(applicationEvent,eventType); }
// 如果当前命名空间还有父亲节点,也需要给父亲推送该消息 // Publish event via parent context as well... if(this.parent!=null){ if(this.parent instanceofAbstractApplicationContext){ ((AbstractApplicationContext)this.parent).publishEvent(event,eventType); } else{ this.parent.publishEvent(event); } } }
// 获取ApplicationEventMulticaster ApplicationEventMulticaster getApplicationEventMulticaster()throwsIllegalStateException{ if(this.applicationEventMulticaster==null){ thrownewIllegalStateException("ApplicationEventMulticaster not initialized - "+ "call 'refresh' before multicasting events via the context: "+this); } returnthis.applicationEventMulticaster; } |
经过上面的分析,我们看到事件是通过applicationEventMulticaster来广播出去的。
applicationEventMulticaster在Spring的启动过程中被建立,在Spring的启动过程中,在核心方法refresh中建立applicationEventMulticaster:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // Initialize message source for this context. initMessageSource();
// Initialize event multicaster for this context. // 在Spring容器中初始化事件广播器,事件广播器用于事件的发布 initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses. onRefresh();
// Check for listener beans and register them. // 把Spring容器内的事件监听器和BeanFactory中的事件监听器都添加的事件广播器中。 registerListeners();
// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event. finishRefresh(); |
关注initApplicationEventMulticaster和registerListeners方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // 初始化事件广播器 protectedvoidinitApplicationEventMulticaster(){ ConfigurableListableBeanFactory beanFactory=getBeanFactory(); // 如果用户手动新建了一个名为applicationEventMulticaster类型为ApplicationEventMulticaster的bean,则将这个bean作为事件广播器 if(beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)){ this.applicationEventMulticaster= beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,ApplicationEventMulticaster.class); if(logger.isTraceEnabled()){ logger.trace("Using ApplicationEventMulticaster ["+this.applicationEventMulticaster+"]"); } } else{ // 否则新建一个SimpleApplicationEventMulticaster作为默认的事件广播器 this.applicationEventMulticaster=newSimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,this.applicationEventMulticaster); if(logger.isTraceEnabled()){ logger.trace("No '"+APPLICATION_EVENT_MULTICASTER_BEAN_NAME+"' bean, using "+ "["+this.applicationEventMulticaster.getClass().getSimpleName()+"]"); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // 注册监听器 protectedvoidregisterListeners(){ // 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! // 获取类型是ApplicationListener的beanName集合,此处不会去实例化bean String[]listenerBeanNames=getBeanNamesForType(ApplicationListener.class,true,false); for(StringlistenerBeanName:listenerBeanNames){ getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); }
// Publish early application events now that we finally have a multicaster... Set<ApplicationEvent>earlyEventsToProcess=this.earlyApplicationEvents; this.earlyApplicationEvents=null; // 如果存在earlyEventsToProcess,提前处理这些事件 if(earlyEventsToProcess!=null){ for(ApplicationEvent earlyEvent:earlyEventsToProcess){ getApplicationEventMulticaster().multicastEvent(earlyEvent); } } } |
经过前面的分析,我们知道了事件广播器applicationEventMulticaster如何被构建,下面我们分析事件的广播过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | @Override publicvoidmulticastEvent(finalApplicationEvent event,@Nullable ResolvableType eventType){ ResolvableType type=(eventType!=null?eventType:resolveDefaultEventType(event)); // 根据event类型获取适合的监听器 for(finalApplicationListener<?>listener:getApplicationListeners(event,type)){ // 获取SimpleApplicationEventMulticaster中的线程执行器,如果存在线程执行器则在新线程中异步执行,否则直接同步执行监听器中的方法 Executor executor=getTaskExecutor(); if(executor!=null){ executor.execute(()->invokeListener(listener,event)); } else{ invokeListener(listener,event); } } }
protectedvoidinvokeListener(ApplicationListener<?>listener,ApplicationEvent event){ // 如果存在ErrorHandler,调用监听器方法如果抛出异常则调用ErrorHandler来处理异常。否则直接调用监听器方法 ErrorHandler errorHandler=getErrorHandler(); if(errorHandler!=null){ try{ doInvokeListener(listener,event); } catch(Throwable err){ errorHandler.handleError(err); } } else{ doInvokeListener(listener,event); } } |
经过上面的分析,我们知道了Spring如何发送并响应事件。下面我们来分析如何使Spring能够异步响应事件。
异步响应Event
默认情况下,Spring是同步执行Event的响应方法的。如果响应方法的执行时间很长会阻塞发送事件的方法,因此很多场景下,我们需要让事件的响应异步化。
自定义SimpleApplicationEventMulticaster
通过前面的代码分析,我们发现如果SimpleApplicationEventMulticaster中的taskExecutor如果不为null,将在taskExecutor中异步执行响应程序。
applicationEventMulticaster的新建在initApplicationEventMulticaster方法中,默认情况下它会新建一个SimpleApplicationEventMulticaster,其中的taskExecutor为null。因此想要taskExecutor不为null,我们可以自己手动创建一个SimpleApplicationEventMulticaster然后设置一个taskExecutor。
添加AsyncTaskConfig配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Configuration publicclassAsyncTaskConfig{ @Bean publicSimpleAsyncTaskExecutor simpleAsyncTaskExecutor(){ returnnewSimpleAsyncTaskExecutor(); }
@Bean publicSimpleApplicationEventMulticaster applicationEventMulticaster(){ SimpleApplicationEventMulticaster simpleApplicationEventMulticaster=newSimpleApplicationEventMulticaster(); simpleApplicationEventMulticaster.setTaskExecutor(simpleAsyncTaskExecutor()); returnsimpleApplicationEventMulticaster; } } |
此时再次执行程序,执行结果如下:
1 | [TaskExecutor-13]c.e.s.e.listener.CustomEventListener :get msg:888888888888888888 |
可以看到这边是在新线程TaskExecutor-13里执行的,而不是像上面那样在main主线程里执行的。
@Async原理
@Async注解可以将方法异步化,下面我们来看看它的原理是什么。
我们在Config类中添加了@EnableAsync注释。@EnableAsync注释引入AsyncConfigurationSelector类,AsyncConfigurationSelector类导入ProxyAsyncConfiguration类,ProxyAsyncConfiguration类新建过程中会新建AsyncAnnotationBeanPostProcessor。
AsyncAnnotationBeanPostProcessor类继承了BeanPostProcessor,当每个Bean新建完成后会调用AsyncAnnotationBeanPostProcessor的postProcessAfterInitialization方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | @Override publicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){ if(this.advisor==null||bean instanceofAopInfrastructureBean){ // Ignore AOP infrastructure such as scoped proxies. returnbean; }
if(bean instanceofAdvised){ Advised advised=(Advised)bean; if(!advised.isFrozen()&&isEligible(AopUtils.getTargetClass(bean))){ // Add our local Advisor to the existing proxy's Advisor chain... if(this.beforeExistingAdvisors){ advised.addAdvisor(0,this.advisor); } else{ advised.addAdvisor(this.advisor); } returnbean; } }
if(isEligible(bean,beanName)){ ProxyFactory proxyFactory=prepareProxyFactory(bean,beanName); if(!proxyFactory.isProxyTargetClass()){ evaluateProxyInterfaces(bean.getClass(),proxyFactory); } proxyFactory.addAdvisor(this.advisor); customizeProxyFactory(proxyFactory); returnproxyFactory.getProxy(getProxyClassLoader()); }
// No proxy needed. returnbean; } |
postProcessAfterInitialization方法判断bean是否符合要求(方法上是否加了@Async注释),如果符合要求则对bean加上代理,代理类为AnnotationAsyncExecutionInterceptor。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | @Override @Nullable publicObjectinvoke(finalMethodInvocation invocation)throwsThrowable{ Class<?>targetClass=(invocation.getThis()!=null?AopUtils.getTargetClass(invocation.getThis()):null); Method specificMethod=ClassUtils.getMostSpecificMethod(invocation.getMethod(),targetClass); finalMethod userDeclaredMethod=BridgeMethodResolver.findBridgedMethod(specificMethod);
// 获取executor AsyncTaskExecutor executor=determineAsyncExecutor(userDeclaredMethod); if(executor==null){ thrownewIllegalStateException( "No executor specified and no default executor set on AsyncExecutionInterceptor either"); }
// 将我们真正的方法包装成一个`Callable`任务 Callable<Object>task=()->{ try{ Objectresult=invocation.proceed(); if(result instanceofFuture){ return((Future<?>)result).get(); } } catch(ExecutionException ex){ handleError(ex.getCause(),userDeclaredMethod,invocation.getArguments()); } catch(Throwable ex){ handleError(ex,userDeclaredMethod,invocation.getArguments()); } returnnull; };
// 将任务提交到`executor`中执行 returndoSubmit(task,executor,invocation.getMethod().getReturnType()); } |
调用我们的方法时首先调用AnnotationAsyncExecutionInterceptor的invoke方法,invoke方法将我们真正的方法包装成一个Callable任务,将这个任务提交到executor中执行。由此达到了将我们的方法异步化的目的。
总结
Spring的事件机制是一套相当灵活的机制,使用它可以简便地将我们的代码解耦从而优化我们的代码。经过前面的分析我们了解了其中的运行原理,这有助于我们更好地使用这套机制。
本文内容总结:Spring里的5种标准事件,好处,示例,自定义事件类,事件监听类,事件发布类,测试类,结果,Spring Event事件通知原理,异步响应Event,自定义SimpleApplicationEventMulticaster,添加AsyncTaskConfig配置类,@Async原理,总结,
原文链接:https://www.cnblogs.com/shamo89/p/15715091.html
以上是 详解Spring中的Event事件处理机制和原理 的全部内容, 来源链接: utcz.com/z/296515.html