Spring(22)——ApplicationEvent

简介: 22 ApplicationEvent Spring允许我们在ApplicationContext中发布ApplicationEvent事件,然后对应的ApplicationListener可以用来监听对应的事件。

22 ApplicationEvent

Spring允许我们在ApplicationContext中发布ApplicationEvent事件,然后对应的ApplicationListener可以用来监听对应的事件。当发布了一个ApplicationEvent后,在对应bean容器中实现了ApplicationListener接口的bean实例都会接收到对应的通知,即对应的ApplicationListener回调方法将会被调用。

22.1内置事件

Spring自身已经为我们提供了几个ApplicationEvent,它们会由Spring在相应的时间自动进行发布,用户如果有需要可以对它们进行监听。具体来说有如下几种类型。

22.1.1 ContextRefreshedEvent

ContextRefreshedEvent将在对应的ApplicationContext调用refresh()方法时进行发布,这也包括直接使用配置文件等进行对应的ApplicationContext初始化时,因为在这个时候也会调用对应的refresh()方法。而在refresh()方法中是在该方法的最后才进行ContextRefreshedEvent发布的,也就是说在发布ContextRefreshedEvent时对应ApplicationContext中的bean定义都已经加载完成,对应的BeanFactoryPostProcessor都执行过了,需要实例化的bean也都已经实例化了。

22.1.2 ContextStartedEvent

ContextStartedEvent将在对应的ApplicationContext调用start()方法时进行发布。此时已经对所有实现了LifeCycle接口的bean回调了对应的start()方法。

22.1.3ContextStoppedEvent

ContextStoppedEvent将在对应的ApplicationContext调用stop()方法时进行发布。此时已经对所有实现了LifeCycle接口的bean回调了对应的stop()方法。

22.1.4ContextClosedEvent

ContextClosedEvent将在对应的ApplicationContext调用close()方法时进行发布。此时所有的资源都已经销毁了。ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent和ContextClosedEvent都继承自ApplicationContextEvent,因为它们都是针对ApplicationContext的事件。

22.1.5 ServletRequestHandledEvent

ServletRequestHandledEvent将在Spring处理了一个HttpRequest请求后进行发布,即对应的HttpRequest已经完成了。ServletRequestHandledEvent只能在使用DispatcherServlet时使用,当DispatcherServlet处理完一个HttpRequest请求后将发布一个ServletRequestHandledEvent。ServletRequestHandledEvent继承自RequestHandledEvent,所以当我们需要监听RequestHandledEvent时也可以监听ServletRequestHandledEvent。

22.2 自定义事件

Spring能够发布的事件是ApplicationEvent,其是一个继承了EventObject的抽象类。其源码如下所示,我们可以看到其只有一个构造方法,且必须传入一个对象作为当前事件发布的发布者。

public abstract class ApplicationEvent extends EventObject {

	/** use serialVersionUID from Spring 1.2 for interoperability */
	private static final long serialVersionUID = 7099057708183571937L;

	/** System time when the event happened */
	private final long timestamp;


	/**
	 * Create a new ApplicationEvent.
	 * @param source the component that published the event (never {@code null})
	 */
	public ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
	}


	/**
	 * Return the system time in milliseconds when the event happened.
	 */
	public final long getTimestamp() {
		return this.timestamp;
	}

}

用户如果需要自定义事件则是自定义一个继承ApplicationEvent的类,除了提供构造父类必须要有的source对象以外,其它信息都可以由用户自定义。如下我们就简单的实现了一个自定义的ApplicationEvent,那么在之后进行事件发布时就可以使用自定义的MyApplicationEvent来作为ApplicationEvent进行发布了。

public class MyApplicationEvent extends ApplicationEvent {

	private static final long serialVersionUID = 1L;

	public MyApplicationEvent(Object source) {
		super(source);
	}

}

22.3 事件发布

事件的发布是由ApplicationEventPublisher接口中的publishEvent()方法定义的,其定义如下。

public interface ApplicationEventPublisher {

	void publishEvent(ApplicationEvent event);

}

ApplicationContext接口继承了ApplicationEventPublisher接口,所以我们可以直接使用ApplicationContext来进行事件的发布。如下示例中我们就给Hello注入了一个ApplicationContext,然后在调用其doSomething()方法时通过注入的ApplicationContext发布了一个自定义的MyApplicationEvent。

@Component
public class Hello {

	@Autowired
	private ApplicationContext context;
	
	public void doSomething() {
		System.out.println("----do something....");
		//发布一个自定义的MyApplicationEvent
		context.publishEvent(new MyApplicationEvent(this));
	}

}

除了直接使用ApplicationContext进行事件发布外,Spring还给我们提供了一个用于发布事件的ApplicationEventPublisher接口对应的Aware接口——ApplicationEventPublisherAware,该接口跟Spring提供的其它Aware接口一样,当一个bean实现了该接口以后,Spring在实例化对应的bean后将调用其中的回调方法以传入一个ApplicationEventPublisher,通常就是传递的当前的ApplicationContext对象。所以我们还可以让我们的bean实现ApplicationEventPublisherAware接口,然后使用Spring传入的ApplicationEventPublisher发布对应的事件。所以上述示例我们也可以把它改成实现ApplicationEventPublisherAware的方式,示例如下。

@Component
public class Hello implements ApplicationEventPublisherAware {

	private ApplicationEventPublisher eventPublisher;
	
	public void doSomething() {
		System.out.println("----do something....");
		//发布一个自定义的MyApplicationEvent
		this.eventPublisher.publishEvent(new MyApplicationEvent(this));
	}

	public void setApplicationEventPublisher(
			ApplicationEventPublisher applicationEventPublisher) {
		this.eventPublisher = applicationEventPublisher;
	}

}

22.4 事件监听

事件监听需要定义对应的监听器,Spring中用于监听ApplicationEvent的监听器是通过ApplicationListener来定义的。ApplicationListener是一个接口,其定义如下,我们可以看到该接口中使用了泛型,即可以指定只监听某种类型的ApplicationEvent。

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	void onApplicationEvent(E event);

}

ApplicationListener每次监听到对应的ApplicationEvent后都将调用其onApplicationEvent()方法。所以如果我们想定义一个只监听之前自定义的MyApplicationEvent的监听器,则可以如下定义,如果想监听所有的ApplicationEvent,则可以将泛型指定为ApplicationEvent,即将如下的MyApplicationEvent改成ApplicationEvent。

public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {

	public void onApplicationEvent(MyApplicationEvent event) {
		System.out.println(event.getSource() + "****************" + event.getTimestamp());;
	}

}

光实现了ApplicationListener接口,对应的监听器还监听不到对应的事件。我们需要把它们定义bean容器中的一个bean,这样当Spring发布了一个事件后就会将其传递给相匹配的监听器。所以针对于上述监听器,我们可以在基于XML进行配置时在对应的XML配置文件中进行如下配置。

<bean class="com.app.MyApplicationListener"/>

如果是基于注解的扫描则可以在MyApplicationListener上使用@Component等注解进行标注。

(注:本文是基于Spring4.1.0所写)

 

目录
相关文章
|
消息中间件 安全 JavaScript
小家Spring】从Spring中的(ApplicationEvent)事件驱动机制出发,聊聊【观察者模式】【监听者模式】【发布订阅模式】【消息队列MQ】【EventSourcing】...(中)
小家Spring】从Spring中的(ApplicationEvent)事件驱动机制出发,聊聊【观察者模式】【监听者模式】【发布订阅模式】【消息队列MQ】【EventSourcing】...(中)
|
消息中间件 前端开发 安全
小家Spring】从Spring中的(ApplicationEvent)事件驱动机制出发,聊聊【观察者模式】【监听者模式】【发布订阅模式】【消息队列MQ】【EventSourcing】...(上)
小家Spring】从Spring中的(ApplicationEvent)事件驱动机制出发,聊聊【观察者模式】【监听者模式】【发布订阅模式】【消息队列MQ】【EventSourcing】...(上)
小家Spring】从Spring中的(ApplicationEvent)事件驱动机制出发,聊聊【观察者模式】【监听者模式】【发布订阅模式】【消息队列MQ】【EventSourcing】...(上)
|
Java Spring
[Java Framework] [Spring] Spring Event / 事件的使用 一: ApplicationEvent
[Java Framework] [Spring] Spring Event / 事件的使用 一: ApplicationEvent
308 0
|
消息中间件 设计模式 安全
小家Spring】从Spring中的(ApplicationEvent)事件驱动机制出发,聊聊【观察者模式】【监听者模式】【发布订阅模式】【消息队列MQ】【EventSourcing】...(下)
小家Spring】从Spring中的(ApplicationEvent)事件驱动机制出发,聊聊【观察者模式】【监听者模式】【发布订阅模式】【消息队列MQ】【EventSourcing】...(下)
|
Java Spring
Spring ApplicationEvent 使用
Spring ApplicationEvent 使用
608 0
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1539 0
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
1499 0
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
643 0
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
1220 0
|
12月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
730 4