Spring事件

在spring容器中是通过ApplicationEvent类和ApplicationListener接口来处理事件的。如果某个bean实现了ApplicationListener接口并被部署到容器中,那么每次对应的ApplicationEvent被发布到容器中时,都会通知该bean,在设计模式中这个叫观察者模式。

spring的事件默认是同步的,即调用publisEvent()方法发布事件后, 它会处于阻塞状态,直到onApplicationEvent接收到事件并处理完返回之后才会继续往下执行,这种单线程同步的好处是可以进行事务管理

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时有效,当一个请求被处理完成时发布

代码实现

实现Spring标准事件只需要实现ApplicationListener并重写onApplicationEvent方法即可

@Slf4j
@Component
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        log.info("监听到ContextRefreshedEvent {}", event);
    }
}

结果

2020-09-22 13:02:18.481  INFO 10600 --- [           main] c.m.e.e.ContextRefreshedEventListener    : 监听到ContextRefreshedEvent org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@35cabb2a, started on Tue Sep 22 13:02:17 CST 2020]

Spring自定义事件

代码实现

定义事件

定义通知事件

public class NotifyEvent extends ApplicationEvent {

    private final String address;

    private final String content;

    /**
     * 构造方法中构建事件内容
     *
     * @param source
     * @param address
     * @param content
     */
    public NotifyEvent(Object source, String address, String content) {
        super(source);
        this.address = address;
        this.content = content;
    }

    public String getAddress() {
        return address;
    }

    public String getContent() {
        return content;
    }

    @Override
    public String toString() {
        return "BlackListEvent{" +
                "address='" + address + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

定义监听器

邮件监听器

@Slf4j
@Component
public class MailEventListener implements ApplicationListener<NotifyEvent> {

    private String notificationAddress;

    /**
     * 对接收到的事件进行处理
     *
     * @param event
     */
    @Override
    public void onApplicationEvent(NotifyEvent event) {
        log.info("发送邮件 {}", event);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("发送邮件 {}完成", event);


    }

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    public String getNotificationAddress() {
        return this.notificationAddress;
    }
}

短信监听器

@Slf4j
@Component
public class SmsEventListener implements ApplicationListener<NotifyEvent> {

    private String notificationAddress;

    /**
     * 对接收到的事件进行处理
     *
     * @param event
     */
    @Override
    public void onApplicationEvent(NotifyEvent event) {
        log.info("发送短信 {}", event);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("发送短信 {}完成", event);
    }

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    public String getNotificationAddress() {
        return this.notificationAddress;
    }
}

在Spring中发布事件

@Slf4j
@Service
public class NotifyService implements ApplicationEventPublisherAware {

    @Autowired
    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {

        this.publisher = applicationEventPublisher;
    }

    public void notify(String address, String content) {
        log.info("发布事件");
        NotifyEvent event = new NotifyEvent(this, address, content);
        publisher.publishEvent(event);
    }

}

结果

2020-09-22 13:47:46.159  INFO 12844 --- [nio-9000-exec-2] com.mantis.event.event.NotifyService     : 发布事件
2020-09-22 13:47:46.160  INFO 12844 --- [nio-9000-exec-2] c.mantis.event.event.MailEventListener   : 发送邮件 BlackListEvent{address='D', content=''}
2020-09-22 13:47:51.160  INFO 12844 --- [nio-9000-exec-2] c.mantis.event.event.MailEventListener   : 发送邮件 BlackListEvent{address='D', content=''}完成
2020-09-22 13:47:51.160  INFO 12844 --- [nio-9000-exec-2] com.mantis.event.event.SmsEventListener  : 发送短信 BlackListEvent{address='D', content=''}
2020-09-22 13:47:56.161  INFO 12844 --- [nio-9000-exec-2] com.mantis.event.event.SmsEventListener  : 发送短信 BlackListEvent{address='D', content=''}完成

总结

Spring使用事件通知机制方便系统的解耦,比如发送邮件功能,如果按照调用第三方服务的写法,就需要定义一个邮件发送接口,由后续开发者实现功能,而有了监听事件,一个事件可以配置多个监听,方便系统进行解耦。


zero
49 声望6 粉丝

前进