IT必备技能

Spring事件ApplicationEvent使用入门

2022-05-13  本文已影响0人  木木与呆呆

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);
    }

}
上一篇 下一篇

猜你喜欢

热点阅读