一、ApplicationListener
ApplicationContext提供事件处理通过ApplicationEvent类和ApplicationListener接口。如果一个bean实现ApplicationListener接口在容器中,每次一个ApplicationEvent被发布到ApplicationContext中,这类bean就会收到这些通知。
实现Spring事件机制主要有4个类:
ApplicationEvent:事件,每个实现类表示一类事件,可携带数据。
ApplicationListener:事件监听器,用于接收事件处理时间。
ApplicationEventMulticaster:事件管理者,用于事件监听器的注册和事件的广播。
ApplicationEventPublisher:事件发布者,委托ApplicationEventMulticaster完成事件发布。
- 事件就是一个包含了任意对象并含有事件对象创建时间戳的类。
框架源码:
public abstract class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 7099057708183571937L;
private final long timestamp = System.currentTimeMillis();
public ApplicationEvent(Object source) {
super(source);
}
public final long getTimestamp() {
return this.timestamp;
}
}
- ApplicationListener
框架源码:
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E var1);
}
当事件监听器接收到它可以处理的事件,会调用onApplicationEvent()方法。注意到ApplicationListener是泛型参数的这样可以参数化的定制事件。这意味着onApplicationEvent()方法可以保持类型安全,避免任何需要向下类型转换。你可以尽可能多的注册你希望事件侦听器,但是注意,默认情况下,事件监听器同步接收事件。这意味着publishEvent()方法会阻塞直到所有的事件监听器成处理完事件。这种单线程同步方法的一个特点是,当一个监听器接收到一个事件时,它运行在事务上下文的发布者线程上如果事务上下文可用。如果事件的发布需要另一种策略(譬如多线程)需要实现自己的 ApplicationEventMulticaster接口类。
- ApplicationEventMulticaster
ApplicationEventMulticaster接口方法分为三类,注册事件监听器、移除事件监听器、发布事件。
二、Spring内置事件
事件 | 描述 |
---|---|
ContextRefreshedEvent | 事件发布在ApplicationContext初始化或刷新时(例如,通过在ConfigurableApplicationContext接口使用refresh()方法)。这里,“初始化”意味着所有bean加载,post-processor bean被检测到并且激活,单例预先实例化,ApplicationContext对象可以使用了。只要上下文没有关闭,可以触发多次刷新,ApplicationContext提供了一种可选择的支持这种“热”刷新。例如,XmlWebApplicationContext支持热刷新,但GenericApplicationContext并非如此。具体是在AbstractApplicationContext的finishRefresh()方法中。 |
ContextStartedEvent | 事件发布在ApplicationContext开始使用ConfigurableApplicationContext接口start()方法。这里,“开始”意味着所有生命周期bean接收到一个明确的起始信号。通常,这个信号用于明确停止后重新启动,但它也可以用于启动组件没有被配置为自动运行(例如,组件还没有开始初始化)。 |
ContextStoppedEvent | 事件发布在ApplicationContext停止时通过使用ConfigurableApplicationContext接口上的stop()方法。在这里,“停止”意味着所有生命周期bean接收一个显式的停止信号。停止上下文可以通过重新调用start()方法。 |
ContextClosedEvent | 事件发布在ApplicationContext关闭时通过关闭ConfigurableApplicationContext接口()方法。这里,“封闭”意味着所有单例bean被摧毁。一个封闭的环境达到生命的终结。它不能刷新或重启。 |
RequestHandledEvent | 一个特定的web事件告诉所有能处理HTTP请求的bean 。这个事件是在请求完成后发布的。这个事件只适用于使用Spring的DispatcherServlet的web应用程序。 |
三、示例
当一个用户完成贷款订单后,我们希望执行发送提醒短信、调用积分服务增加积分、通知风控服务重算风控值(后续操作可能增加)等功能。
//创建订单
public void createOrder(Order order){
创建贷款订单;
发送提醒短信;
调用积分服务增加积分;
调用风控服务推送订单信息;
……
返回;
}
随着业务复杂度的增加,我们很快发现createOrder()创建订单这个方法耦合了太多与注册无关的逻辑,即影响了原本创建订单方法的效率,在设计上又不符合“开闭原则”。
现在使用spring事件机制我们来解耦,将与注册无关的操作改为异步。这里直接使用注解式写法。
- 创建订单实体
@Data
@Component
public class Order {
private String orderNo;
private String phone;
}
- 创建事件
/**
* 创建订单完成事件
*/
@Component
public class AfterCreateOrderEvent extends ApplicationEvent {
public AfterCreateOrderEvent(Order order) {
super(order);
}
public Order getOrder(){
return (Order) getSource();
}
}
- 创建业务类进行事件发布与监听
@Service
public class OrderService {
//直接注入spring事件发布者
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
/**
* 简单的创建订单方法
*/
public void createOrder(Order order) {
System.out.println("创建订单 order:" + order.getOrderNo() + " 结束");
// TODO 1. 调用事件发布者发布事件,解耦
applicationEventPublisher.publishEvent(new AfterCreateOrderEvent(order));
System.out.println("createOrder方法 结束");
}
// TODO 2. 事件监听处理,加入@EventListener注解后,该方法可以看出一个事件监听者
@EventListener
public void afterCreateOrder(AfterCreateOrderEvent afterCreateOrderEvent) throws InterruptedException {
Order order = afterCreateOrderEvent.getOrder();
Thread.sleep(2000);
System.out.println("调用短信通知服务:" + order.getPhone());
System.out.println("调用积分服务增加贷款积分:" + order.getOrderNo());
}
}
- 测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringSessionApplicationTests {
@Autowired
private OrderService orderService;
@Test
public void eventTest() {
Order order = new Order();
order.setOrderNo("N123124124124");
order.setPhone("18782202534");
orderService.createOrder(order);
}
}
结果
网友评论