详解Spring中的Event事件处理机制和原理
我们都知道 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
public class CustomEvent extends ApplicationEvent {
private String message;
/**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})    */
public CustomEvent(Object source, String message) {
super(source);
}
}
事件监听类
1 2 3 4 5 6 7 8/**
* 事件监听类
*/
@Component
@Slf4j
public class CustomEventListener implements ApplicationListener<CustomEvent> {    @Override
public void onApplicationEvent(CustomEvent event) {
8 9 10 11    public void onApplicationEvent(CustomEvent event) {        log.info("get msg:{}", Message());
}
}
事件发布类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15/**
* 事件发布类
*/
@Component
public class CustomEventPublish {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void publish(String message){
CustomEvent event = new CustomEvent(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
public class SpringeventApplicationTests {
@Autowired
private CustomEventPublish eventPublish;
@Test
public void test() {
eventPublish.publish("888888888888888888");    }
}
结果
1INFO 15108 --- [          main] c.listener.CustomEventListener    : get msg:888888888888888888 Spring Event事件通知原理
⾸先我们跟踪publishEvent⽅法,这个⽅法在AbstractApplicationContext类中。
1 2 3 4 5 6 7 8 9 10 11 12 13protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;spring启动流程面试回答
if (event instanceof ApplicationEvent) {
// 如果event是ApplicationEvent对象
applicationEvent = (ApplicationEvent) event;
}
else {
/
/ 如果event不是ApplicationEvent对象,则将其包装成PayloadApplicationEvent事件,并获取对应的事件类型        applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
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        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
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
// 获取ApplicationEventMulticaster
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {    if (this.applicationEventMulticaster == null) {
throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
"call 'refresh' before multicasting events via the context: " + this);
}
return this.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// 初始化事件⼴播器
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果⽤户⼿动新建了⼀个名为applicationEventMulticaster类型为ApplicationEventMulticaster的bean,则将这个bean作为事件⼴播器
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21器
if (ainsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
}
}
else {
// 否则新建⼀个SimpleApplicationEventMulticaster作为默认的事件⼴播器
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
"[" + Class().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// 注册
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!
// 获取类型是ApplicationListener的beanName集合,此处不会去实例化bean
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);    for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have
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@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 根据event类型获取适合的
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
/
/ 获取SimpleApplicationEventMulticaster中的线程执⾏器,如果存在线程执⾏器则在新线程中异步执⾏,否则直接同步执⾏中的⽅法
Executor executor = getTaskExecutor();
if (executor != null) {
}
else {
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
// 如果存在ErrorHandler,调⽤⽅法如果抛出异常则调⽤ErrorHandler来处理异常。否则直接调⽤⽅法
20 21 22 23 24 25 26 27 28 29 30 31    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⽅法中,默认情况下它会新建⼀个S
impleApplicationEventMulticaster,其中的taskExecutor为null。因此想要taskExecutor不为null,我们可以⾃⼰⼿动创建⼀个SimpleApplicationEventMulticaster然后设置⼀个taskExecutor。
添加AsyncTaskConfig配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14@Configuration
public class AsyncTaskConfig {
@Bean
public SimpleAsyncTaskExecutor simpleAsyncTaskExecutor() {
return new SimpleAsyncTaskExecutor();
}
@Bean
public SimpleApplicationEventMulticaster applicationEventMulticaster() {
SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();        simpleApplicationEventMulticaster.setTaskExecutor(simpleAsyncTaskExecutor());
return simpleApplicationEventMulticaster;
}
}
此时再次执⾏程序,执⾏结果如下:
1[TaskExecutor-13] c.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@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {    if (this.advisor == null || bean instanceof AopInfrastructureBean) {

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。