Spring监听事件使用
废话前言:
首先说一下我为什么使用事件,比如现在创建一个订单但是我创建成功后要给客户发送一条短信和一个邮件提醒,本身没创建订单一系列操作就需要很多时间但是我还要去发送短信和邮件,期间还要调用其它服务来实现耗时比较长达不到客户的满意度,所以使用的方式可以说一下:
1:activeMQ(异步)
2:使用spring事件监听(同步+异步)
下面我们只说第二种方式
/**
* 自定义管理事件
*/
public class MessageEvent extends ApplicationEvent {
/**
* 在自定义事件的构造方法中除了第一个source参数,其他参数都可以去自定义
* 可以根据项目实际情况进行监听传参
*/
private final String message;//事件交互信息
private final String JNDI;//过滤指定监听
private final String desc;//描述可传特殊参数不满足时扩展改成MAP/Object目前没遇到太特殊的
/*
* 保存JNDI的信息
* 用来过滤具体执行的监听方法
*/
public MessageEvent(Object source,String message,String desc) {
super(source);
this.message = message;
this.JNDI = (String) source;
this.desc = desc;
}
public String getJNDI() {
return JNDI;
}
public String getMessage() {
return message;
}
public String getDesc() {
return desc;
}
第二:定义一个监听
/**
* 测试用自定义监听器,监听事件为MyEvent
*/
@Component
public class MyLisenter implements ApplicationListener<MyEvent> {
/**
* 对监听到的事件进行处理
* @param myEvent
*/
@Override
public void onApplicationEvent(MyEvent myEvent) {
/*
这里不做处理,只对消息进行透传打印,实际情况,
可以根据项目进行逻辑进行处理
*/
myEvent.printMsg(myEvent.getMsg());
System.out.println("监听到。。。");
}
}
第三:现在自定义事件和监听器都好了,我们就来看看第一个问题,监听器如何部署到ApplicationContext,有四种方式可以实现,我们一个一个看:
2.监听器部署到ApplicationContext,实际上就是将将监听器交给Spring 容器管理,所以最简单的方法只需在自定义的PrintListener上加上@Component注解就行了把上图//事件配置监听注掉就行了这个注解就可以实现。
4.使用@EventListener注解,先看代码,建立一个普通的java类并交给spring容器,其中一个处理event的方法,加上该注解,删掉配置文件中的配置。
我们注意到ApplicationContext的事件发布能力是继承自ApplicationEventPublisher,并且ApplicationContextAware中有这样一段注释:
测试代码:
(异步方式,可指定监听事件)
第一步:在启动类添加注解@EnableAsync,自定义线程池类
创建一个配置类ExecutorConfig,用来定义如何创建一个ThreadPoolTaskExecutor,要使用@Configuration和@EnableAsync这两个注解,表示这是个配置类,并且是线程池的配置类
如下所示:
/**
* 连接池配置
*/
@Configuration
@EnableAsync
public class TaskExecutePool {
private static final Logger log = LoggerFactory.getLogger(TaskExecutePool.class);
@Bean("myTaskAsyncPool")
public Executor myTaskAsyncPool() {
log.info("start TaskExecutePool myTaskAsyncPool");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(10);
//配置核心线程数
executor.setMaxPoolSize(20);
//配置队列容量
executor.setQueueCapacity(1000);
//设置线程活跃时间
executor.setKeepAliveSeconds(60);
//设置线程名
executor.setThreadNamePrefix("myTaskAsyn-");
//设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
注意,上面的方法名称为asyncServiceExecutor,
@Async("asyncServiceExecutor"):即配置线程池的方法名,此处如果不写自定义线程池的方法名,会使用默认的线程池
第二步:自定义事件发布类
/**
* 自定义管理事件
*/
public class MessageEvent extends ApplicationEvent {
/**
* 在自定义事件的构造方法中除了第一个source参数,其他参数都可以去自定义
* 可以根据项目实际情况进行监听传参
*/
private final String message;//事件交互信息
private final String JNDI;//过滤指定监听
private final String desc;//描述可传特殊参数不满足时扩展改成MAP/Object目前没遇到太特殊的
/*
* 保存JNDI的信息
* 用来过滤具体执行的监听方法
*/
public MessageEvent(Object source,String message,String desc) {
super(source);
this.message = message;
this.JNDI = (String) source;
this.desc = desc;
}
public String getJNDI() {
return JNDI;
}
public String getMessage() {
return message;
}
public String getDesc() {
return desc;
}
第三步:抽取事件发布公共类
/**
* 事件发布类
*/
@Component
public class EventPublisher implements ApplicationEventPublisherAware {
private static ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public static void publishEvent(ApplicationEvent applicationEvent) {
applicationEventPublisher.publishEvent(applicationEvent);
}
}
第四步:编写监听事件
@EventListener有个参数condition进行event属性过滤。
比如我查的看的有这样的目前没研究太多:
@EventListener
@EventListener(condition = "#event.test == 'foo'")(我使用的这个)
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
@EventListener(classes = {BlackListEvent.class})
/**
* 监听事件:送开通
*/
@Component
public class ProvNotifier {
private static final Logger log = LoggerFactory.getLogger(ProvNotifier.class);
@Autowired
private IProvSvc iProvSvc;
/**
* 监听送开通的消息
* @param event
*/
@Async
@EventListener( condition= "#event.JNDI == 'sendToProv'")
public void onApplicationEvent(MessageEvent event) {
log.info(" ==>异步事件启动 onApplicationEvent sendToProv Message:" + event.getMessage());
try {
iProvSvc.sendToProv(event.getMessage(),event.getDesc());
log.info(" ==>送开通成功!");
} catch (Exception e) {
log.error(" %%%%%% onApplicationEvent listener sendToProv:" + e.getMessage());
e.printStackTrace();
}
}
}
第五步:测试
结果:
这是异步的实现基本结束,也可以根据自己的业务规则实现配置化。
看了很多大神贴也有抄袭多见谅:https://blog.csdn.net/LouisQMei/article/details/79605590
如果有优化还会更细,也请有好的想法指教指教。