0
点赞
收藏
分享

微信扫一扫

SpringBoot--自定义事件--方法/详解/实例


简介

说明

        本文用实例来介绍如何在SpringBoot中自定义事件来使用观察者模式。

事件的顺序

可使用实现Ordered接口的方式,调整监听器顺序。

注意:必须是同时实现 ApplicationListener<MyEvent>,Ordered这样的方法才能控制顺序。

下边几种都是无法控制顺序的:

  1. @Component+@EventListerner+实现Ordered
  2. 实现 ApplicationListener<MyEvent>+@Order

步骤1:自定义事件

通过继承ApplicationEvent来自定义事件。

构造器的参数为该事件的相关数据对象,监听器可以获取到该数据对象,进而进行相关逻辑处理。

package com.example.event;

import org.springframework.context.ApplicationEvent;

public class MyEvent extends ApplicationEvent {

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

}

步骤2:自定义监听器

方案1:ApplicationListener

法1:@EventListener

监听单个事件

package com.example.event;

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

public class MyListener {
@EventListener
public void abc(MyEvent event) {
System.out.println("监听器: " + "MyListener");
System.out.println(" 线程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的数据:" + event.getSource());
}
}

或者

package com.example.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

public class MyListener {
@EventListener({MyEvent.class})
public void abc(ApplicationEventevent) {
System.out.println("监听器: " + "MyListener");
System.out.println(" 线程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的数据: " + event.getSource());
}
}

 上边的办法比较好,因为不需要类型转换了。直接就能确定是MyEvent类型。

监听多个事件

事件进来之后,可以使用if(event instanceOf MyEvent.class)来判断是哪种事件。

package com.example.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class MyListener {
@EventListener({MyEvent.class, MyEvent2.class})
public void abc(ApplicationEvent event) {
System.out.println("监听器: " + "MyListener");
System.out.println(" 所在线程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的数据:" + event.getSource());
}
}

监听所有ApplicationEvent

若使用这种写法,启动时会打印很多Spring自带的事件。任意ApplicationEvent都会进入这里边。

package com.example.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class MyListener {
@EventListener
public void abc(ApplicationEvent event) {
System.out.println("监听器: " + "MyListener");
System.out.println(" 所在线程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的数据:" + event.getSource());
}
}

法2:实现ApplicationListener<T>接口

public class MyListener implements ApplicationListener<MyEvent>{

public void onApplicationEvent(MyEvent event){
System.out.println("监听器: " + "MyListener");
System.out.println(" 所在线程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的数据:" + event.getSource());
}
}

方案2:SmartApplicationListener

源码如下

public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
boolean supportsEventType(Class<? extends ApplicationEvent> var1);

default boolean supportsSourceType(@Nullable Class<?> sourceType) {
return true;
}

default int getOrder() {
return 2147483647;
}
}

supportsEventType:支持的事件的类型

supportsSourceType:支持的数据的类型

getOrder:2147483641:是2^31-1,也就是32位的int的最大正数 。

示例

事件

package com.example.event;

import org.springframework.context.ApplicationEvent;

public class MyEvent extends ApplicationEvent {

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

}

监听器1

package com.example.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class MyListener implements SmartApplicationListener {

@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
return aClass == MyEvent.class;
}

@Override
public boolean supportsSourceType(Class<?> sourceType) {
return sourceType == String.class;
}

@Override
public int getOrder() {
return 2;
}

@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("监听器: " + "MyListener");
System.out.println(" 所在线程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的数据:" + event.getSource());
System.out.println(" 是MyEvent?:" + (event instanceof MyEvent));
}
}

监听器2

package com.example.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class MyListener2 implements SmartApplicationListener {

@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
return aClass == MyEvent.class;
}

@Override
public boolean supportsSourceType(Class<?> sourceType) {
return sourceType == String.class;
}

@Override
public int getOrder() {
return 1;
}

@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("监听器: " + "MyListener2");
System.out.println(" 所在线程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的数据:" + event.getSource());
System.out.println(" 是MyEvent?:" + (event instanceof MyEvent));
}
}

发布器

package com.example.event;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class MyPublisher {
@Autowired
ApplicationContext applicationContext;

public void myPublish(String message) {
System.out.println("发布器所在线程:" + Thread.currentThread().getName());
applicationContext.publishEvent(new MyEvent(message));
}
}

测试

package com.example.controller;

import com.example.event.MyPublisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
@Autowired
MyPublisher myPublisher;

@GetMapping("/test1")
public String test1() {
myPublisher.myPublish("Hello");
return "test1 success";
}

}

启动后,访问:​​http://localhost:8080/test1​​

后端输出:

发布器所在线程:http-nio-8080-exec-2
监听器: MyListener2
所在线程: http-nio-8080-exec-2
事件: com.example.event.MyEvent[source=Hello]
事件的数据:Hello
是MyEvent?:true
监听器: MyListener
所在线程: http-nio-8080-exec-2
事件: com.example.event.MyEvent[source=Hello]
事件的数据:Hello
是MyEvent?:true

如果将监听器的实现的Ordered顺序颠倒,则输出结果如下:

发布器所在线程:http-nio-8080-exec-1
监听器: MyListener
所在线程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的数据:Hello
是MyEvent?:true
监听器: MyListener2
所在线程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的数据:Hello
是MyEvent?:true

步骤3:注册监听器

方式

适用范围

能否搭配@Async注解,进行异步监听

@Component

所有监听器


application.yml中添加配置

实现ApplicationListener<T>接口的监听器

不能

启动类中注册

实现ApplicationListener<T>接口的监听器

不能

法1:@Component(适用于所有监听器)

package com.example.event;

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class MyListener {
@EventListener
public void abc(MyEvent event) {
System.out.println("监听器:" + "MyListener");
System.out.println("线程:" + Thread.currentThread().getName());
System.out.println("事件:" + event);
System.out.println("事件的数据:" + event.getSource());
}
}
package com.example.event;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class MyListener2 implements ApplicationListener<MyEvent> {

@Override
public void onApplicationEvent(MyEvent event) {
System.out.println("监听器:" + "MyListener2");
System.out.println("线程:" + Thread.currentThread().getName());
System.out.println("事件:" + event);
System.out.println("事件的数据:" + event.getSource());
}
}

法2:application.yml中添加配置

只适用于实现ApplicationListener<T>接口的监听器

context:
listener:
classes: com.example.event.MyListener,com.example.event.MyListener2

法3:启动类中注册

只适用于实现ApplicationListener<T>接口的监听器

package com.example;

import com.example.event.MyListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 原来是这样的:SpringApplication.run(DemoApplication.class, args);
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
context.addApplicationListener(new MyListener());
}
}

步骤4:发布事件

法1:注入ApplicationContext,调用其publishEvent方法

package com.example.event;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class MyPublisher {
@Autowired
ApplicationContext applicationContext;

public void myPublish(String message) {
applicationContext.publishEvent(new MyEvent(message));
}
}

法2:启动类中发布

package com.example;

import com.example.event.MyEvent;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//原来是:SpringApplication.run(DemoApplication.class, args);
ConfigurableApplicationContext context =SpringApplication.run(DemoApplication.class, args);
context.publishEvent(new MyEvent("Hello"));
}
}


举报

相关推荐

0 条评论