一、简介

spring事件是观察者设计模式的实现,主要有三个元素:

  • 事件  spring事件由ApplicationEvent定义
  • 监听者  由ApplicationListener定义
  • 发布者  由ApplicationEventPublisher定义,而ApplicationContext继承自ApplicationEventPublisher

简单示例:

自定义事件

public class TestEvent extends ApplicationEvent {

    private String message;

    public TestEvent(Object source) {
this(source, "default message");
} public TestEvent(Object source, String msg) {
super(source);
this.message = msg;
} public String getMessage() {
return message;
}
}

监听者

@Component
public class TestListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof TestEvent) {
        System.out.println(((TestEvent)event).getMessage());
}
}
}

XML配置

<context:component-scan base-package="cn.matt.event"/>  

测试

public class EventTest {
@Test
public void testCustomEvent() {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-context.xml");
context.publishEvent(new TestEvent("", "hello matt"));
}
}

补充:

定义监听者时,可通过泛型指定监听事件类型,因此,上例监听者可定义如下:

@Component
public class TestListener implements ApplicationListener<TestEvent> {
@Override
public void onApplicationEvent(TestEvent event) {
System.out.println(((TestEvent) event).getMessage());
}
}

二、spring容器事件

spring为容器启动各阶段定义了相关事件,实现如图:

事件说明:

  • ContextStartedEvent:ApplicationContext启动后触发的事件(调用start方法)
  • ContextStoppedEvent:ApplicationContext停止后触发的事件(调用stop方法)
  • ContextClosedEvent:ApplicationContext关闭后触发的事件
  • ContextRefreshedEvent:ApplicationContext初始化或刷新完成后触发的事件(容器初始化(如bean的实例化、依赖注入)完成后调用)

使用示例

@Component
public class ApplicationStartUpListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("spring context inited");
}
}

三、事件的执行机制

spring事件的执行机制默认使用单线程同步执行,异步执行可使用@Async注解实现,示例如下(新用户注册):

定义事件

public class RegisterEvent extends ApplicationEvent {
public RegisterEvent(User user) {
super(user);
}
}

定义监听者

// 发生邮件
@Component
public class EmailRegisterListener implements ApplicationListener<RegisterEvent> {
@Async
public void onApplicationEvent(final RegisterEvent event) {
System.out.println(Thread.currentThread().getId() + " **** 注册成功,发送确认邮件给:" + ((User)event.getSource()).getUsername());
}
}
// 赠送积分
@Component
public class PointRegisterListener implements ApplicationListener<RegisterEvent> {
@Async
public void onApplicationEvent(final RegisterEvent event) {
System.out.println(Thread.currentThread().getId() + " **** 注册成功,赠送积分给:" + ((User)event.getSource()).getUsername());
}
}
// 赠送大礼包
@Component
public class PresentRegisterListener implements ApplicationListener<RegisterEvent> {
@Async
public void onApplicationEvent(final RegisterEvent event) {
System.out.println(Thread.currentThread().getId() + " **** 注册成功,赠送大礼包给:" + ((User)event.getSource()).getUsername());
}
}

用户类与业务类

public class User implements Serializable {
private String username;
private String password; public User(String username, String password) {
this.username = username;
this.password = password;
} public String getUsername() {
return username;
}
}
@Service
public class RegisterService {
@Autowired
private ApplicationContext applicationContext; public void register(String username, String password) {
System.out.println(username + "注册成功!");
publishRegisterEvent(new User(username, password));
} private void publishRegisterEvent(User user) {
applicationContext.publishEvent(new RegisterEvent(user));
}
}

配置

<context:component-scan base-package="com.sishuok"/>

<!-- 任务调度器 -->
<task:scheduler id="scheduler" pool-size="10"/> <!-- 任务执行器 -->
<task:executor id="executor" pool-size="10"/> <!--开启注解调度支持 @Async @Scheduled-->
<task:annotation-driven executor="executor" scheduler="scheduler" proxy-target-class="true"/>

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring-config-register.xml"})
public class RegisterServiceIT {
@Autowired
private RegisterService registerService; @Test
public void testRegister() {
registerService.register("long", "123");
}
} // 输出:
// long注册成功!
// 15 **** 注册成功,发送确认邮件给:long
// 17 **** 注册成功,赠送积分给:long
// 18 **** 注册成功,赠送大礼包给:long

参考:

事件驱动模型简介

Spring进阶之路(2)-ApplicationContext容器以及事件机制

Spring ApplicationContext事件机制

Spring 使用介绍(十一)—— Spring事件的更多相关文章

  1. [转帖]微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务

    微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务 http://skaka.me/blog/2016/04/21/springcloud1/ APR 21ST,  ...

  2. 黑马_13 Spring Boot:01.spring boot 介绍&&02.spring boot 入门

    13 Spring Boot: 01.spring boot 介绍&&02.spring boot 入门 04.spring boot 配置文件 SpringBoot基础 1.1 原有 ...

  3. 微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务

    http://skaka.me/blog/2016/04/21/springcloud1/ 不同于单一架构应用(Monolith), 分布式环境下, 进行事务操作将变得困难, 因为分布式环境通常会有多 ...

  4. 黑马_13 Spring Boot:05.spring boot 整合其他技术

    13 Spring Boot: 01.spring boot 介绍&&02.spring boot 入门 04.spring boot 配置文件 05.spring boot 整合其他 ...

  5. 黑马_13 Spring Boot:04.spring boot 配置文件

    13 Spring Boot: 01.spring boot 介绍&&02.spring boot 入门 04.spring boot 配置文件 05.spring boot 整合其他 ...

  6. [翻译]Spring框架参考文档(V4.3.3)-第二章Spring框架介绍 2.1 2.2 翻译--2.3待继续

    英文链接:http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/overview.ht ...

  7. 一、Spring Cloud介绍

    springcloud 介绍 研究了一段时间spring boot了准备向spirng cloud进发,公司架构和项目也全面拥抱了Spring Cloud.在使用了一段时间后发现Spring Clou ...

  8. Spring入门介绍

    概述 下载地址:https://repo.spring.io/release/org/springframework/spring/ spring是开源的轻量级框架 spring核心的主要两部分 AO ...

  9. Spring Cloud第十一篇 | 分布式配置中心高可用

    ​ 本文是Spring Cloud专栏的第十一篇文章,了解前十篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring Cl ...

随机推荐

  1. Kafka 入门三问

    目录 1 Kafka 是什么? 1.1 背景 1.2 定位 1.3 产生的原因 1.4 Kafka 有哪些特征 消息和批次 模式 主题和分区 生产者和消费者 broker 和 集群 1.5 Kafka ...

  2. git revert 还有这个坑?

    最近也是终于开启了代码编写之旅,我只能默默地说一句,写代码的感觉,简直不能再爽! 不过也由于 git 的分支管理蛋疼懵逼很久,所以必须记录以及和大家分享一下本次坑爹的旅行. 写在前面 每个公司相比都有 ...

  3. .Net Core 在 Linux-Centos上的部署实战教程(四) ---- 总结

    问题: 1.网站部署上访问不了,可能是防火墙/安全组的原因 2.在后台运行这块上 我查了一些类似的部署博客 好多人都是用守护进程搞的,本人也算Linux小白  不懂这样做的好处是啥  有大佬的话  可 ...

  4. Python学习第十二篇——切片的使用

    Python中使用函数切片可以创建副本,保留原本.现在给出如下代码 magicians_list = ['mole','jack','lucy'] new_lists = [] def make_gr ...

  5. 使用Dockerfile来构建镜像

    Dockerfile原理 创建Dockerfile Dockerfile实例 Dockerfile指令 注释 FROM MAINTAINER RUN ADD WORKDIR ENV USER COPY ...

  6. 【Python3练习题 017】 两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。a说他不和x比,c说他不和x,z比。请编程序找出三队赛手的名单。

    import itertools   for i in itertools.permutations('xyz'):     if i[0] != 'x' and i[2] != 'x' and i[ ...

  7. js根据ip自动获取地址(省市区)

    HTML: <html> <head> <meta charset="utf-8"> <meta name="viewport& ...

  8. 一、npm基础

    一.什么是npm? npm 是模块管理工具,可以下载.更新第三方模块,也可以发布自己的模块共替他人使用,主要目的在于分享和重用代码: 二.下载安装node,更新npm node 下载网址  https ...

  9. WPF中任务栏只显示主窗口

    我们在用WPF开发的时候,常常会遇到在主窗口打开的情况下,去显示子窗口,而此时任务栏同时显示主窗口与子窗口.这样看起来很不美观.所以在弹出子窗口之前,设置它的几个相应属性,便不会出现这种问题了. // ...

  10. java.lang(StringBuffer)

    public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharS ...