spring 事件为bean 与 bean之间传递消息。一个bean处理完了希望其余一个接着处理.这时我们就需要其余的一个bean监听当前bean所发送的事件.

spring事件使用步骤如下:

1.先自定义事件:你的事件需要继承 ApplicationEvent

2.定义事件监听器: 需要实现 ApplicationListener

3.使用容器对事件进行发布

  • 首先定义一个事件
/**
* @Title:
* @Auther: hangyu
* @Date: 2019/3/13
* @Description
* @Version:1.0
*/
public class TestEvent extends ApplicationEvent { private String name; private String msg; public TestEvent(Object source){
super(source);
} public TestEvent(Object source, String name, String msg) {
super(source);
this.name = name;
this.msg = msg;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
}
}
  • 其次定义事件监听
/**
* @Title:
* @Auther: hangyu
* @Date: 2019/3/13
* @Description
* @Version:1.0
*/
@Component
public class TestEventListener implements ApplicationListener<TestEvent> { @Async
@Override
public void onApplicationEvent(TestEvent testEvent) {
System.out.println("姓名:"+testEvent.getName()+"得到消息:"+testEvent.getMsg());
}
}
  • 使用容器发布事件

/**
* @Title:
* @Auther: hangyu
* @Date: 2019/3/13
* @Description
* @Version:1.0
*/
@Component
public class TestEventPublisher { @Autowired
private ApplicationContext applicationContext; public void pushlish(String name, String msg){
applicationContext.publishEvent(new TestEvent(this, name,msg));
}
}
  • 测试事件是否能够生效
/**
* @Title:
* @Auther: hangyu
* @Date: 2019/3/13
* @Description
* @Version:1.0
*/
@Configuration
@ComponentScan("cn.*.event")
public class EventConfig {
} /**
* @Title:
* @Auther: hangyu
* @Date: 2019/3/13
* @Description
* @Version:1.0
*/
public class TestMain { private static AnnotationConfigApplicationContext context; public static void main(String[] args) {
start();
} private static void start() {
if (context == null) {
context=new AnnotationConfigApplicationContext(EventConfig.class);
}
context.getBean(TestEventPublisher.class).pushlish("hangyu","申请退款!");
}
}
 
输出打印结果

最后有一个思考:ApplicationEvent事件执行部分和起一个TaskExecutor去执行 有啥区别吗?反正都是异步。

可以这样实现;

 @Autowired
private AsyncExecutor asyncExecutor; Executor executor = asyncExecutor.getAsyncExecutor();
executor.execute(
//具体业务
}); @Configuration
@EnableAsync
public class AsyncExecutor implements AsyncConfigurer { // 日志
static final Logger logger = LoggerFactory.getLogger(AsyncExecutor.class); public Executor getAsyncExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(5); taskExecutor.setMaxPoolSize(10); taskExecutor.setQueueCapacity(20000); taskExecutor.setKeepAliveSeconds(120); taskExecutor.setAllowCoreThreadTimeOut(true); taskExecutor.initialize(); return taskExecutor;
}
}

还可以这样实现;

    <!-- 异步线程池 -->
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数 -->
<property name="corePoolSize" value="3" />
<!-- 最大线程数 -->
<property name="maxPoolSize" value="10" />
<!-- 队列最大长度 >=mainExecutor.maxSize -->
<property name="queueCapacity" value="25" />
<!-- 线程池维护线程所允许的空闲时间 -->
<property name="keepAliveSeconds" value="300" />
<!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃. -->
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean> @Resource
private TaskExecutor taskExecutor; taskExecutor.execute(new Runnable() {
@Override
public void run() {
//具体业务
}
}
 
这就是注解方式和直接引用方式,本质是一样的

我的思考:ApplicationEvent是观察者设计模式,这种设计模式使得主题和观察者之间的耦合度降低,松耦合是面向对象设计中很重要的一个原则,最终也是使用@Async来实现异步。而TaskExecutor则是启动一个线程池任务异步执行任务,两者效果一样,但原理不同。

通过我的思考,又带来一个疑问:那观察者模式是不是就是我们MQ中的发布订阅模式呢?只不过观察者模式是进程内的,而MQ是跨进程的?就这唯一的区别吗?

经过一些资料的查阅:大多数地方观察者模式约等于发布订阅模式,但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会。

所以说观察者模式是小米加步枪,发布订阅模式是95式自动步枪,是它的进化版!

作者:杭宇_8ba6
链接:https://www.jianshu.com/p/e03c5c53d2e9
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

如何实现Application event,观察者模式的更多相关文章

  1. Spring 事件:Application Event

    Spring Application Event Spring 的事件(Application Event)为 Bean 与 Bean 之间的消息通信提供了支持.当一个 Bean 处理完一个任务之后, ...

  2. Spring Application Event Example

    Spring Application Event 项目结构 工程下载 https://github.com/xiaoheike/SpringApplicationEventExample.git Sp ...

  3. Spring Boot实战笔记(四)-- Spring常用配置(事件Application Event)

    一.事件(Application Event) Spring的事件为Bean和Bean之间的消息通信提供了支持.当一个Bean处理完一个任务之后,希望另一个Bean知道并能做相应的处理,这时我们就需要 ...

  4. SpringBoot -- 事件(Application Event)

    Spring的事件为Bean与Bean之间的消息通信提供了支持,当一个Bean处理完一个任务之后,希望另外一个Bean知道并能做相应的处理,这时我们就需要让一个Bean监听当前Bean所发送的事件. ...

  5. spring boot: 一般注入说明(五) @Component, application event事件为Bean与Bean之间通信提供了支持

    spring的事件,为Bean与Bean之间通信提供了支持,当一个Bean处理完成之后,希望另一个Bean知道后做相应的事情,这时我们就让另外一个Bean监听当前Bean所发送的事件. spring的 ...

  6. 从命令模式的维度理解Spring 之Application Event

    Spring的事件(Application Event)为Bean与Bean之间的信息通讯提供了支持.当一个Bean处理完一个任务之后,希望另一Bean指定并能做相应的处理,这时我们就需要让另外一个B ...

  7. spring 事件(Application Event)

    spring 事件为bean 与 bean之间传递消息.一个bean处理完了希望其余一个接着处理.这时我们就需要其余的一个bean监听当前bean所发送的事件. spring事件使用步骤如下: 1.先 ...

  8. c++ 设计模式5 (Observer / Event 观察者模式)

    3.3 观察者模式 (Observer)/发布-订阅模式 动机: 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都能得 ...

  9. 事件(Application Event)

    Spring的事件(Appllcation Event)为Bean与Bean之间的消息通信提供了支持.当一个Bean处理完一个任务后,希望另一个Bean知道并能做相应的处理,这种情况可以让另一个Bea ...

随机推荐

  1. vue回调接口

    1.微博回调接口 1.1oauth/urls.py 中添加路由 urlpatterns = [ path('weibo/callback/', views.OauthWeiboCallback.as_ ...

  2. 关于缓存的一些重要概念(Redis 前置菜)

    1. 缓存的基本思想 很多朋友,只知道缓存可以提高系统性能以及减少请求相应时间,但是,不太清楚缓存的本质思想是什么. 缓存的基本思想其实很简单,就是我们非常熟悉的空间换时间.不要把缓存想的太高大上,虽 ...

  3. 学习工具---maven

    写在前面 为什么要用maven? 作为一跨平台的项目管理工具,它有着以下丰富的应用场景: 作为程序员,有相当一部分时间花在编译.运行单元测试.生成文档.打包.部署和发布等不起眼的工作上,而maven将 ...

  4. 腾讯牛逼!终于开源了自家的 Tencent JDK——Kona!!.md

    是的,继阿里 2019/03 开源基于 OpenJDK 的长期支持版本 Alibaba Dragonwell 之后,腾讯也发布了自家的开源免费的 JDK 版本--Tencent Kona,必须替小马哥 ...

  5. Python中str类型的字符串写入二进制文件时报TypeError错的处理方式

    在用二进制模式打开文件情况下,写入一个str对象时报错:TypeError: a bytes-like object is required, not 'str' 出现该问题是因为Python严格区分 ...

  6. 小程序view的显示与隐藏

    需要在全局数据块中,设定一个控制键. data: { ......//省略其他代码 showView: true }, 然后是在wxml中,view的class中设置2个class,并用三目表达式来进 ...

  7. 总括订单Blanket order

    总括订单Blanket order是客户向其供应方发出的采购订单,但其中包含一段时间内的多个交货日期,通常使用谈判时的预定价格.大多数情况下,它用于对消耗性商品有经常性需求的情况.总括订单通常用于客户 ...

  8. typora字体与字体颜色

    字体 基本格式:\字体信息{内容} 罗马体\rm \rm{罗马体abc}>>\(\rm{罗马体abc}\) 意大利体\it \it{意大利体}>>\(\it{意大利体}\) 等 ...

  9. KM 算法

    KM 算法 可能需要先去学学匈牙利算法等二分图相关知识. 模板题-洛谷P6577 [模板]二分图最大权完美匹配 给 \(n\) 和 \(m\) 与边 \(u_i,v_i,w_i(1\le i\le m ...

  10. 数据结构—— Trie (前缀树)

    实现一个 Trie (前缀树),包含 插入, 查询, 和 查询前缀这三个操作. Trie trie = new Trie(); trie.insert("apple"); trie ...