Spring中的观察者模式
编码式监听器
观察者模式三个角色:事件本身,事件发布者,事件监听者。
Spring中的事件本身:集成抽象类ApplicationEvent
Spring中的事件发布者:ApplicationContext
Spring中的事件监听者:实现ApplicationListener接口
观察者模式实现的流程:
创建事件Event,Application发布Event,事件监听者接收处理Event。
实践代码
// 事件监听者
@Component
public class HuyonghaoListener implements ApplicationListener<HuyonghaoEvent> {
@Override
public void onApplicationEvent(HuyonghaoEvent event) {
System.out.println("监听到我这个成功了");
Huyonghao huyonghao = (Huyonghao) event.getSource();
System.out.println("我是谁:" +huyonghao.getName() + ", 我多大了" + huyonghao.getAge());
}
}
// source实体类
@Data
public class Huyonghao {
private String name;
private Integer age;
}
// 事件本身
public class HuyonghaoEvent extends ApplicationEvent {
public HuyonghaoEvent(Object source) {
super(source);
}
}
// 测试方法
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
"com.example.springlearn.listener");
HuyonghaoEvent event = new HuyonghaoEvent("sss");
Huyonghao huyonghao = new Huyonghao();
huyonghao.setAge(26);
huyonghao.setName("huyonghao");
ctx.publishEvent(new HuyonghaoEvent(huyonghao));
}
运行结果:
监听到我这个成功了
我是谁:huyonghao, 我多大了26
注解式监听器
@Component
public class HuyonghaoListenerDouble {
@EventListener
public void onApplicationEvent(HuyonghaoEvent event) {
System.out.println("监听到我这个成功了--2");
Huyonghao huyonghao = (Huyonghao) event.getSource();
System.out.println("我是谁:" +huyonghao.getName() + ", 我多大了--2" + huyonghao.getAge());
}
}
Spring中监听器实现原理
ApplicationContext实现了ApplicationEventPublisher接口
该接口中有两个方法
// 调用发布事件
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
// 真正执行的方法
void publishEvent(Object event);
}
改接口也有回调接口 ApplicationEventPublisherAware,实现改接口可实现启动容器注入事件发布者的子类,而不使用ApplicationContext进行发布事件
public interface ApplicationEventPublisherAware extends Aware {
void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
}
上述代码使用DEBUG跟踪:
最终发布事件调用的代码为AbstractApplicationContext 中的publishEvent方法
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
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 {
// 主要方法
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
}
最终获取监听器,执行监听器中的代码
@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 {
invokeListener(listener, event);
}
}
}