Spring中观察者模式的应用
1. 通过@EventListener监听ApplicationEvent
Spring里的ApplicationListen相当于观察者;ApplicationEventPublisher可看作被观察对象。
当需要实现通知多个观察者的操作时可使用Spring里的ApplicationEventPublishe。观察者的操作可同步也可异步。
@Service
public class MyService {
/**
* Spring4.2之后,ApplicationEventPublisher 自动被注入到容器中,不再需要显示实现Aware接口。
*/
@Autowired
private ApplicationEventPublisher publisher;
public void doSomething(){
System.out.println(Thread.currentThread().getName()+ ":send the msg");
//发布通知
publisher.publishEvent(new MyEvent("content"));
}
}
/**
* 自定义事件
*/
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
/**
* 自定义监听器(观察者)
*/
@Component
public class MyListener {
@EventListener
public void reciveMsg(MyEvent myEvent){
String msg = (String) myEvent.getSource();
System.out.println(Thread.currentThread().getName()+ ": recive msg --"+msg);
}
}
运行结果:service调用publisher的publishEven方法会将ApplicationEvent对象传给Multicast对象,Multicast对象可以根据ApplicationEvent拿到对应的监听器集合,迭代这个集合,执行每个监听器的操作。 这个过程是同步的,也就是说service必须等待观察者操作完毕才能继续运行。
当需要观察者异步执行时可做以下修改:
在容器中添加一个自定义的Executor,在启动类上添加@EnableAsync注解
@Configuration
@ComponentScan
@EnableAsync
public class MyConfig {
@Bean("myThreadPool")
public Executor getExecutor() {
ThreadFactory namedThreadFactory = r -> {
Thread thread = new Thread(r);
thread.setName("myThreadPool");
return thread;
};
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 线程池维护线程的最少数量
executor.setCorePoolSize(5);
// 线程池维护线程的最大数量
executor.setMaxPoolSize(10);
// 缓存队列
executor.setQueueCapacity(25);
//线程名
executor.setThreadFactory(namedThreadFactory);
// 线程池初始化
executor.initialize();
return executor;
}
}
在监听器方法上添加@Async注解,指定自己定义的Executor
/**
* 自定义监听器(观察者)
*/
@Component
public class MyListener {
@Async("myThreadPool")
@EventListener
public void reciveMsg(MyEvent myEvent){
String msg = (String) myEvent.getSource();
System.out.println(Thread.currentThread().getName()+ ": recive msg --"+msg);
}
}
2. 通过@TransactionalEventListener监听事务提交
可用在事务结束后需要发送mq的场景,防止事务在生产者发送消息后才提交造成的问题
在Service的需要事务控制的方法最后发送自定义事件
@Service
public class MyService {
/**
* Spring4.2之后,ApplicationEventPublisher 自动被注入到容器中,不再需要显示实现Aware接口。
*/
@Autowired
private ApplicationEventPublisher publisher;
//添加事务注解
@Transactional(rollbackFor = Exception.class)
public void doSomething(){
System.out.println(Thread.currentThread().getName()+ ":send the msg");
//发布通知
publisher.publishEvent(new MyEvent("content"));
}
}
定义监听器
原理:publisher发送事件的方法会通过传入的事件参数查找与之对应的监听器对象,将其注册到一个容器中,当执行完事务提交操作后,会遍历容器中的监听器,执行相应的处理方法。
@Component
public class TransactionEventListener {
/**
* AFTER_COMMIT是事务提交后执行,默认就是这个
* fallbackExecution=true则会在没有事务时也执行该方法,不然只有加上事务才会监听,切记。默认是false
* @param message
* @throws Exception
*/
@TransactionalEventListener(fallbackExecution = true,phase=TransactionPhase.AFTER_COMMIT)
public void handleMessageSend(TestMqDTO message) throws Exception{
System.out.println("发送消息");
}
}
观察者模式的好处
1.被观察者不需要知道观察者是谁,也不知道有多少观察者。
2.增加或减少观察者,都不会影响被观察者的逻辑