引用: https://juejin.im/post/5d93fa78f265da5b991d5133
谈到Spring 事件驱动模型,我想大家都不陌生,事件驱动模型,通常也可以说是观察者设计模式。
java本身也自带了对事件驱动的支持,但是大部分都是用于我们的客户端开发,比如GUI ,Swing这些,而Spring 则在java的基础上,扩展了对事件驱动的支持。
废话不多说,直接撸代码。
我们新建一个类NotifyEvent 继承ApplicationEvent,用于封装我们事件额外的信息,这里则是String类型的msg,用于记录详细的事件内容。
public class NotifyEvent extends ApplicationEvent {
@Getter
private String msg;
public NotifyEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
}
NotifyPublisher用于我们事件的发布工作,该类实现了ApplicationContextAware
并重写了setApplicationContext 方法,这一步的目的是可以获取我们Spring的应用上下文,因为事件的发布是需要应用上下文来做的.
@Component
@Slf4j
public class NotifyPublisher implements ApplicationContextAware {
private ApplicationContext ctx; //应用上下文
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.ctx= applicationContext;
}
public void publishEvent(int type, String json) {
ctx.publishEvent(new NotifyEvent(type, json));
}
}
最后一步就是实现一个类作为事件的订阅者啦,当事件发布时,会通知订阅者,然后订阅者做相关的处理,比如新用户注册发送事件自动发送欢迎邮件等等。
@Component
@Slf4j
//指定具体的事件类型: E extends ApplicationEvent
public class NotifyListener implements ApplicationListener<NotifyEvent> {
@Override
public void onApplicationEvent(NotifyEvent event) {
log.info("收到事件{}",event.getMsg());
}
}
@EventListener
Spring 4.2 版本更新的EventListener,可以很方便帮助我们实现事件与方法的绑定,只需要在目标方法上加上EventListener即可。
@Component
public class MqListener {
@EventListener
//参数NotifyEvent ,当有NotifyEvent 类型的事件发生时,交给sayHello方法处理
public void sayHello(NotifyEvent notifyEvent){
log.info("收到事件{}",event.getMsg());
}
}
public class AuthenticationCenterApplication implements CommandLineRunner {
//略...
@Autowired
private NotifyPublisher mqPublisher;
@Override
public void run(String... args) throws Exception {
AtomicInteger loop = new AtomicInteger(1);
while (loop.get() < 10) {
mqPublisher.publishEvent(1, "nihao_" + loop.getAndIncrement());
TimeUnit.SECONDS.sleep(1);
}
}
}
但是可以看到上述的执行内容,全部是由main
线程执行的。
Spring 也提供了@Async 注解来实现异步事件的消费。用起来也很简单,只需要在
@EventListener
上加上@Async
onApplicationEvent
方法上添加@Async
springboot开启@EnableAsync 即可支持异步。
@EnableAsync
public class AuthenticationCenterApplication implements CommandLineRunner {
}
自定义线程池
Springboot默认的异步线程池名为"taskExecutor":
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor, 可以通过注入
java.util.concurrent.Executor`进行覆盖:
@Bean
public Executor taskExecutor(){
return new ThreadPoolExecutor(2,
4,
1000,
TimeUnit.SECONDS,
new ArrayBlockingQueue(5),
new UserThreadFactory("myAysnc")
);
}
static class UserThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger nextId = new AtomicInteger(1);
UserThreadFactory(String whatFeatureOfGroup) {
namePrefix = whatFeatureOfGroup + "-pool-";
}
@Override
public Thread newThread(Runnable task) {
String name = namePrefix + nextId.getAndIncrement();
Thread thread = new Thread(null, task, name,0);
return thread;
}
}