废话前言:java
首先说一下我为何使用事件,好比如今建立一个订单可是我建立成功后要给客户发送一条短信和一个邮件提醒,自己没建立订单一系列操做就须要不少时间可是我还要去发送短信和邮件,期间还要调用其它服务来实现耗时比较长达不到客户的满意度,因此使用的方式能够说一下:spring
1:activeMQ(异步)app
2:使用spring事件监听(同步+异步)异步
下面咱们只说第二种方式async
/**
* 自定义管理事件
*/
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;
}
第二:定义一个监听ide
/**
* 测试用自定义监听器,监听事件为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
若是有优化还会更细,也请有好的想法指教指教。