SpringBoot--开发实战--监听器(四十一)

一、ApplicationListener

ApplicationContext提供事件处理通过ApplicationEvent类和ApplicationListener接口。如果一个bean实现ApplicationListener接口在容器中,每次一个ApplicationEvent被发布到ApplicationContext中,这类bean就会收到这些通知。
实现Spring事件机制主要有4个类:
ApplicationEvent:事件,每个实现类表示一类事件,可携带数据。
ApplicationListener:事件监听器,用于接收事件处理时间。
ApplicationEventMulticaster:事件管理者,用于事件监听器的注册和事件的广播。
ApplicationEventPublisher:事件发布者,委托ApplicationEventMulticaster完成事件发布。

  1. 事件就是一个包含了任意对象并含有事件对象创建时间戳的类。
    框架源码:
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;
    }
}
  1. ApplicationListener
    框架源码:
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);
}

当事件监听器接收到它可以处理的事件,会调用onApplicationEvent()方法。注意到ApplicationListener是泛型参数的这样可以参数化的定制事件。这意味着onApplicationEvent()方法可以保持类型安全,避免任何需要向下类型转换。你可以尽可能多的注册你希望事件侦听器,但是注意,默认情况下,事件监听器同步接收事件。这意味着publishEvent()方法会阻塞直到所有的事件监听器成处理完事件。这种单线程同步方法的一个特点是,当一个监听器接收到一个事件时,它运行在事务上下文的发布者线程上如果事务上下文可用。如果事件的发布需要另一种策略(譬如多线程)需要实现自己的 ApplicationEventMulticaster接口类。

  1. 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事件机制我们来解耦,将与注册无关的操作改为异步。这里直接使用注解式写法。

  1. 创建订单实体
@Data
@Component
public class Order {
    private String orderNo;
    private String phone;
}
  1. 创建事件
/**
 * 创建订单完成事件
 */
@Component
public class AfterCreateOrderEvent extends ApplicationEvent {
    public AfterCreateOrderEvent(Order order) {
        super(order);
    }
    public Order getOrder(){
        return (Order) getSource();
    }
}
  1. 创建业务类进行事件发布与监听
@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());
    }
}
  1. 测试
@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);
    }
}
结果
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容