网站遭受攻击,网站推广软件预期效果,左右布局的网站,网站建设案例展示上集从官网的角度讲解了基本的使用和源码的内容#xff0c;没有深入的进行分析#xff0c;本章将从源码的角度分析ApplicationEvent、ApplicationListener、ApplicationEventMulticaster这三者之间的关系。
initApplicationEventMulticaster
上一章后续部分给出了源码的含义…上集从官网的角度讲解了基本的使用和源码的内容没有深入的进行分析本章将从源码的角度分析ApplicationEvent、ApplicationListener、ApplicationEventMulticaster这三者之间的关系。
initApplicationEventMulticaster
上一章后续部分给出了源码的含义我们从中可以知道默认的情况下也就是我们BeanFactory中没有存在名称为applicationEventMulticaster的BeanDefinition或者Bean是会创建一个SimpleApplicationEventMulticaster应用事件广播器也就是else中的逻辑创建一个然后注册到Beanfactory中。
protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory getBeanFactory();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 {// 广播器的创建SimpleApplicationEventMulticasterthis.applicationEventMulticaster new SimpleApplicationEventMulticaster(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() ]);}}}只有自定义一个应用事件广播器的时候会走上面的if中的逻辑。我这边直接改造一下这个SimpleApplicationEventMulticaster的实现如下所示
Configuration
public class CustomApplicationEventMulticasterConfig {Beanpublic ApplicationEventMulticaster applicationEventMulticaster(){SimpleApplicationEventMulticaster simpleApplicationEventMulticaster new SimpleApplicationEventMulticaster();return simpleApplicationEventMulticaster;}
}默认的SimpleApplicaitonEventMulticaster是不支持异步的所以我们可以配置线程池以支持异步事件处理。
通过配置一个合适的线程池你可以使事件的处理在独立的线程中进行从而实现异步处理避免阻塞主线程。
Configuration
public class CustomApplicationEventMulticasterConfig {Beanpublic TaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();executor.setCorePoolSize(10); // 设置核心线程数executor.setMaxPoolSize(50); // 设置最大线程数executor.setQueueCapacity(100); // 设置队列容量executor.setThreadNamePrefix(event-executor-); // 设置线程名称前缀executor.initialize();return executor;}Beanpublic ApplicationEventMulticaster applicationEventMulticaster(TaskExecutor taskExecutor) {SimpleApplicationEventMulticaster eventMulticaster new SimpleApplicationEventMulticaster();eventMulticaster.setTaskExecutor(taskExecutor); // 设置线程池return eventMulticaster;}
}再看我们的EmailService类可以通过AnnotationConfigApplicationContext也就是ApplicationEventPublisher执行publishEvent广播事件。我们这儿只传递了一个参数也就是ApplicationEvent event参数。
Component
public class EmailService implements ApplicationEventPublisherAware, ApplicationContextAware {// 使用ApplicationEventPublisher应用事件发布器发布事件private ApplicationEventPublisher applicationEventPublisher;private ApplicationContext applicationContext;Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher applicationEventPublisher;}public void sendEmail(String address, String content) {applicationEventPublisher.publishEvent(new BlockedListEvent(applicationContext, address, content));}Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContextapplicationContext;}
}在SimpleApplicationEventMulticaster的multicastEvnet方法中会执行getApplicationListeners(event, type)方法通过event去获取监听event的监听器。
Overridepublic 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);}}}最终会使用监听器调用onApplicationEvent方法来达到通知和广播的目的。如下图所示 总结ApplicationEvent是一种应用事件ApplicationListener就是和事件进行绑定当有相应的应用事件广播的时候就会找到所有和应用事件绑定的监听器调用其onApplicationEvent方法。而ApplicationEventMulticaster是什么个人感觉简单来说它就是一个“路由器”。
Annotation-based Event Listeners
案例一
可以使用EventListener注解将事件监听器注册到托管bean的任何方法上。AnnotationBlockedListNotifier可以按以下方式进行重写
Component
public class AnnotationBlockedListNotifier {EventListener// 这个名字随便写都行public void processBlockedListEvent(BlockedListEvent event) {System.out.println(Annotation-地址:event.getAddress());System.out.println(Annotation-内容:event.getContent());}
}我们使用EventListener注解将processBlockedListEvent方法标记为BlockedListEvent的事件监听器。当发布一个BlockedListEvent事件时Spring会自动调用该方法并将事件作为参数传递给它。
使用EventListener注解可以简化事件监听器的注册过程无需实现ApplicationListener接口或显式注册为Spring bean。Spring会自动扫描并识别带有EventListener注解的方法并将其注册为事件监听器。
请注意使用EventListener注解的方法可以有不同的访问修饰符public、protected、private等并且可以带有其他参数。Spring将根据参数类型进行事件匹配并将事件作为方法的参数传递。
案例二
方法签名再次声明了它所监听的事件类型但这次使用了灵活的名称并且无需实现特定的监听器接口。只要实际的事件类型在其实现层次结构中解析了我们的泛型参数事件类型也可以通过泛型进行缩小。
如果我们的方法应该监听多个事件或者如果我们希望在没有参数的情况下定义它事件类型也可以在注解本身上指定。以下示例展示了如何实现
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;Component
public class MyEventListener {EventListener({EventA.class, EventB.class})public void onEvent(Object event) {// 处理事件逻辑System.out.println(Received event: event);}
}在上述示例中我们使用EventListener注解并在注解上指定了要监听的事件类型EventA和EventB。在方法中我们将事件类型声明为Object类型以接收不同类型的事件。在事件处理逻辑中我们可以根据实际的事件类型进行处理。
请注意使用EventListener注解的方法可以具有不同的访问修饰符public、protected、private等并且可以带有其他参数。Spring将根据方法的参数类型和注解上指定的事件类型进行事件匹配。
案例三
还可以通过在定义注解的条件属性中使用SpEL表达式来添加额外的运行时过滤以匹配特定事件才实际调用方法。
以下示例展示了如何重写我们的通知器只有当事件的content属性等于my-event时才会被调用
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;Component
public class BlockedListNotifier {EventListener(condition #event.content my-event)public void onBlockedListEvent(BlockedListEvent event) {// 处理事件逻辑System.out.println(Received blocked list event: event.getMessage());}
}在上述示例中我们使用EventListener注解并在注解的条件属性上指定了一个SpEL表达式#event.content ‘my-event’。这个表达式将用于过滤事件只有当事件的content属性等于my-event时才会调用方法。
通过使用条件属性我们可以根据事件的属性值或其他条件灵活地控制方法的调用。在SpEL表达式中可以使用事件对象的属性和方法进行比较、计算和判断。 该功能不支持异步监听器 Asynchronous Listeners
如果希望特定的监听器以异步方式处理事件可以重用常规的Async支持。以下示例展示了如何实现
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;Component
public class MyAsyncEventListener {AsyncEventListenerpublic void onEvent(Object event) {// 异步处理事件逻辑System.out.println(Received event asynchronously: event);}
}在上述示例中我们在方法上使用了Async注解来表示该方法应以异步方式执行。同时我们仍然使用EventListener注解将该方法标记为事件监听器。当事件发生时Spring将自动使用异步线程池来执行该方法从而实现异步事件处理。
要使用Async注解我们还需要在Spring配置中启用异步支持。可以通过在配置类上添加EnableAsync注解来实现。
通过将Async注解与EventListener注解结合使用可以实现异步事件处理。这使我们能够在后台线程中并行处理事件从而提高系统的响应性和性能。请注意异步事件处理可能会导致事件处理的顺序变得不确定因此请谨慎使用。 Be aware of the following limitations when using asynchronous events: If an asynchronous event listener throws an Exception, it is not propagated to the caller. See AsyncUncaughtExceptionHandler for more details.Asynchronous event listener methods cannot publish a subsequent event by returning a value. If you need to publish another event as the result of the processing, inject an ApplicationEventPublisher to publish the event manually. 在使用异步事件时请注意以下限制
如果异步事件监听器抛出异常它不会传播到调用方。有关更多详细信息请参阅AsyncUncaughtExceptionHandler。
异步事件监听器方法无法通过返回值发布后续事件。如果需要在处理的结果中发布另一个事件请注入ApplicationEventPublisher以手动发布事件。
Ordering Listeners
如果您需要一个监听器在另一个监听器之前被调用您可以在方法声明中添加Order注解如下面的示例所示
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;Component
public class MyEventListener {Order(1)EventListenerpublic void firstListener(MyEvent event) {// 第一个监听器的逻辑}Order(2)EventListenerpublic void secondListener(MyEvent event) {// 第二个监听器的逻辑}
}在上述示例中我们使用Order注解来指定监听器方法的执行顺序。在第一个监听器方法上我们将Order(1)注解添加表示它应该在第二个监听器方法之前被调用。在第二个监听器方法上我们将Order(2)注解添加表示它应该在第一个监听器方法之后被调用。
请注意Order注解的值越小优先级越高。因此具有较小Order值的监听器将在具有较大Order值的监听器之前被调用。
通过使用Order注解您可以控制监听器方法的执行顺序以确保它们按照您的需求进行调用。
总结
第八章和这一章节主要分析和描述了Spring事件的使用在日常工作中基本没怎么使用本来想绕过这一段直接进行初始化实例化和三级缓存抱着学习的态度还是仔细分析了一下然后查阅了官网进行学习还是有所收获希望对正在学习的朋友们有所帮助。