以实际案例出发,商城商家发货后,会通过短信和邮件方式通知买家。但后期可能会增加微信通知和qq通知,想到设计模式中的观察者模式,于是结合spring,整理一下代码流程
1.定义事件 (继承ApplicationEvent抽象类 )
import org.springframework.context.ApplicationEvent;
import java.util.Map;
/**
* @Description 发货事件(使用观察者模式实现发货后的事件处理,如邮件通知、短信提醒等)
* @Author: yanxh<br>
* @Date 2019-12-11 10:39<br>
* @Version 1.0<br>
*/
public class OrderDeliveryEvent extends ApplicationEvent {
private Map<String, Object> params;
public OrderDeliveryEvent(Object source, Map<String, Object> params) {
super(source);
this.params = params;
}
public Map<String, Object> getParams() {
return params;
}
public void setParams(Map<String, Object> params) {
this.params = params;
}
}
2.定义事件监听者 (实现ApplicationListener接口)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
/**
* @Description 订单发货邮件监听
* @Author: yanxh<br>
* @Date 2019-12-11 10:44<br>
* @Version 1.0<br>
*/
@Component
public class OrderDeliveryEmailListener implements ApplicationListener<OrderDeliveryEvent> {
@Autowired
private RestTemplate restTemplate;
/** 线程 */
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
/**
* @Description todo
* @Author: yanxh<br>
* @Date 2019/12/11 13:22<br>
* @Version 1.0<br>
*/
@Override
public void onApplicationEvent(OrderDeliveryEvent event) {
// 发货后传递的数据
Map<String, Object> params = event.getParams();
// 下面为处理邮件发送的逻辑。。因只做观察者说明,所以邮件发送的具体业务代码暂不透漏了
Long orderId = Long.valueOf(String.valueOf(params.get("orderId")));
Long billId = Long.valueOf(String.valueOf(params.get("billId")));
// 放于异步线程中处理
taskExecutor.execute(new SendMailToOrg(orderId, billId, restTemplate));
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
/**
* @Description 订单发货短信监听
* @Author: yanxh<br>
* @Date 2019-12-11 10:44<br>
* @Version 1.0<br>
*/
@Component
public class OrderDeliveryMessageListener implements ApplicationListener<OrderDeliveryEvent> {
@Autowired
private RestTemplate restTemplate;
/** 线程 */
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
@Override
public void onApplicationEvent(OrderDeliveryEvent event) {
// 发短信的业务逻辑,异步线程处理
taskExecutor.execute(new OrderDeliveryMessage(event.getParams(), restTemplate));
}
}
多个观察者在spring启动时会自动绑定到接口中泛型代表的事件中
3.触发事件
发货逻辑。。。
// 事件传递的信息
Map<String, Object> params = new HashMap<String, Object>(0);
ApplicationEvent orderDeliveryEvent = new OrderDeliveryEvent(this, params);
// 调用父容器发布事件
ContextLoader.getCurrentWebApplicationContext().publishEvent(orderDeliveryEvent);
注意事项
在web项目中如果同时集成了spring和springMVC的话,上下文中会存在两个容器,
即spring的applicationContext.xml的父容器和springMVC的applicationContext-mvc.xml的子容器
通过applicationContext发送通知的时候,事件会被两个容器发布
所以要通过获取父容器的方式去发布事件,避免事件重复发送