0
点赞
收藏
分享

微信扫一扫

Spring事件ApplicationEvent使用入门


1.说明

Spring事件机制ApplicationEvent,

是一个典型的观察者模式,

包含三部分:

Event 事件(相当于消息)、

Publisher 发送者(相当于被观察者)、

Listener 监听者(相当于观察者)。

可以实现在Spring应用中,

通过发送者发布各种消息事件,

让监听者处理其关心的消息事件,

从而利用观察者模式解耦发送者和监听者。

2.事件

首先确定需要在事件中传递的消息,

比如下面的用户信息,

新建UserInfo.java:

package org.springframework.context.event.entity;

public class UserInfo {
private String name;
private int age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "UserInfo [name=" + name + ", age=" + age + "]";
}

}

然后创建事件类型,

比如用户的创建和删除事件,

分别创建UserAddEvent.java类:

package org.springframework.context.event.type;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.entity.UserInfo;

public class UserAddEvent extends ApplicationEvent {

private static final long serialVersionUID = -3910960183687086015L;

private UserInfo user;

public UserAddEvent(Object source, UserInfo user) {
super(source);
this.user = user;
}

public UserInfo getUser() {
return user;
}

public void setUser(UserInfo user) {
this.user = user;
}

@Override
public String toString() {
return "UserAddEvent [user=" + user + "]";
}
}

以及UserDelEvent.java类

package org.springframework.context.event.type;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.entity.UserInfo;

public class UserDelEvent extends ApplicationEvent {

private static final long serialVersionUID = -3910960183687086015L;

private UserInfo user;

public UserDelEvent(Object source, UserInfo user) {
super(source);
this.user = user;
}

public UserInfo getUser() {
return user;
}

public void setUser(UserInfo user) {
this.user = user;
}

@Override
public String toString() {
return "UserDeleteEvent [user=" + user + "]";
}
}

注意自定义的事件类,需要继承ApplicationEvent类,

在自定义类中承载需要发布的消息。

3.发送者

发送者使用ApplicationContext的publishEvent方法发布用户事件,

只需要在发布事件的地方注入ApplicationContext实例即可:

package org.springframework.context.event.publisher;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.type.UserAddEvent;
import org.springframework.context.event.type.UserDelEvent;
import org.springframework.stereotype.Component;

@Component
public class UserEventPublisherContext {

@Autowired
private ApplicationContext applicationContex;

public void publishUserAddEvent(UserAddEvent event) {
applicationContex.publishEvent(event);
}

public void publishUserDelEvent(UserDelEvent event) {
applicationContex.publishEvent(event);
}
}

为了方便测试,新建AutoPublisher.java类,

自动产生用户新增或者删除的事件,

每隔一秒,交替发布用户新增和删除事件:

package org.springframework.context.event.publisher;

import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.entity.UserInfo;
import org.springframework.context.event.type.UserAddEvent;
import org.springframework.context.event.type.UserDelEvent;
import org.springframework.stereotype.Component;

@Component
public class AutoPublisher implements InitializingBean {

@Autowired
private UserEventPublisherContext userEventPublisherContext;

@Override
public void afterPropertiesSet() throws Exception {
Thread t = new Thread(new Runnable() {

boolean isAdd = true;

@Override
public void run() {
while (true) {
UserInfo user = new UserInfo();
System.out.println("Publish isAdd=" + isAdd + ", user=" + user);
if (isAdd) {
UserAddEvent event = new UserAddEvent(this, user);
userEventPublisherContext.publishUserAddEvent(event);
} else {
UserDelEvent event = new UserDelEvent(this, user);
userEventPublisherContext.publishUserDelEvent(event);
}

isAdd = !isAdd;
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});

t.start();
}
}

4.监听者

监听者,即事件监听器,接收事件并对其进行处理,

监听者既可以通过实现ApplicationListener接口,

也可以通过@EventListener注解来接收事件。

新建UserEventListenerInterface.java类,

实现ApplicationListener接口,

这里只监听用户新增事件,

然后打印出对应的日志:

package org.springframework.context.event.listener;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.type.UserAddEvent;
import org.springframework.stereotype.Component;

@Component
public class UserEventListenerInterface implements ApplicationListener<UserAddEvent> {

@Override
public void onApplicationEvent(UserAddEvent event) {
System.out.println("UserEventListenerInterface.onApplicationEvent()收到消息=" + event);
}
}

新建UserEventListenerAnnotation.java类,

使用@EventListener注解,

同时监听用户新增和删除事件:

package org.springframework.context.event.listener;

import org.springframework.context.event.EventListener;
import org.springframework.context.event.type.UserAddEvent;
import org.springframework.context.event.type.UserDelEvent;
import org.springframework.stereotype.Component;

@Component
public class UserEventListenerAnnotation {

@EventListener
public void listenUserAddEvent(UserAddEvent event) {
System.out.println("UserEventListenerAnnotation.listenUserAddEvent()收到消息=" + event);
}

@EventListener
public void listenUserDelEvent(UserDelEvent event) {
System.out.println("UserEventListenerAnnotation.listenUserDelEvent()收到消息=" + event);
}
}

5.其他代码

为了进行测试,

这里使用Spring Boot启动环境,

需要一些其他辅助的代码和配置如下:

新建ContextApplication.java启动类:

package org.springframework.context.event;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ContextApplication {
public static void main(String[] args) {
SpringApplication.run(ContextApplication.class, args);
}
}

新建application.yml配置文件:

server:
port: 8088

新建pom.xml依赖配置:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yuwen.spring</groupId>
<artifactId>spring-basic-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>spring-context</artifactId>
<description>spring-context相关功能测试Demo</description>

<properties>
<spring-boot.version>2.5.6</spring-boot.version>
</properties>

<dependencyManagement>
<dependencies>
<!--Spring Boot 依赖管理 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>

<!-- Spring Boot Web服务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<!-- Log4j2 start 日志框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- Log4j2 end -->

</dependencies>
</project>

6.运行测试

运行ContextApplication.java启动类,

输出日志如下:

.   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.6)

2022-05-13 13:51:13.142 INFO 2188 --- [ main] o.s.c.e.ContextApplication : Starting ContextApplication using Java 1.8.0_191 on yuwen-asiainfo with PID 2188 (D:\Code\Learn\SpringBasic\spring-basic-demo\spring-context\target\classes started by yuwen in D:\Code\Learn\SpringBasic\spring-basic-demo\spring-context)
2022-05-13 13:51:13.150 INFO 2188 --- [ main] o.s.c.e.ContextApplication : No active profile set, falling back to default profiles: default
2022-05-13 13:51:14.632 INFO 2188 --- [ main] o.s.b.w.e.t.TomcatWebServer : Tomcat initialized with port(s): 8088 (http)
2022-05-13 13:51:14.646 INFO 2188 --- [ main] o.a.c.c.StandardService : Starting service [Tomcat]
2022-05-13 13:51:14.647 INFO 2188 --- [ main] o.a.c.c.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.54]
2022-05-13 13:51:14.716 INFO 2188 --- [ main] o.a.c.c.C.[.[.[/] : Initializing Spring embedded WebApplicationContext
2022-05-13 13:51:14.716 INFO 2188 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1510 ms
Publish isAdd=true, user=UserInfo [name=null, age=0]
UserEventListenerInterface.onApplicationEvent()收到消息=UserAddEvent [user=UserInfo [name=null, age=0]]
2022-05-13 13:51:15.038 INFO 2188 --- [ main] o.s.b.w.e.t.TomcatWebServer : Tomcat started on port(s): 8088 (http) with context path ''
2022-05-13 13:51:15.047 INFO 2188 --- [ main] o.s.c.e.ContextApplication : Started ContextApplication in 2.263 seconds (JVM running for 2.882)
Publish isAdd=false, user=UserInfo [name=null, age=0]
UserEventListenerAnnotation.listenUserDelEvent()收到消息=UserDelEvent [user=UserInfo [name=null, age=0]]
Publish isAdd=true, user=UserInfo [name=null, age=0]
UserEventListenerInterface.onApplicationEvent()收到消息=UserAddEvent [user=UserInfo [name=null, age=0]]
UserEventListenerAnnotation.listenUserAddEvent()收到消息=UserAddEvent [user=UserInfo [name=null, age=0]]

查看日志发现:

UserDeleteEvent能够被UserEventListenerAnnotation接收到;

UserAddEvent事件能够被UserEventListenerInterface和UserEventListenerAnnotation接收到。

7.发送者写法2

发送者不仅可以注入ApplicationContext发布事件,

也可以实现ApplicationEventPublisherAware接口发布事件,

新建UserEventPublisherInterface.java类如下:

package org.springframework.context.event.publisher;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.event.type.UserAddEvent;

public class UserEventPublisherInterface implements ApplicationEventPublisherAware {

private ApplicationEventPublisher applicationEventPublisher;

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

public void publishUserAddEvent(UserAddEvent event) {
applicationEventPublisher.publishEvent(event);
}
}

顺便一提,ApplicationContext实现了ApplicationEventPublisher接口,

也可以在代码中注入ApplicationEventPublisher,

和注入ApplicationContext是等价的,

因为际还是使用ApplicationContext发布用户事件,

推荐使用ApplicationEventPublisher使代码更明确,

新建UserEventPublisher.java类如下:

package org.springframework.context.event.publisher;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.type.UserAddEvent;
import org.springframework.stereotype.Component;

@Component
public class UserEventPublisher {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;

public void publishUserAddEvent(UserAddEvent event) {
applicationEventPublisher.publishEvent(event);
}

}



举报

相关推荐

Spring事件监听器使用

Spring AOP使用入门案例

0 条评论