参考文章:https://www.baeldung.com/spring-events
在spring框架中Events是容易被忽略的功能,事件发布是由ApplicationContext(bean的容器)提供的。下面的简单的提供一些示例代码说明一下相关功能
同步事件处理
下面的示例中说明了注入ApplicationEventPublisher的两种方式,监听事件的两种方式。以及对同一类型的事件监听多次的优先级处理,默认是同步进行处理的,我们可以通过打印日志来验证。
package annotation;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
/**
* @author chengliangpu
* @date 2021/10/13
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader = AnnotationConfigContextLoader.class,
classes = {SpringEvent.CustomSpringEventPublisher.class, SpringEvent.CustomSpringEventListener.class})
public class SpringEvent {
@Autowired
private CustomSpringEventPublisher eventPublisher;
@Test
public void publish() {
this.eventPublisher.publishCustomEvent("hello world");
}
/**
* 通过实现ApplicationEventPublisherAware,注入ApplicationEventPublisher
*/
// @Component
// public static class CustomSpringEventPublisher implements ApplicationEventPublisherAware {
// private ApplicationEventPublisher applicationEventPublisher;
//
// public void publishCustomEvent(final String message) {
// System.out.println("Publishing custom event. ");
// System.out.println("Publishing Thread:"+Thread.currentThread().toString());
// CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
// applicationEventPublisher.publishEvent(customSpringEvent);
// }
//
// @Override
// public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
// this.applicationEventPublisher = applicationEventPublisher;
// }
// }
/**
* 最简单的方式是通过@Autowired自动注入ApplicationEventPublisher
*/
@Component
public static class CustomSpringEventPublisher {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void publishCustomEvent(final String message) {
System.out.println("Publishing custom event. ");
System.out.println("Publishing Thread:" + Thread.currentThread().toString());
CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
applicationEventPublisher.publishEvent(customSpringEvent);
}
}
/**
* 通过实现ApplicationListener注册event监听器
*/
// @Component
// public static class CustomSpringEventListener implements ApplicationListener {
//
// @Override
// public void onApplicationEvent(CustomSpringEvent event) {
// System.out.println("Received spring custom event - " + event.getMsg());
// System.out.println("Received Thread:" + Thread.currentThread().toString());
// }
// }
/**
* 通过@EventListener注册event监听器
*/
@Component
public static class CustomSpringEventListener {
@EventListener
@Order(value = Ordered.LOWEST_PRECEDENCE)
public void onApplicationEvent(CustomSpringEvent event) {
System.out.println("Received spring custom event - " + event.getMsg());
System.out.println("Received Thread:" + Thread.currentThread().toString());
}
@EventListener
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public void onApplicationEvent1(CustomSpringEvent event) {
System.out.println("Received1 spring custom event - " + event.getMsg());
System.out.println("Received1 Thread:" + Thread.currentThread().toString());
}
}
public static class CustomSpringEvent extends ApplicationEvent {
private String msg;
/**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})
*/
public CustomSpringEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
public String getMsg() {
return this.msg;
}
}
}
我们可以观察监听到的事件是同步的,他们的线程信息是一致的
异步事件处理
事件的异步处理大体和上面是一样的,只是需要配置一下ApplicationEventMulticaster
完整的示例代码如下
package annotation;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.EventListener;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
/**
* @author chengliangpu
* @date 2021/10/13
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader = AnnotationConfigContextLoader.class,
classes = {SpringEventAync.AsynchronousSpringEventsConfig.class, SpringEventAync.CustomSpringEventPublisher.class, SpringEventAync.CustomSpringEventListener.class})
public class SpringEventAync {
@Autowired
private CustomSpringEventPublisher eventPublisher;
@Test
public void publish() {
this.eventPublisher.publishCustomEvent("hello world");
}
/**
* 配置event的异步处理,可以观察打印的线程信息查看是否是异步处理
*/
@Configuration
public static class AsynchronousSpringEventsConfig {
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster =
new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}
}
/**
* 通过实现ApplicationEventPublisherAware,注入ApplicationEventPublisher
*/
// @Component
// public static class CustomSpringEventPublisher implements ApplicationEventPublisherAware {
// private ApplicationEventPublisher applicationEventPublisher;
//
// public void publishCustomEvent(final String message) {
// System.out.println("Publishing custom event. ");
// System.out.println("Publishing Thread:"+Thread.currentThread().toString());
// CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
// applicationEventPublisher.publishEvent(customSpringEvent);
// }
//
// @Override
// public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
// this.applicationEventPublisher = applicationEventPublisher;
// }
// }
/**
* 最简单的方式是通过@Autowired自动注入ApplicationEventPublisher
*/
@Component
public static class CustomSpringEventPublisher {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void publishCustomEvent(final String message) {
System.out.println("Publishing custom event. ");
System.out.println("Publishing Thread:" + Thread.currentThread().toString());
CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
applicationEventPublisher.publishEvent(customSpringEvent);
}
}
/**
* 通过实现ApplicationListener注册event监听器
*/
// @Component
// public static class CustomSpringEventListener implements ApplicationListener {
//
// @Override
// public void onApplicationEvent(CustomSpringEvent event) {
// System.out.println("Received spring custom event - " + event.getMsg());
// System.out.println("Received Thread:" + Thread.currentThread().toString());
// }
// }
/**
* 通过@EventListener注册event监听器
*/
@Component
public static class CustomSpringEventListener {
@EventListener
@Order(value = Ordered.LOWEST_PRECEDENCE)
public void onApplicationEvent(CustomSpringEvent event) {
System.out.println("Received spring custom event - " + event.getMsg());
System.out.println("Received Thread:" + Thread.currentThread().toString());
}
@EventListener
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public void onApplicationEvent1(CustomSpringEvent event) {
System.out.println("Received1 spring custom event - " + event.getMsg());
System.out.println("Received1 Thread:" + Thread.currentThread().toString());
}
}
public static class CustomSpringEvent extends ApplicationEvent {
private String msg;
/**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})
*/
public CustomSpringEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
public String getMsg() {
return this.msg;
}
}
}
验证一下输出的日志线程信息,发现监听所使用的线程和发送的确不一样。
结合泛型和SpEl定义通用事件
@Data
@AllArgsConstructor
public class LogEvent {
private T source;
private LogType type;
}
@Slf4j
public class UsualLogListener {
public UsualLogListener(){
}
@Async
@Order
@EventListener(classes = LogEvent.class, condition = "#event.type == T(com.springboot.cloud.common.web.entity.enums.LogType).USUAL_LOG")
public void saveApiLog(LogEvent event) {
LogUsual logUsual = event.getSource();
// 测试异步监听,要开启异步参数,在入口需要加上@EnableAsync注解
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info(logUsual.toString());
// todo:把日志归档到es
}
}