- 浏览: 7937104 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (2425)
- 软件工程 (75)
- JAVA相关 (662)
- ajax/web相关 (351)
- 数据库相关/oracle (218)
- PHP (147)
- UNIX/LINUX/FREEBSD/solaris (118)
- 音乐探讨 (1)
- 闲话 (11)
- 网络安全等 (21)
- .NET (153)
- ROR和GOG (10)
- [网站分类]4.其他技术区 (181)
- 算法等 (7)
- [随笔分类]SOA (8)
- 收藏区 (71)
- 金融证券 (4)
- [网站分类]5.企业信息化 (3)
- c&c++学习 (1)
- 读书区 (11)
- 其它 (10)
- 收藏夹 (1)
- 设计模式 (1)
- FLEX (14)
- Android (98)
- 软件工程心理学系列 (4)
- HTML5 (6)
- C/C++ (0)
- 数据结构 (0)
- 书评 (3)
- python (17)
- NOSQL (10)
- MYSQL (85)
- java之各类测试 (18)
- nodejs (1)
- JAVA (1)
- neo4j (3)
- VUE (4)
- docker相关 (1)
最新评论
-
xiaobadi:
jacky~~~~~~~~~
推荐两个不错的mybatis GUI生成工具 -
masuweng:
(转)JAVA获得机器码的实现 -
albert0707:
有些扩展名为null
java 7中可以判断文件的contenttype了 -
albert0707:
非常感谢!!!!!!!!!
java 7中可以判断文件的contenttype了 -
zhangle:
https://zhuban.me竹板共享 - 高效便捷的文档 ...
一个不错的网络白板工具
http://blog.csdn.net/qwe6112071/article/details/50966660
分析需求引入事件机制
使用spring的事件机制有助于对我们的项目进一步的解耦。假如现在我们面临一个需求:
我需要在用户注册成功的时候,根据用户提交的邮箱、手机号信息,向用户发送邮箱认证和手机号短信通知。传统的做法之一是在我们的UserService层注入邮件发送和短信发送的相关类,然后在完成用户注册同时,调用对应类方法完成邮件发送和短信发送
但这样做的话,会把我们邮件、短信发送的业务与我们的UserService的逻辑业务耦合在了一起。耦合造成的常见缺点是,我(甚至假设很频繁的)修改了邮件、短信发送的API,我就可能需要在UserService层修改相应的调用方法,但这样做人家UserService就会很无辜并吐槽:你改邮件、短信发送的业务,又不关我的事,干嘛老改到我身上来了?这就是你的不对了。
对呀!根据职责分明的设计原则,人家UserService就只该管用户管理部分的业务逻辑,你老让它干别人干的事,它当然不高兴了!
那该怎么拌?凉拌?不不不。。。我们可以通过spring的事件机制来实现解耦呀。利用观察者设计模式,设置监听器来监听userService的注册事件(同时,我们可以很自然地将userService理解成了事件发布者),一旦userService注册了,监听器就完成相应的邮箱、短信发送工作(同时,我们也可以很自然地将发送邮件、发送短信理解成我们的事件源)。这样userService就不用管别人的事了,只需要在完成注册功能时候,当下老大,号令手下(监听器),让它完成短信、邮箱的发送工作。
事件实例分析
在这里面,我们涉及到三个主要对象:事件发布者、事件源、事件监听器。根据这三个对象,我们来配置我们的注册事件实例:
1. 定义事件源
利用事件通信的第一步往往便是定义我们的事件。在spring中,所有事件都必须扩展抽象类ApplicationEvent,同时将事件源作为构造函数参数,在这里,我们定义了发邮件、发短信两个事件如下所示
/*****************邮件发送事件源*************/
public class SendEmailEvent extends ApplicationEvent {
//定义事件的核心成员:发送目的地,共监听器调用完成邮箱发送功能
private String emailAddress;
public SendEmailEvent(Object source,String emailAddress ) {
//source字面意思是根源,意指发送事件的根源,即我们的事件发布者
super(source);
this.emailAddress = emailAddress;
}
public String getEmailAddress() {
return emailAddress;
}
}
/*****************短信发送事件源*************/
public class sendMessageEvent extends ApplicationEvent {
private String phoneNum;
public sendMessageEvent(Object source,String phoneNum ) {
super(source);
this.phoneNum = phoneNum;
}
public String getPhoneNum() {
return phoneNum;
}
}
2. 定义事件监听器
事件监听类需要实现我们的ApplicationListener接口,除了可以实现ApplicationListener定义事件监听器外,我们还可以让事件监听类实现SmartApplicationListener(智能监听器)接口,。关于它的具体用法和实现可参考我的下一篇文章《spring学习笔记(14)趣谈spring 事件机制[2]:多监听器流水线式顺序处理 》。而此外,如果我们事件监听器监听的事件类型唯一的话,我们可以通过泛型来简化配置。
现在我们先来看看本例定义:
public class RegisterListener implements ApplicationListener {
/*
*当我们的发布者发布时间时,我们的监听器收到信号,就会调用这个方法
*我们对其进行重写来适应我们的需求
*@Param event:我们的事件源
*/
@Override
public void onApplicationEvent(ApplicationEvent event) {
//我们定义了两个事件:发短信,发邮箱,他们一旦被发布都会被此方法调用
//于是我们需要判断当前event的具体类型
if(event instanceof SendEmailEvent){//如果是发邮箱事件
System.out.println("正在向" + ((SendEmailEvent) event).getEmailAddress()+ "发送邮件......");//模拟发送邮件事件
try {
Thread.sleep(1* 1000);//模拟请求邮箱服务器、验证账号密码,发送邮件耗时。
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("邮件发送成功!");
}else if(event instanceof sendMessageEvent){//是发短信事件
event = (sendMessageEvent) event;
System.out.println("正在向" + ((sendMessageEvent) event).getPhoneNum()+ "发送短信......");//模拟发送邮短信事件
try {
Thread.sleep(1* 1000);//模拟发送短信过程
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("短信发送成功!");
}
}
}
/******************通过泛型配置实例如下******************/
public class RegisterListener implements ApplicationListener<SendEmailEvent> {//这里使用泛型
@Override//因为使用了泛型,我们的重写方法入参事件就唯一了。
public void onApplicationEvent(SendEmailEvent event) {
.....
}
....
}
3. 定义事件发布者
事件发送的代表类是ApplicationEventPublisher我们的事件发布类常实现ApplicationEventPublisherAware接口,同时需要定义成员属性ApplicationEventPublisher来发布我们的事件。
除了通过实现ApplicationEventPublisherAware外,我们还可以实现ApplicationContextAware接口来完成定义,ApplicationContext接口继承了ApplicationEventPublisher。ApplicationContext是我们的事件容器上层,我们发布事件,也可以通过此容器完成发布。下面使用两种方法来定义我们的发布者
在本例中,我们的时间发布者自然就是我们的吐槽者,userService:
/**********方法一:实现除了通过实现ApplicationEventPublisherAware接口************/
public class UserService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;//底层事件发布者
@Override
public void setApplicationEventPublisher(//通过Set方法完成我们的实际发布者注入
ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void doLogin(String emailAddress,String phoneNum) throws InterruptedException{
Thread.sleep(200);//模拟用户注册的相关业务逻辑处理
System.out.println("注册成功!");
//下列向用户发送邮件
SendEmailEvent sendEmailEvent = new SendEmailEvent(this,emailAddress);//定义事件
sendMessageEvent sendMessageEvent = new sendMessageEvent(this, phoneNum);
applicationEventPublisher.publishEvent(sendEmailEvent);//发布事件
applicationEventPublisher.publishEvent(sendMessageEvent);
}
//...忽略其他用户管理业务方法
}
/**********方法二:实现除了通过实现ApplicationContext接口************/
public class UserService2 implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
public void doLogin(String emailAddress,String phoneNum) throws InterruptedException{
Thread.sleep(200);//模拟用户注册的相关业务逻辑处理
System.out.println("注册成功!");
//下列向用户发送邮件
SendEmailEvent sendEmailEvent = new SendEmailEvent(this,emailAddress);//定义事件
sendMessageEvent sendMessageEvent = new sendMessageEvent(this, phoneNum);
applicationContext.publishEvent(sendEmailEvent);//发布事件
applicationContext.publishEvent(sendMessageEvent);
}
//...忽略其他用户管理业务方法
}
4. 在IOC容器注册监听器
<!-- 在spring容器中注册事件监听器,
应用上下文将会识别实现了ApplicationListener接口的Bean,
并在特定时刻将所有的事件通知它们 -->
<bean id="RegisterListener" class="test.event.RegisterListener" />
<!-- 注册我们的发布者,后面测试用到 -->
<bean id="userService" class="test.event.UserService" />
5. 测试方法
public static void main(String args[]) throws InterruptedException{
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:test/event/event.xml");
UserService userService = (UserService) ac.getBean("userService");
Long beginTime = System.currentTimeMillis();
userService.doLogin("zenghao@google.com","12345678911");//完成注册请求
System.out.println("处理注册相关业务耗时" + (System.currentTimeMillis() - beginTime )+ "ms");
System.out.println("处理其他业务逻辑");
Thread.sleep(500);//模拟处理其他业务请求耗时
System.out.println("处理所有业务耗时" + (System.currentTimeMillis() - beginTime )+ "ms");
System.out.println("向客户端发送注册成功响应");
}
6. 测试结果及分析
调用上面测试方法,控制台打印信息
注册成功!
正在向zenghao@google.com发送邮件……
邮件发送成功!
正在向12345678911发送短信……
发送成功!
处理注册相关业务耗时2201ms
处理其他业务逻辑开始..
处理其他业务逻辑结束..
处理所有业务耗时2701ms
向客户端发送注册成功响应
在本例中,我们通过事件机制完成了userService和邮件、短信发送业务的解耦。但观察我们的测试结果,我们会发现,这样的用户体验真是糟糕透了:天呐,我去你那注册个用户,要我等近3秒钟!这太久了!
为什么会这么久?我们根据方法分析:
1. 注册查询数据库用了200ms(查询用户名、邮箱、手机号有没被使用,插入用户信息到数据库等操作)
2. 发送邮件用了1000ms
3. 发送短信用了1000ms
4. 处理其他业务逻辑(保存用户信息到session,其他信息数据处理等)
第1,4步的时间耗损我们很难优化,但2,3步是主要耗时的地方,我们能不能想办法把它缩减掉了,它把我们的正常的业务处理堵塞了。什么?堵塞,想到堵塞,我们会很自然地想到非堵塞,那就通过异步来完成2,3呗!
7. 异步拓展。
在spring3以上,拓展了自己独立的时间机制,我们可以使用@Async来完成异步配置。
首先我们需要在我们的IOC容器增加
<!--先在命名空间中增加我们的task标签,注意它们的添加位置
xmlns 多加下面的内容:
xmlns:task="http://www.springframework.org/schema/task"
然后xsi:schemaLocation多加下面的内容
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
-->
<!-- 我们的异步事件配置,非常简单 -->
<!--开启注解调度支持 @Async @Scheduled-->
<task:annotation-driven/>
然后在我们的事件监听器中添加@Async注解
/***************我们可以在类名上添加****************/
@Async
public class RegisterListener implements ApplicationListener {
......
}
/****************也可以在方法体上添加************/
@Async
public class RegisterListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
.....
}
}
14
然后,再调用我们的同样的测试方法,这次我们的结果变成:
注册成功!
正在向zenghao@google.com发送邮件……
处理注册相关业务耗时201ms ————此时邮件发送还没有结束,和邮件发送异步了
正在向12345678911发送短信….. ————–短信发送和邮件发送和主业务处理程序都异步了!
处理其他业务逻辑开始..
处理其他业务逻辑结束..
处理所有业务耗时701ms
向客户端发送注册成功响应 ——客户端耗时701ms就收到响应了。
邮件发送成功! —-这个时候邮箱才发完
短信发送成功!
从以上的测试结果我们,我们的邮箱发送和短信发送都分别单独地异步完成了,大大缩短了我们主业务处理事件,也提高了用户体验
小结
从本例可以看出,不同业务功能的生硬组合,会出现逻辑处理混乱的严重耦合现象,比如userService类既处理自己的用户逻辑,还要处理邮箱等发送的逻辑,这是不是也意味着,如果以后我们拓展更多的功能,我们的userService类还要出现更多的逻辑处理,来个大杂烩?,这同时还可能会为我们主要业务处理带来不必要的阻塞。当然,为了防止阻塞,我们还可以创建新的线程来异步,但这样原来的类就显得更加杂乱臃肿了。
使用spring事件机制能很好地帮助我们消除不同业务间的深耦合关系。它强大的任务调度还能帮助我们简洁地实现事件异步。
关于事件的一些其他用法可参考我的下一篇博文《趣谈spring 事件机制[2]:多监听器流水线式顺序处理》
关于任务调度的相关框架和使用可参考我的专栏《深入浅出Quartz任务调度》。
实例代码下载
本篇博文的实例代码可到我的github仓库https://github.com/jeanhao/spring的event文件夹下下载。
分析需求引入事件机制
使用spring的事件机制有助于对我们的项目进一步的解耦。假如现在我们面临一个需求:
我需要在用户注册成功的时候,根据用户提交的邮箱、手机号信息,向用户发送邮箱认证和手机号短信通知。传统的做法之一是在我们的UserService层注入邮件发送和短信发送的相关类,然后在完成用户注册同时,调用对应类方法完成邮件发送和短信发送
但这样做的话,会把我们邮件、短信发送的业务与我们的UserService的逻辑业务耦合在了一起。耦合造成的常见缺点是,我(甚至假设很频繁的)修改了邮件、短信发送的API,我就可能需要在UserService层修改相应的调用方法,但这样做人家UserService就会很无辜并吐槽:你改邮件、短信发送的业务,又不关我的事,干嘛老改到我身上来了?这就是你的不对了。
对呀!根据职责分明的设计原则,人家UserService就只该管用户管理部分的业务逻辑,你老让它干别人干的事,它当然不高兴了!
那该怎么拌?凉拌?不不不。。。我们可以通过spring的事件机制来实现解耦呀。利用观察者设计模式,设置监听器来监听userService的注册事件(同时,我们可以很自然地将userService理解成了事件发布者),一旦userService注册了,监听器就完成相应的邮箱、短信发送工作(同时,我们也可以很自然地将发送邮件、发送短信理解成我们的事件源)。这样userService就不用管别人的事了,只需要在完成注册功能时候,当下老大,号令手下(监听器),让它完成短信、邮箱的发送工作。
事件实例分析
在这里面,我们涉及到三个主要对象:事件发布者、事件源、事件监听器。根据这三个对象,我们来配置我们的注册事件实例:
1. 定义事件源
利用事件通信的第一步往往便是定义我们的事件。在spring中,所有事件都必须扩展抽象类ApplicationEvent,同时将事件源作为构造函数参数,在这里,我们定义了发邮件、发短信两个事件如下所示
/*****************邮件发送事件源*************/
public class SendEmailEvent extends ApplicationEvent {
//定义事件的核心成员:发送目的地,共监听器调用完成邮箱发送功能
private String emailAddress;
public SendEmailEvent(Object source,String emailAddress ) {
//source字面意思是根源,意指发送事件的根源,即我们的事件发布者
super(source);
this.emailAddress = emailAddress;
}
public String getEmailAddress() {
return emailAddress;
}
}
/*****************短信发送事件源*************/
public class sendMessageEvent extends ApplicationEvent {
private String phoneNum;
public sendMessageEvent(Object source,String phoneNum ) {
super(source);
this.phoneNum = phoneNum;
}
public String getPhoneNum() {
return phoneNum;
}
}
2. 定义事件监听器
事件监听类需要实现我们的ApplicationListener接口,除了可以实现ApplicationListener定义事件监听器外,我们还可以让事件监听类实现SmartApplicationListener(智能监听器)接口,。关于它的具体用法和实现可参考我的下一篇文章《spring学习笔记(14)趣谈spring 事件机制[2]:多监听器流水线式顺序处理 》。而此外,如果我们事件监听器监听的事件类型唯一的话,我们可以通过泛型来简化配置。
现在我们先来看看本例定义:
public class RegisterListener implements ApplicationListener {
/*
*当我们的发布者发布时间时,我们的监听器收到信号,就会调用这个方法
*我们对其进行重写来适应我们的需求
*@Param event:我们的事件源
*/
@Override
public void onApplicationEvent(ApplicationEvent event) {
//我们定义了两个事件:发短信,发邮箱,他们一旦被发布都会被此方法调用
//于是我们需要判断当前event的具体类型
if(event instanceof SendEmailEvent){//如果是发邮箱事件
System.out.println("正在向" + ((SendEmailEvent) event).getEmailAddress()+ "发送邮件......");//模拟发送邮件事件
try {
Thread.sleep(1* 1000);//模拟请求邮箱服务器、验证账号密码,发送邮件耗时。
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("邮件发送成功!");
}else if(event instanceof sendMessageEvent){//是发短信事件
event = (sendMessageEvent) event;
System.out.println("正在向" + ((sendMessageEvent) event).getPhoneNum()+ "发送短信......");//模拟发送邮短信事件
try {
Thread.sleep(1* 1000);//模拟发送短信过程
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("短信发送成功!");
}
}
}
/******************通过泛型配置实例如下******************/
public class RegisterListener implements ApplicationListener<SendEmailEvent> {//这里使用泛型
@Override//因为使用了泛型,我们的重写方法入参事件就唯一了。
public void onApplicationEvent(SendEmailEvent event) {
.....
}
....
}
3. 定义事件发布者
事件发送的代表类是ApplicationEventPublisher我们的事件发布类常实现ApplicationEventPublisherAware接口,同时需要定义成员属性ApplicationEventPublisher来发布我们的事件。
除了通过实现ApplicationEventPublisherAware外,我们还可以实现ApplicationContextAware接口来完成定义,ApplicationContext接口继承了ApplicationEventPublisher。ApplicationContext是我们的事件容器上层,我们发布事件,也可以通过此容器完成发布。下面使用两种方法来定义我们的发布者
在本例中,我们的时间发布者自然就是我们的吐槽者,userService:
/**********方法一:实现除了通过实现ApplicationEventPublisherAware接口************/
public class UserService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;//底层事件发布者
@Override
public void setApplicationEventPublisher(//通过Set方法完成我们的实际发布者注入
ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void doLogin(String emailAddress,String phoneNum) throws InterruptedException{
Thread.sleep(200);//模拟用户注册的相关业务逻辑处理
System.out.println("注册成功!");
//下列向用户发送邮件
SendEmailEvent sendEmailEvent = new SendEmailEvent(this,emailAddress);//定义事件
sendMessageEvent sendMessageEvent = new sendMessageEvent(this, phoneNum);
applicationEventPublisher.publishEvent(sendEmailEvent);//发布事件
applicationEventPublisher.publishEvent(sendMessageEvent);
}
//...忽略其他用户管理业务方法
}
/**********方法二:实现除了通过实现ApplicationContext接口************/
public class UserService2 implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
public void doLogin(String emailAddress,String phoneNum) throws InterruptedException{
Thread.sleep(200);//模拟用户注册的相关业务逻辑处理
System.out.println("注册成功!");
//下列向用户发送邮件
SendEmailEvent sendEmailEvent = new SendEmailEvent(this,emailAddress);//定义事件
sendMessageEvent sendMessageEvent = new sendMessageEvent(this, phoneNum);
applicationContext.publishEvent(sendEmailEvent);//发布事件
applicationContext.publishEvent(sendMessageEvent);
}
//...忽略其他用户管理业务方法
}
4. 在IOC容器注册监听器
<!-- 在spring容器中注册事件监听器,
应用上下文将会识别实现了ApplicationListener接口的Bean,
并在特定时刻将所有的事件通知它们 -->
<bean id="RegisterListener" class="test.event.RegisterListener" />
<!-- 注册我们的发布者,后面测试用到 -->
<bean id="userService" class="test.event.UserService" />
5. 测试方法
public static void main(String args[]) throws InterruptedException{
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:test/event/event.xml");
UserService userService = (UserService) ac.getBean("userService");
Long beginTime = System.currentTimeMillis();
userService.doLogin("zenghao@google.com","12345678911");//完成注册请求
System.out.println("处理注册相关业务耗时" + (System.currentTimeMillis() - beginTime )+ "ms");
System.out.println("处理其他业务逻辑");
Thread.sleep(500);//模拟处理其他业务请求耗时
System.out.println("处理所有业务耗时" + (System.currentTimeMillis() - beginTime )+ "ms");
System.out.println("向客户端发送注册成功响应");
}
6. 测试结果及分析
调用上面测试方法,控制台打印信息
注册成功!
正在向zenghao@google.com发送邮件……
邮件发送成功!
正在向12345678911发送短信……
发送成功!
处理注册相关业务耗时2201ms
处理其他业务逻辑开始..
处理其他业务逻辑结束..
处理所有业务耗时2701ms
向客户端发送注册成功响应
在本例中,我们通过事件机制完成了userService和邮件、短信发送业务的解耦。但观察我们的测试结果,我们会发现,这样的用户体验真是糟糕透了:天呐,我去你那注册个用户,要我等近3秒钟!这太久了!
为什么会这么久?我们根据方法分析:
1. 注册查询数据库用了200ms(查询用户名、邮箱、手机号有没被使用,插入用户信息到数据库等操作)
2. 发送邮件用了1000ms
3. 发送短信用了1000ms
4. 处理其他业务逻辑(保存用户信息到session,其他信息数据处理等)
第1,4步的时间耗损我们很难优化,但2,3步是主要耗时的地方,我们能不能想办法把它缩减掉了,它把我们的正常的业务处理堵塞了。什么?堵塞,想到堵塞,我们会很自然地想到非堵塞,那就通过异步来完成2,3呗!
7. 异步拓展。
在spring3以上,拓展了自己独立的时间机制,我们可以使用@Async来完成异步配置。
首先我们需要在我们的IOC容器增加
<!--先在命名空间中增加我们的task标签,注意它们的添加位置
xmlns 多加下面的内容:
xmlns:task="http://www.springframework.org/schema/task"
然后xsi:schemaLocation多加下面的内容
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
-->
<!-- 我们的异步事件配置,非常简单 -->
<!--开启注解调度支持 @Async @Scheduled-->
<task:annotation-driven/>
然后在我们的事件监听器中添加@Async注解
/***************我们可以在类名上添加****************/
@Async
public class RegisterListener implements ApplicationListener {
......
}
/****************也可以在方法体上添加************/
@Async
public class RegisterListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
.....
}
}
14
然后,再调用我们的同样的测试方法,这次我们的结果变成:
注册成功!
正在向zenghao@google.com发送邮件……
处理注册相关业务耗时201ms ————此时邮件发送还没有结束,和邮件发送异步了
正在向12345678911发送短信….. ————–短信发送和邮件发送和主业务处理程序都异步了!
处理其他业务逻辑开始..
处理其他业务逻辑结束..
处理所有业务耗时701ms
向客户端发送注册成功响应 ——客户端耗时701ms就收到响应了。
邮件发送成功! —-这个时候邮箱才发完
短信发送成功!
从以上的测试结果我们,我们的邮箱发送和短信发送都分别单独地异步完成了,大大缩短了我们主业务处理事件,也提高了用户体验
小结
从本例可以看出,不同业务功能的生硬组合,会出现逻辑处理混乱的严重耦合现象,比如userService类既处理自己的用户逻辑,还要处理邮箱等发送的逻辑,这是不是也意味着,如果以后我们拓展更多的功能,我们的userService类还要出现更多的逻辑处理,来个大杂烩?,这同时还可能会为我们主要业务处理带来不必要的阻塞。当然,为了防止阻塞,我们还可以创建新的线程来异步,但这样原来的类就显得更加杂乱臃肿了。
使用spring事件机制能很好地帮助我们消除不同业务间的深耦合关系。它强大的任务调度还能帮助我们简洁地实现事件异步。
关于事件的一些其他用法可参考我的下一篇博文《趣谈spring 事件机制[2]:多监听器流水线式顺序处理》
关于任务调度的相关框架和使用可参考我的专栏《深入浅出Quartz任务调度》。
实例代码下载
本篇博文的实例代码可到我的github仓库https://github.com/jeanhao/spring的event文件夹下下载。
发表评论
-
复习:强迫线程顺序执行方式
2019-01-03 23:42 1569方法1: 三个线程,t1,t2,t3,如果一定要按顺序执行, ... -
(转)不错的前后端处理异常的方法
2019-01-02 23:16 2018前言 在 Web 开发中, 我们经常会需要处理各种异常, 这是 ... -
info q的极客时间大咖说等资料下载
2018-08-15 08:40 3465info q的极客时间大咖说等资料下载,还有不少思维导图 链 ... -
CXF 客户端超时时间设置(非Spring配置方式)
2018-07-03 22:38 2232import org.apache.cxf.endpoint. ... -
(转)synchronized关键字画像:正确打开方式
2018-06-14 09:25 490https://mp.weixin.qq.com/s/b3Sx ... -
CountDownLatch的例子
2018-06-13 14:10 684public class StatsDemo { ... -
两道面试题,带你解析Java类加载机制
2018-06-12 16:29 607https://mp.weixin.qq.com/s/YTa0 ... -
Spring中获取request的几种方法,及其线程安全性分析
2018-06-11 09:03 669https://mp.weixin.qq.com/s/KeFJ ... -
内部类小结
2018-06-06 10:25 434https://mp.weixin.qq.com/s/hErv ... -
JVM虚拟机小结1
2018-06-04 20:43 5391 jps -l //列出详细的类名和进程ID 2)jps ... -
windows下自带命令行工具查看CPU资源情况等
2018-06-04 12:53 3097微软提供了不少命令行 ... -
(收藏)深入分析Java的序列化与反序列化
2018-05-30 15:21 614https://mp.weixin.qq.com/s/T2Bn ... -
apache common包中的序列化工具
2018-05-30 09:10 1843什么是序列化 我们的 ... -
JAVA8 JVM的变化: 元空间(Metaspace)
2018-05-24 22:30 963本文将会分享至今为至我收集的关于永久代(Permanent G ... -
(转)服务器性能指标(一)——负载(Load)分析及问题排查
2018-05-21 21:03 1360原创: Hollis Hollis 负载 ... -
(转)对象复用
2018-05-20 15:27 857public class Student { priv ... -
mapreduce中入门中要注意的几点
2018-05-06 08:59 670在 mapreduce中,比如有如下的词: I love b ... -
HDFS的基本操作
2018-05-02 21:47 937-mkdir 在HDFS创建目录 ... -
一个不错的开源工具类,专门用来解析日志头部的,好用
2018-05-02 20:00 768一个不错的开源工具类,专门用来解析日志头部的,好用。 http ... -
介绍个不错的RESTFUL MOCK的工具wiremock
2018-04-27 21:02 1904介绍个不错的RESTFUL MOCK的工具wiremock,地 ...
相关推荐
在SpringBoot中,我们可以利用Spring框架的面向接口编程、依赖注入(DI)和事件监听器等特性来实现解耦。例如,服务间的通信可以通过定义接口并使用HTTP或消息队列来实现,而不是直接依赖具体的服务实例。 在...
本文将深入探讨如何使用Java来实现异步调用,以及它在后端开发中的应用。 1. **Java中的异步调用基础** - **线程与并发**:Java中的异步调用通常基于多线程或并发执行。Java内置了对多线程的支持,通过`Thread`类...
通过Spring的管理和服务,可以实现业务逻辑的解耦和模块化,而Struts2则负责协调视图和控制器,提供动态交互的界面,结合异步处理,提升了系统的性能和用户体验。对于理解SSH框架的整合应用和Struts2的核心特性,这...
首先,Webwork是一个轻量级的MVC(Model-View-Controller)框架,它强调了动作调度和分离关注点,使得业务逻辑与视图和控制层解耦。在登录功能中,Webwork负责处理用户的HTTP请求,将这些请求映射到特定的动作类,...
4. Ajax通信:ExtJS通过Ajax与Spring后台进行通信,实现异步请求,提升用户体验。 四、人力资源管理系统实践 1. 用户管理:使用ExtJS创建用户登录注册界面,Spring负责后端的用户验证和权限控制。 2. 员工信息管理...
在IT行业中,异步消息传递是一种常见的提升系统性能和可扩展性的技术,特别是在高并发、分布式环境下的应用。本教程将带你逐步了解如何利用Tomcat、Spring和JMS(Java Message Service)构建一个简单的异步消息传递...
总结来说,Spring的事件管理提供了一种高效且灵活的方式来解耦组件间的通信,通过创建自定义事件、发布事件、监听并处理事件,可以实现复杂业务逻辑中的模块化。在实际开发中,结合`@Async`注解和事件上下文,可以...
这些方法通常在Spring的服务层实现,负责查询数据库或执行其他业务逻辑,然后返回可用于填充自动补全列表的结果。DWR会将这些结果转换为JSON或其他易于JavaScript处理的格式。 实现过程中,前端的JavaScript代码会...
在Java Spring框架中,事件处理是一个重要的特性,它允许组件之间进行解耦通信。Spring事件主要涉及两个核心概念:事件发布(Event Publishing)和事件监听(Event Listening)。在这个"JAVA-spring学习资源之spring...
此外,Spring还提供了事件驱动的机制,可以用来处理异步工作流任务。例如,当某个事件发生(如用户提交表单),我们可以发布一个事件,由监听该事件的处理器启动或推进工作流实例。 为了确保工作流的可测试性,我们...
6. **spring-jms**: 这是Spring对Java消息服务(JMS)的支持,提供了与JMS提供者交互的一系列抽象和模板类,简化了消息生产者和消费者的实现,便于实现异步通信和解耦。 7. **spring-messaging**: 该模块提供了通用...
**Spring JMS 实现异步消息传递** 在 IT 领域,特别是在 Web 应用开发中,异步消息传递是一种提高系统效率和响应性的重要技术。传统的同步处理方式可能会导致用户等待时间较长,尤其是在处理复杂的业务逻辑或者需要...
3. Controller:业务逻辑处理,通过@RequestBody和@ResponseBody注解处理请求和响应数据。 4. ViewResolver:视图解析器,将处理结果转换为视图展示给用户。 5. Model-View-Template(MVC设计模式):模型层、视图层...
Spring AMQP是一个强大的框架,它将Apache RabbitMQ的消息中间件集成到Spring应用程序中,使得开发者可以轻松地在Java应用中实现异步通信和消息队列的功能。在这个名为"spring-rabbit-stocks"的项目中,我们将深入...
在Spring框架中,事件监听是一种实现模块间解耦的有效手段,它允许我们在应用程序的不同部分之间传递消息,而无需直接依赖。本篇文章将详细介绍Spring事件监听的三种方式:基于接口的监听器、基于类的监听器以及基于...
该框架只提供和设备对接部分(通过spring的bean注入解耦特性实现业务和协议实现分离), 使用此框架的客户必须遵循此框架设计的Api规范;接入一台设备只需创建两三个对象(协议的实现不算在内).并提供丰富的日志输出...
通过以上步骤,我们可以构建一个基于ActivityMQ和Spring的系统,其中业务逻辑可以通过消息进行解耦,提高系统的可扩展性和容错性。同时,Spring的声明式事务管理和AOP特性能够进一步优化整个消息处理流程。 例如,...
在Spring框架中,事件监听是一种常见的模式,用于在应用程序中实现不同组件之间的解耦通信。这一机制使得系统可以在不直接依赖彼此的情况下,传递信息和触发响应。本文将深入探讨Spring中的事件监听机制,并通过源码...
在实际应用中,可以将`callRpcService`方法封装到业务逻辑中,以实现远程过程调用的功能。 通过这种方式,我们已经成功地在Spring项目中集成了RabbitMQ,并利用RPC模式实现了服务间的通信。这种通信方式能够提高...