本文章介绍spring内部事件是如何发布,监听消息是怎么消费的。
一般来说spring发布事件,监听器接收并执行,是同步的。这样写虽然代码分离,但同步执行时间就会增加,想改为异步执行,在监听方法上加@Async注解。
目录
测试代码
发布消息
监听消息
spring事件源码分析
自己新建一个springboot项目
import com.example.demo2.AppConfig;
import com.example.demo2.domain.dto.AnaimalEvent;
import com.example.demo2.domain.dto.Dog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author wfl 2021/12/10
* 功能
*/
@Slf4j
public class UserListener {
public static void main(String[] args) {
// 创建spring 容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Dog dog = new Dog();
dog.setAddr("aa");
dog.setName("eventlistener");
context.publishEvent(dog);
Dog dog2 = new Dog();
dog2.setAddr("cc");
dog2.setName("Applicationlistener");
AnaimalEvent event = new AnaimalEvent(dog2);
context.publishEvent(event);
log.info("jjjjj");
context.close();
}
}
以上发布了2中事件,一种是继承ApplicationEvent类的AnaimalEvent。一种是Dog类。
监听事件也是2种形式,1实现了ApplicationListener;
2. 使用注解@EventListener org.springframework.context.event.EventListener
或者@TransactionalEventListener org.springframework.transaction.event.TransactionalEventListener;
注解监听
import com.example.demo2.domain.dto.Dog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* @Author wfl 2021/12/10
* 功能
*/
@Component
@Slf4j
public class AnaimalEventListen {
//这个asyncGmOrderHttpExecutor 是自定义的,可以删除,使用springboot默认的
@Async("asyncGmOrderHttpExecutor")
@EventListener
public void hanlderAnaimal(Dog dog){
System.out.println(Thread.currentThread().getName() + "=====注解监听===");
log.info("llllll");
}
}
实现监听器
import com.example.demo2.domain.dto.AnaimalEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* @Author wfl 2021/12/14
* 功能
*/
@Component
public class MyAnaimalListener implements ApplicationListener {
@Override
public void onApplicationEvent(AnaimalEvent event) {
System.out.println("实现监听器----"+event);
}
}
其他实体类
import lombok.Data;
/**
* @Author wfl 2021/12/10
* 功能
*/
@Data
public class Dog extends Anaimal{
private String name;
}
import lombok.Data;
import org.springframework.context.ApplicationEvent;
import java.time.Clock;
/**
* @Author wfl 2021/12/10
* 功能
*/
@Data
public class Anaimal {
private String addr;
}
import org.springframework.context.ApplicationEvent;
/**
* @Author wfl 2021/12/10
* 功能
*/
public class AnaimalEvent extends ApplicationEvent {
private String addr;
public AnaimalEvent(Object source) {
super(source);
}
}
配置类
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* @Author wfl 2021/12/10
* 功能 配置类,开启异步功能
*/
@Configuration
@ComponentScan("com.*")
@EnableAsync
public class AppConfig {
}
以上代码就可以运行,实现发布事件,监听事件。项目需要注入事件发布类
ApplicationContext
@RestController
@RequestMapping(value = "/user" )
public class UserController {
@Resource
private ApplicationContext applicationContext;
@GetMapping("/a")
public int accountAdssd(){
Anaimal dog = new Dog();
dog.setAddr("aa");
applicationContext.publishEvent(dog);
return 2;
}
}
下面介绍源码执行过程
先从事件发布入手。applicationContext.publishEvent(dog);
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
//...............省略代码
//发布事件方法
public void publishEvent(Object event) {
this.publishEvent(event, (ResolvableType)null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
Object applicationEvent;
//处理第二种实现ApplicationEvent类的事件
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent)event;
} else {
applicationEvent = new PayloadApplicationEvent(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
}
}
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
//上面是一些判断处理,最后会走到这。 this.getApplicationEventMulticaster()获取事件发布器。再发布
this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
}
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
}
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener> listener : getApplicationListeners(event, type)) {
// 这个异步执行器一般是空的。
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
// 会执行这个反射 这里体现的就是同步执行
//其中这个listener 就会分两种,一种注解的,
//被ApplicationListenerMethodAdapter包装的监听类
//另一种是实现监听的,下面加载的时候会介绍
invokeListener(listener, event);
}
}
}
}
这里会同步执行消息处理,如果要异步加@Async注解实现。
invokeListener(ApplicationListener> listener, ApplicationEvent event)----》
doInvokeListener(listener, event);----->
listener.onApplicationEvent(event);这里的listener是ApplicationListenerMethodAdapter打开这个类找到onApplicationEvent(event)方法;----->
processEvent(event);
/**
* Process the specified {@link ApplicationEvent}, checking if the condition
* matches and handling a non-null result, if any.
*/
public void processEvent(ApplicationEvent event) {
Object[] args = resolveArguments(event);
if (shouldHandle(event, args)) {
Object result = doInvoke(args);
if (result != null) {
handleResult(result);
}
else {
logger.trace("No result object given - no result to handle");
}
}
}
然后执行
Object result = doInvoke(args);----》反射执行,有返回结果result会接收到。---》
protected Object doInvoke(Object... args){ //这个bean是从spring中拿到的监听类 Object bean = this.getTargetBean(); //省略代码.... try { //反射执行 return this.method.invoke(bean, args); } }
此时还在ApplicationListenerMethodAdapter这个类中,大约在342行源码。
断点调试图@EventListener执行过程
实现监听调试class MyAnaimalListener implements ApplicationListener
下面是复杂的加异步注解的调试
加异步注解后返回的是异步执行代理类这里与没加异步注解返回的bean是不一样的
构建一个代理,执行proceed() 进入异步拦截器执行
下图,开始提交任务,异步执行
这里,事件发布介绍完了。
监听如何加载的另一篇文章介绍。
https://blog.csdn.net/wangfenglei123456/article/details/121930345https://blog.csdn.net/wangfenglei123456/article/details/121930345