网站修改联系方式,外贸网站建设长沙,北京网站建设公司哪些好,网页设计与网站建设考试大家好#xff0c;我是程序员牛牛#xff0c;《AI超级个体: ChatGPT与AIGC实战指南》的参与人#xff0c;10年Java编程程序员。 1. 概述
在做业务开发过程中#xff0c;有些复杂点的逻辑#xff0c;可能代码逻辑会很冗长#xff0c;举一个很简单的例子#xff0c;如我是程序员牛牛《AI超级个体: ChatGPT与AIGC实战指南》的参与人10年Java编程程序员。 1. 概述
在做业务开发过程中有些复杂点的逻辑可能代码逻辑会很冗长举一个很简单的例子如用户购买产品下单支付当支付完成后可能有以下操作 如果这些都在一个流程中同步执行下来不仅代码冗长耦合度高而且也不方便维护此时我们需要做的就是把这三个步骤进行异步解耦我们第一个想到解决方案的可能是使用消息队列MQ确实可以解决这个问题但MQ是比较复杂的非必要不提升架构复杂度。
如果是微服务架构涉及到多个服务之间协作那MQ无疑是最佳选择但如果是单体架构完全可以使用更加轻量级的解决方案Spring Event
2. Spring Event简介
事件是框架中最容易被忽视的功能之一但也是最有用的功能之一。与 Spring 中的许多其他功能一样事件发布是ApplicationContext提供的功能之一它类似发布订阅机制发布一个事件之后可以在其他地方监听这个事件做一些异步处理当然也支持同步其实它就是一个观察者模式设计。
3. 使用Spring Event
spring event使用其实很简单 下面我们已发送邮件为例来做一个简单的演示
3.1 其中事件监听的方式有两种 通过监听器的方式 通过注解的方式
3.2 通过监听器方式监听事件
3.2.1 定义事件
定义邮件发送事件需要继承ApplicationEvent 这里我们列举了两个简单的属性邮箱地址和邮件内容。
Getter
Setter
public class EmailSendEvent extends ApplicationEvent {private String address;private String content;public EmailSendEvent(Object source, String address, String content) {super(source);this.address address;this.content content;}
}3.2.2 定义事件发布者
事件发布类需要实现ApplicationEventPublisherAware接口, 并且需要把该对象注入到spring容器中
Component
public class EmailEventPublisher implements ApplicationEventPublisherAware {Resourceprivate ApplicationEventPublisher publisher;Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.publisher applicationEventPublisher;}/*** 发送邮件** param address 邮件地址* param content 邮件内容*/public void sendEmail(String address, String content) {// 发送邮件的逻辑System.out.println(发送邮件 address content);// 发布邮件发送事件publisher.publishEvent(new EmailSendEvent(this, address, content));System.out.println(邮件发送完毕);}}3.2.3 创建事件监听类
这里要实现ApplicationListener接口且同样要把对象注入到Spring容器内
Component
public class EmailEventListener implements ApplicationListenerEmailSendEvent {Overridepublic void onApplicationEvent(EmailSendEvent event) {// 因为此处是同步执行可以发现这里收到邮件之后前面的邮件发送才算完成// 如果需要异步可以使用注解方式System.out.println(监听器方式收到邮件 event.getAddress() event.getContent());}}3.2.4 测试效果
SpringBootTest
RunWith(SpringRunner.class)
public class TestEmailDemo {Autowiredprivate EmailEventPublisher emailEventPublisher;Testpublic void testSendEmail() {String address testexample.com;String content Hello, World!;emailEventPublisher.sendEmail(address, content);}
}此时我们运行该测试类正常情况下EmailEventListener类中将输出收到邮件的信息我们看看效果 结果也和我们预想的一致实际业务中我们就可以在监听器中做一些具体的逻辑处理如把邮件内容发送给具体的用户等等…
3.3 通过注解方式监听事件 在spring4.2版本之后可以直接使用注解的方式监听事件 事件定义和事件发布和上面一致我们增加一个注解监听的方式。
Component
public class EmailService {/*** 使用注解方式监听时间* param sendEvent: email事件*/EventListener(EmailSendEvent.class)public void receiveEmail(EmailSendEvent sendEvent) {System.out.println(注解监听方式收到邮件 sendEvent.getAddress() sendEvent.getContent());}}此时我们再运行上面的测试类得到的结果 可以看到两种监听方式都生效了ps: 正常使用时我们只需要选择一种监听方式即可
3.4 同步事件和异步事件
3.4.1 同步事件
默认的spring事件是同步的也就是说事件发送者需要等到事件被监听完成才算是一个事件发送完成。
按我们这个例子是邮件监听完成后才算邮件事件发送完成我们来测试一下。
在监听器方式中加入以下代码
public void onApplicationEvent(EmailSendEvent event) {// 此处睡眠10秒try {Thread.sleep(1000 * 10);} catch (InterruptedException e) {throw new RuntimeException(e);}// 因为此处是同步执行可以发现这里收到邮件之后前面的邮件发送才算完成// 如果需要异步可以使用注解方式System.out.println(监听器方式收到邮件 event.getAddress() event.getContent());}此时执行测试类应该是10s后才算是邮件事件发布完成看看实际效果 对于一些同步场景我们可以直接使用监听器方式然后我们更多场景应该是使用异步事件
3.4.2 异步事件
先使用EnableAsync注解开启异步事件支持
SpringBootApplication
EnableAsync
public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}
}然后修改EmailService代码加入Async注解来开启异步模式 EventListener(EmailSendEvent.class)AsyncOrder(1)public void receiveEmail(EmailSendEvent sendEvent) {try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(注解监听方式收到邮件 sendEvent.getAddress() sendEvent.getContent());}同时我们把监听器方式类注释掉只保留异步监听方式。
此时再执行测试类的时候应该是邮件事件发送后不用等待事件监听完成执行就算是该事件已经发送完成了。 3.4.3 事件监听顺序
当一个事件我们有多个监听器时可以可以使用Order注解来指定监听器的顺序这里Order(1)来指定这里的顺序为1可以看看这个注解的源码默认值为Integer.MAX_VALUE
Retention(RetentionPolicy.RUNTIME)
Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
Documented
public interface Order {int value() default Integer.MAX_VALUE;
}我们在EmailService中增加一个监听器并指定receiveEmail的顺序为100receiveEmail2的顺序为1此时应该先执行receiveEmail2
/*** 使用注解方式监听时间* param sendEvent: email事件*/EventListener(EmailSendEvent.class)AsyncOrder(100)public void receiveEmail(EmailSendEvent sendEvent) {
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }System.out.println(注解监听方式1收到邮件 sendEvent.getAddress() sendEvent.getContent());}/*** 使用注解方式监听时间* param sendEvent: email事件*/EventListener(EmailSendEvent.class)AsyncOrder(1)public void receiveEmail2(EmailSendEvent sendEvent) {System.out.println(注解监听方式2收到邮件 sendEvent.getAddress() sendEvent.getContent());}看看测试结果 跟预期一致
最后我把测试源码都放到码云上了欢迎关注公众号获取源码发送消息“Spring Event”即可。