博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring event
阅读量:5227 次
发布时间:2019-06-14

本文共 9393 字,大约阅读时间需要 31 分钟。

昨天看到了一遍关于spring event的帖子,觉得很好,就照着敲了一份代码,感觉对spring event有了进一步的认识。帖子链接:https://segmentfault.com/a/1190000011433514。

spring event 封装了底层,为我们方便提供了事件的发布、消息订阅。其底层原理是观察者模式。

下面直接上代码:

定义一个bean如下,使用了lombok插件(真的挺好用):

package com.abc.model;import lombok.Data;@Datapublic class User {    private String name;    private String password;}

定义一个一个注册事件:

package com.abc.event;import com.abc.model.Dog;import com.abc.model.User;import lombok.Getter;import org.springframework.context.ApplicationEvent;@Getterpublic class UserRegisterEvent extends ApplicationEvent {    private User user;    public UserRegisterEvent(Object source, User user) {        super(source);        this.user = user;    }}

 

编写service:

这里说明一下,applicationContext.publishEvent(new UserRegisterEvent(this, user)) 这个是发布事件的方法。到这里就完成了事件的发布了。当controller里面请求时候,service响应发布事件。

package com.tuandai.service;import com.tuandai.event.UserRegisterEvent;import com.tuandai.model.Dog;import com.tuandai.model.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.stereotype.Service;@Servicepublic class UserRegisterService {    @Autowired    private ApplicationContext applicationContext;    //发布事件    public void register(User user) {        //做些其他业务        applicationContext.publishEvent(new UserRegisterEvent(this, user));    }}
View Code

 

定义监听器,有两种方式。

第一种,使用@EventListener 注解方式:

package com.tuandai.listener;import com.tuandai.event.UserRegisterEvent;import com.tuandai.model.User;import org.springframework.context.event.EventListener;import org.springframework.stereotype.Component;@Componentpublic class AnnotationListener {    @EventListener     //这里如果加上@EventListener,代码运行的时候就会自动扫描到这里,也就是会执行监听的动作    public void register(UserRegisterEvent userRegisterEvent) {        User user = userRegisterEvent.getUser();        System.out.println("@UserRegisterEvent注册信息,狗命:" + user.getName() + ",密码:" + user.getPassword());    }}
View Code

第二种,继承@ApplicationListener接口的方式,重写onApplicationEvent方法:

package com.tuandai.listener;import com.tuandai.event.UserRegisterEvent;import com.tuandai.model.User;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Component;//@Component 这里如果加上@Component,代码运行的时候就会自动扫描到这里,也就是会执行监听的动作public class RegisterListener implements ApplicationListener
{ @Override public void onApplicationEvent(UserRegisterEvent userRegisterEvent) { //做些其他业务 User user=userRegisterEvent.getUser(); System.out.println("注册信息,用户名:"+user.getName()+",密码:"+user.getPassword()); }}
package com.abc.listener; import com.abc.event.UserRegisterEvent; import com.abc.model.User; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component //这里如果加上@Component,代码运行的时候就会自动扫描到这里,也就是会执行监听的动作 public class RegisterListener implements ApplicationListener
{
@Override public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {
//做些其他业务 User user=userRegisterEvent.getUser(); System.out.println("注册信息,用户名:"+user.getName()+",密码:"+user.getPassword()); } }

请求controller:http://localhost:9001/register?name=admin&password=123

结果如下:

可以看到,的确是做到了观察者的模式,订阅了消息。

下面再定义一个监听器,用于在注册之后发送邮件,这个也是基于@EventListener注解的方式的,代码如下:

package com.tuandai.listener;import com.tuandai.event.UserRegisterEvent;import com.tuandai.model.User;import org.springframework.context.event.EventListener;import org.springframework.stereotype.Component;@Componentpublic class EmalRegisterListener {    @EventListener     // 这里如果加上@EventListener,代码运行的时候就会自动扫描到这里,也就是会执行监听的动作    public void sendEmal(UserRegisterEvent userRegisterEvent) {        User user = userRegisterEvent.getUser();        System.out.println("发送邮件,用户名是:" + user.getName() + ",密码是:" + user.getPassword());    }}
View Code

再次运行,结果:

在这里可以看到,是发送邮件的监听器先于注册监听器监听到注册信息,这个在实际的生产环境中,应该是先注册这块业务,然后再是发送邮件。为此,spring event提供了一个监听先后顺序的机制:SmartApplicationListener,可保证实际的监听效果符合我们的期望。

定义一个有序的监听注册的监听器:

这段代码中,重写的 supportsEventType方法,用于确保监听的事件是用户注册的事件,实际生产环境中,可以换成自己的定义的事件。

package com.abc.listener;import com.abc.event.UserRegisterEvent;import com.abc.model.User;import com.abc.service.UserRegisterService;import org.springframework.context.ApplicationEvent;import org.springframework.context.event.SmartApplicationListener;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Component;@Componentpublic class SmartRegisterListener implements SmartApplicationListener {    @Override    public boolean supportsEventType(Class
aClass) { return aClass== UserRegisterEvent.class; } @Override public boolean supportsSourceType(Class
aClass) { return aClass== UserRegisterService.class; } /** * 只有supportsEventType和supportsSourceType返回true的时候,才执行这个方法 * @param applicationEvent */ @Override public void onApplicationEvent(ApplicationEvent applicationEvent) {
UserRegisterEvent userRegisterEvent=(UserRegisterEvent) applicationEvent; User user=userRegisterEvent.getUser(); System.out.println("注册用户,用户名是:"+ user.getName()); } @Override public int getOrder() { return 0; //这里数字越小,监听的优先级越高 }}

 

 

定义一个智能的发送邮件的监听器:

package com.tuandai.listener;import com.tuandai.event.UserRegisterEvent;import com.tuandai.model.User;import com.tuandai.service.UserRegisterService;import org.springframework.context.ApplicationEvent;import org.springframework.context.event.SmartApplicationListener;import org.springframework.stereotype.Component;/** * 智能发送邮件监听器 */@Componentpublic class SmartEmailRegisterListener implements SmartApplicationListener {    @Override    public boolean supportsEventType(Class
aClass) { return aClass== UserRegisterEvent.class; } @Override public boolean supportsSourceType(Class
aClass) { return aClass== UserRegisterService.class; } @Override public void onApplicationEvent(ApplicationEvent applicationEvent) { UserRegisterEvent userRegisterEvent=(UserRegisterEvent) applicationEvent; User user=userRegisterEvent.getUser(); System.out.println("发送邮件,用户名是:"+ user.getName()); } @Override public int getOrder() { return 1; //可以是负数 }}
View Code

 

在这两段代码中,均有个getOrder()方法,用于定义该监听器的优先级。这个数字越小,优先级越高。

 再次执行,执行结果如下:

可以看到已经是按照优先级,先注册用户,再发邮件了。

以上的监听事件,都是同步的方式。实际生产环境你中,由于某些事件可能需要耗时较大,所有事件都用同步的方式,会降低体验效果。为此,spring也提供了异步的监听事件方式。

异步监听的关键字:@Async 。但是单单使用这个关键字,还不能起作用,还需要有个自定义的配置,用于继承AsyncConfigurer。

代码如下:

package com.tuandai.confiuration;import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.AsyncConfigurer;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import org.springframework.stereotype.Component;import java.util.concurrent.Executor;@Configuration@EnableAsync   //需要加上这个注解。同事需要继承AsyncConfigurer这个才能实现异步public class ListenerAsyncConfiguration implements AsyncConfigurer {    @Override    public Executor getAsyncExecutor() {        ThreadPoolTaskExecutor threadPoolTaskExecutor=new ThreadPoolTaskExecutor();        threadPoolTaskExecutor.setCorePoolSize(3);        threadPoolTaskExecutor.setMaxPoolSize(10);        threadPoolTaskExecutor.setQueueCapacity(25);        threadPoolTaskExecutor.initialize();        return threadPoolTaskExecutor;    }    @Override    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {        return null;    }}
View Code

修改注册监听器:

package com.abc.listener; import com.abc.event.UserRegisterEvent; import com.abc.model.User; import com.abc.service.UserRegisterService; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.SmartApplicationListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @Component public class SmartRegisterListener implements SmartApplicationListener {
@Override public boolean supportsEventType(Class
aClass) {
return aClass== UserRegisterEvent.class; } @Override public boolean supportsSourceType(Class
aClass) {
return aClass== UserRegisterService.class; } /** * 只有supportsEventType和supportsSourceType返回true的时候,才执行这个方法 * @param applicationEvent */ @Override @Async public void onApplicationEvent(ApplicationEvent applicationEvent) {
try {
Thread.sleep(1000*10); } catch (InterruptedException e) {
e.printStackTrace(); } UserRegisterEvent userRegisterEvent=(UserRegisterEvent) applicationEvent; User user=userRegisterEvent.getUser(); System.out.println("注册用户,用户名是:"+ user.getName()); } @Override public int getOrder() {
return 0; //这里数字越小,监听的优先级越高 } }

在这段代码中,onApplicationEvent方法添加了@Async注解,声明这个方法是异步的方法。这段代码里,会沉睡10秒的时间。

再次运行的时候,运行的速度很快,根本不用1s,证明这个监听器的异步的方式确是起作用了。

执行结果如下:

这里要注意到的是,发送邮件的监听器的执行,先于注册监听器了。之所以出现这种情况,是因为监听器在使用异步的方式的时候,getOrder()这个方法不再起作用了。

因此,个人认为,实际生产环境中,异步的监听器应该是做一些不太重要,优先级不高,不需要实时的业务,比如主站注册,然后把数据同步到其他的副站。

而同步的方式,则是用于做一些实时性较强,并且对顺序有着严格要求的业务。比如,先在主站注册,后发发送邮件。

转载于:https://www.cnblogs.com/drafire/p/9271730.html

你可能感兴趣的文章
TP框架中的page分页实现
查看>>
[转]跨越千年的RSA算法
查看>>
传奇学者应明生
查看>>
【程序执行原理】
查看>>
第二次项目冲刺(Beta阶段)5.24
查看>>
python的多行注释
查看>>
连接Oracle需要jar包和javadoc文档的下载
查看>>
UVA 10976 - Fractions Again?!
查看>>
Dreamweaver cc新版本css单行显示
查看>>
【android】安卓的权限提示及版本相关
查看>>
3D重建的进阶了解---深度图,网格,体素,点云是什么
查看>>
JavaScript可否多线程? 深入理解JavaScript定时机制
查看>>
IOS基础学习
查看>>
PHP 导出 Excell
查看>>
python之-框架
查看>>
Java基础教程——网络基础知识
查看>>
[Web] 如何实现Web服务器和应用服务器的负载均衡?
查看>>
创建文件夹命令
查看>>
自己到底要的是什么
查看>>
this 指向
查看>>