目录
1、使用Spring 事件
(1)事件
(2)事件监听器
(3)事件发布 *** 作
(4)监听器使用的相关问题
2、Spring事件原理
3、源码流程
(1)前期准备
(2)事件多播器的初始化
(3)注册事件监听器,发布早期事件
(4)发布Spring内置事件
1、使用Spring 事件
Spring事件体系包括三个组件:事件,事件监听器,事件广播器。
(1)事件Spring内置事件
内置事件中由系统内部进行发布,只需注入监听器
Event | 说明 |
ContextRefreshedEvent | 当容器被实例化或refreshed时发布。如调用refresh()方法,此处的实例化是指所有的bean都已被加载,后置处理器都被激活,所有单例bean都已被实例化,所有的容器对象都已准备好可使用。如果容器支持热重载,则refresh可以被触发多次(XmlWebApplicatonContext支持热刷新,而GenericApplicationContext则不支持) |
ContextStartedEvent | 当容器启动时发布,即调用start()方法,已启用意味着所有的Lifecycle bean都已显式接收到了start信号 |
ContextStoppedEvent | 当容器停止时发布,即调用stop()方法,即所有的Lifecycle bean都已显式接收到了stop信号,关闭的容器可以通过start()方法重启 |
ContextClosedEvent | 当容器关闭时发布,即调用close方法,关闭意味着所有的单例bean都已被销毁。关闭的容器不能被重启或refresh |
RequestHandledEvent | 这只在使用spring的DispatcherServlet时有效,当一个请求被处理完成时发布 |
自定义事件
事件类需要继承ApplicationEvent,代码如下:
import org.springframework.context.ApplicationEvent;
/***
* 自定义事件
*/
public class OrderEvent extends ApplicationEvent {
private String name;
public OrderEvent(Object source, String name) {
super(source);
this.name = name;
}
public String getName() {
return name;
}
}
这里为了简单测试,所以写的很简单。事件类是一种很简单的pojo,除了需要继承ApplicationEvent 也没什么了,这个类有一个构造方法需要super。
(2)事件监听器事件监听器 -> 基于接口
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/***
* 监听器->观察者模式
*/
@Component
public class OrderEventListener implements ApplicationListener {
public void onApplicationEvent(OrderEvent event) {
if (event.getName().equals("reduce_stock")) {
System.out.println("减库存.......");
}
}
}
事件监听器需要实现ApplicationListener接口,这是个泛型接口,泛型类类型就是事件类型。其次需要是spring容器托管的bean,所以这里加了@component,只有一个方法,就是onApplicationEvent。
事件监听器 -> 基于注解
@Component
public class OrderEventListener {
// 基于注解的监听器
@EventListener(OrderEvent.class)
public void onApplicationEvent(OrderEvent event) {
if (event.getName().equals("reduce_stock")) {
System.out.println("减库存.......");
}
}
}
(3)事件发布 *** 作
事件发布方式很简单,调用AnnotationConfigApplicationContext.publishEvent()方法
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainClass {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
//下单
Order order =new Order();
System.out.println("下单");
// 发布订单事件 -> 减库存
ctx.publishEvent(new OrderEvent(order,"reduce_stock"));
System.out.println("日志...");
}
}
执行结果
补充发布事件中使用到的两个类:Order.java,MainConfig.java
public class Order {
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"com.swadian.task.event"})
//@EnableAsync 异步事件
public class MainConfig {
}
(4)监听器使用的相关问题
1.同样的事件能有多个监听器吗? -- 可以
2.事件监听器一定要写一个类去实现吗?
可以不需要,spring有个注解@EventListener,修饰在方法上,该方法就可以作为一个事件的监听器
@Component
public class OrderEventListener {
// 基于注解的监听器
@EventListener(OrderEvent.class)
public void eventListener(OrderEvent event) {
if (event.getName().equals("reduce_stock")) {
System.out.println("减库存.......");
}
}
}
3.事件监听 *** 作和发布事件的 *** 作是同步的吗?
是的,所以如果有事务,监听 *** 作也在事务内
4.事件监听 *** 作可以异步处理吗?
可以,默认同步。如果需要异步,可以向多播器中(SimpleApplicationEventMulticaster)设置一个TaskExecutor
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@ComponentScan(basePackages = {"com.swadian.task.event"})
@EnableAsync //异步事件
public class MainConfig {
/**
* 往SimpleApplicationEventMulticaster设置taskExecutor则为异步事件
* 或者使用@Async
* @return
*/
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster
= new SimpleApplicationEventMulticaster();
// ThreadPoolTaskExecutor -> 设置异步线程
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}
}
设置的TaskExecutor,会在源码里用到
2、Spring事件原理原理:观察者模式
Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster(多播器)的角色负责把事件转发给监听者,工作流程如下:
发布者调用applicationEventPublisher.publishEvent(msg);将事件发送给了EventMultiCaster,然后由EventMultiCaster注册所有的Listener(监听者),最后根据事件类型决定转发给哪个Listener。
3、源码流程 (1)前期准备Spring在AbstractApplicationContext.refresh()容器启动方法中搭建了事件的基础设施。refresh()方法的具体实现如下:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1-准备刷新上下文环境 -> 声明不需要手动发布的早期监听器+事件
prepareRefresh();
// 2-告诉子类刷新内部bean工厂——>不同的工厂有不同的实现(XML和注解方式)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3-对bean工厂进行填充属性 -> 注册监听器的解析器ApplicationListenerDetector
prepareBeanFactory(beanFactory);
try {
// 4-允许在上下文子类中对bean工厂进行后处理 -> 空方法,子类实现
postProcessBeanFactory(beanFactory);
// 5-调用在上下文中注册的Bean工厂后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 6-注册拦截bean创建的bean后置处理器
registerBeanPostProcessors(beanFactory);
// 7-为此上下文初始化消息源-国际化
initMessageSource();
// 8-为此上下文初始化事件多播 -> 所有的监听器都会注册到多播器里边,由多播器调用
initApplicationEventMulticaster();
// 9-初始化特定上下文子类中的其他特殊bean -> 空方法,留给其他容器进行拓展
onRefresh();
// 10-注册事件监听器
registerListeners();
// 11-实例化所有剩余的(非惰性初始化)单例。
finishBeanFactoryInitialization(beanFactory);
// 12-最后一步:刷新容器,发布相应的事件。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例以避免悬空的资源。
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
// 重置Spring核心中常见的内省缓存,因为我们可能不再需要单例bean的元数据了。
resetCommonCaches();
}
}
}
在prepareRefresh()方法中,添加了早期监听器和早期监听器事件,早期监听器和事件不需要手动发布,在 refresh() 方法中,调用 registerListeners() 会自动进行发布。
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
// 容器费关闭状态
this.closed.set(false);
// 容器激活 ——> 只有调用refresh()才能够激活,然后才能getBean()
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// 默认为空 ——> 拓展用
initPropertySources();
// 验证initPropertySources()中的必须属性,和initPropertySources()一起使用
getEnvironment().validateRequiredProperties();
// 创建一个早期的事件监听器earlyApplicationListeners
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// 添加早期的事件监听器
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// 早期监听事件 earlyApplicationEvents
this.earlyApplicationEvents = new LinkedHashSet<>();
}
AbstractApplicationContext拥有一个applicationListeners成员变量,用于添加早期监听器
(2)事件多播器的初始化refresh() -> initApplicationEventMulticaster()
用户可以在配置文件中为容器定义一个自定义的事件多播器,只要实现ApplicationEventMulticaster 就可以了,Spring会通过反射的机制将其注册成容器的事件多播器。如果没有找到配置的外部事件多播器,Spring自动使用 SimpleApplicationEventMulticaster作为默认的事件多播器。
(3)注册事件监听器,发布早期事件refresh() -> registerListeners()
Spring根据反射机制,使用ListableBeanFactory的getBeansOfType方法,从BeanDefinitionRegistry 中找出所有实现 org.springframework.context.ApplicationListener的Bean,将它们注册为容器的事件监听器,实际的 *** 作就是将其添加到事件广播器所提供的监听器注册表中。
AbstractApplicationContext拥有一个applicationEventMulticaster成员变量,applicationEventMulticaster提供了容器监听器的注册表。
(4)发布Spring内置事件refresh() -> finishRefresh()
如果是自定义的监听事件发布,也是需要调用 publishEvent() 的方法;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainClass {
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
//下单
Order order =new Order();
System.out.println("下单");
// 发布订单自定义事件 -> 调用publishEvent()
ctx.publishEvent(new OrderEvent(order,"reduce_stock"));
Thread.sleep(2000);
System.out.println("日志...");
}
}
进入AbstractApplicationContext.publishEvent() 方法,会获取一个多播器,然后去发布事件
如果没有设置用户自定义的多播器,那么会使用默认多播器 SimpleApplicationEventMulticaster, 在多播器SimpleApplicationEventMulticaster中会去调用事件监听器:
有没有发现,这个方法,正是我们自定义监听器时实现 ApplicationListener 接口,重写的那个onApplicationEvent()方法;
至此,通过接口方式的实现的监听器解析步骤源码就分析结束了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)