1 案例分析
引用 : https://zhuanlan.zhihu.com/p/101128672
1.1假设业务场景
用户下单成功之后,平台需要发送短信通知下单成功
最直观的写法
public void order(){
// 下单成功
System.out.println("下单成功...");
// 发送短信
sendSms();
}
假设过了一个月之后,下单成功之后,还需要通知物流系统发货
于是就需要修改原有代码
public void order(){
// 下单成功
System.out.println("下单成功...");
// 发送短信
sendSms();
// 通知车队发货
notifyCar();
}
假设又过了几个月,不需要通知物流系统了,那么又需要修改原有代码
public void order(){
// 下单成功
System.out.println("下单成功...");
// 发送短信
sendSms();
// 车队没了,注释掉这行代码
// notifyCar();
}
根据编码的基本原则,开闭原则,这样的代码是合格的
于是根据一种以增量的方式应对变化的需求,在并发较小时可使用Spring的监听机制,在并发较大时,需要使用消息中间件
2 Spring监听机制
订单服务
@Service
public class OrderService {
@Autowired
private ApplicationContext applicationContext;
public void order() {
// 下单成功
System.out.println("下单成功...");
// 发布通知
applicationContext.publishEvent(new OrderSuccessEvent(this));
System.out.println("main线程结束...");
}
}
OrderSuccessEvent(继承ApplicationEvent,自定义事件)
public class OrderSuccessEvent extends ApplicationEvent {
public OrderSuccessEvent(Object source) {
super(source);
}
}
SmsService(实现ApplicationListener,监听OrderSuccessEvent)
/**
* 短信服务,监听OrderSuccessEvent
*/
@Service
public class SmsService implements ApplicationListener<OrderSuccessEvent> {
@Override
public void onApplicationEvent(OrderSuccessEvent event) {
this.sendSms();
}
/**
* 发送短信
*/
public void sendSms()
System.out.println("发送短信...");
}
}
测试输出
下单成功...
发送短信...
main线程结束...
如果后期针对下单成功有新的操作,可以新写一个事件监听类:
/**
* 物流服务
*/
@Service
public class CarService implements ApplicationListener<OrderSuccessEvent> {
@Override
public void onApplicationEvent(OrderSuccessEvent event) {
this.dispatch();
}
public void dispatch() {
System.out.println("发车咯...");
}
}
这就是“以增量的方式应对变化的需求”,而不是去修改已有的代码。假设有B接口调用了C接口,你修改了C接口,那么B接口可能业务结果就错了,此时调用B接口的A接口也可能受到影响,是连锁反应。所以,一般我们都提倡“对扩展开放,对修改关闭”的原则。
注解方式监听
/**
* 短信服务,监听LendSuccessEvent,但不用实现ApplicationListener
*/
@Service
public class SmsService {
/**
* 发送短信 @EventListener指定监听的事件
*/
@EventListener(LendSuccesssEvent.class)
public void sendSms() {
try {
Thread.sleep(1000L * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送短信...");
}
}
目前为止,方法的执行都是同步的,但是在业务中,只需要返回订单执行业务的逻辑,不需要等待发送短信,通知物流的时间,所以需要将消息发布的执行机制改为异步执行
Spring异步机制
当SimpleApplicationEventMulticaster中的Executor不为null,就会执行异步通知
@Configuration
public class AsyncEventConfig {
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster
= new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}
}
= new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}
}
Spring监听原理 : https://editor.youkuaiyun.com/md?not_checkout=1&articleId=123542755