Spring 事件监听器示例及源码解析

Spring 事件监听器示例及源码解析


源码解析


ApplicationEvent

public abstract class ApplicationEvent extends EventObject {
    //序列化
    private static final long serialVersionUID = 7099057708183571937L;
    //时间戳
    private final long timestamp = System.currentTimeMillis();
    //source事件推送源
    public ApplicationEvent(Object source) {
        super(source);
    }

    public final long getTimestamp() {
        return this.timestamp;
    }
}

ApplicationContext - publishEvent()

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        //事件非null
        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().multicastEvent((ApplicationEvent)applicationEvent, eventType);
        }

        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
            } else {
                this.parent.publishEvent(event);
            }
        }

    }

SimpleApplicationEventMulticaster

public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        //获取线程池
        Executor executor = this.getTaskExecutor();
        //获取指定事件监听器的迭代器
        Iterator var5 = this.getApplicationListeners(event, type).iterator();
        
        while(var5.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var5.next();
            //线程池不为null
            if (executor != null) {
                //线程异步执行
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                //同步执行
                this.invokeListener(listener, event);
            }
        }

    }

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        //异常处理器
        ErrorHandler errorHandler = this.getErrorHandler();
        if (errorHandler != null) {
            try {
                //事件处理
                this.doInvokeListener(listener, event);
            } catch (Throwable var5) {
                errorHandler.handleError(var5);
            }
        } else {
            //事件处理
            this.doInvokeListener(listener, event);
        }

    }

 private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            //调用事件监听器处理事件
            listener.onApplicationEvent(event);
        } catch (ClassCastException var6) {
            String msg = var6.getMessage();
            if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
                throw var6;
            }

            Log logger = LogFactory.getLog(this.getClass());
            if (logger.isTraceEnabled()) {
                logger.trace("Non-matching event type for listener: " + listener, var6);
            }
        }

    }

代码


RedisPubSubConfig:Redis 订阅发布配置

@Configuration
public class RedisPubSubConfig {
    public final static String tokenChannel = "ztx";
    @Bean
    RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory) {
        RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
        redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
        redisMessageListenerContainer.addMessageListener(pubSubRefreshListener(), new ChannelTopic(tokenChannel));
        return redisMessageListenerContainer;
    }

    @Autowired
    EventPubSubService eventPubSubService;
    MessageListener pubSubRefreshListener() {
        //事件监听器
        return new MessageListener() {
            @SneakyThrows
            @Override
            public void onMessage(Message message, byte[] pattern) {
                //将message中的数据进行反序列化
                try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(message.getBody()))) {
                    //将事件强转为父接口类型
                    EventBase event = (EventBase) in.readObject();
                    //getEvent()获取的类型是子类型接口 此处泛型
                    eventPubSubService.subEvent(event.getEvent());
                }
            }
        };
    }

EventPubSubService:消息发布与事件发布

@Service
public class EventPubSubService {
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    ApplicationContext applicationContext;
    //消息推送 将消息推送到redis
    public void pubEvent(ApplicationEvent event) {
        redisTemplate.convertAndSend(RedisPubSubConfig.tokenChannel, event);
    }
	
    //将redis发布的事件进行发布
    public <T> void subEvent(T event) {
        applicationContext.publishEvent(event);
    }

}

EventBase:事件接口

//泛型 用于统一发布事件 不同监听器各自监听
public interface EventBase<T> {
    T getEvent();
}

ZTXEvent:事件类

@Getter
public class ZTXEvent extends ApplicationEvent implements EventBase<ZTXEvent>, Serializable {
    private String carId;
    private Integer type;
    private byte param;


    public ZTXEvent() {
        super("ztx");
    }

    public ZTXEvent(String carId, Integer type, byte param) {
        super("ztx");
        this.carId = carId;
        this.type = type;
        this.param = param;
    }


    @Override
    public ZTXEvent getEvent() {
        return this;
    }
}

ZTXEventListener:事件监听器

@Service
public class ZTXEventListener implements ApplicationListener<ZTXEvent> {
    @Autowired
    EquipmentServiceImpl equipmentService;
    
    //处理事件
    @Override
    public void onApplicationEvent(ZTXEvent ztxEvent) {
        ChannelHandlerContext ctx = equipmentService.carCtx.get(ztxEvent.getCarId()).getCtx();
        ProtocolOfZTX protocolOfZTX = new ProtocolOfZTX();
        protocolOfZTX.setAgvId(Byte.parseByte(ztxEvent.getCarId()));
        switch (ztxEvent.getType()){
            case 1:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{5,2});  //前
                break;
            case 2:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{5,3});  //后
                break;
            case 3:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{7,2});  //左
                break;
            case 4:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{7,3});  //右
                break;
            case 5:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{7,3});  //右
                break;
            case 6:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{6,0});  //停止
                break;
            case 7:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{8,ztxEvent.getParam()});  //速度
                break;
            case 8:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{0x0B,1,0,0,0});  //急停
                break;
            case 9:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{0x0B,0,1,0,0});  //准备
                break;
            case 10:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{0x0B,0,0,1,0});  //故障清除
                break;
            case 11:
                setProtocolOfZTXData(protocolOfZTX,new byte[]{0x0B,0,0,0,1});  //驱动提升
                break;
            default:
                break;
        }
        ctx.writeAndFlush(protocolOfZTX);
    }

    private void setProtocolOfZTXData(ProtocolOfZTX protocolOfZTXData,byte[] bytes){
        byte[] data = new byte[20];
        System.arraycopy(bytes, 0, data, 0, bytes.length);
        protocolOfZTXData.setData(data);
    }
}

流程

类分布

  • A系统包含类
    • ZTXEvent
    • RedisPubSubConfig
    • EventBase
  • B系统包含类
    • EventBase
    • ZTXEvent
    • ZTXEventListener

工作流程

  • A系统
    • 界面按钮点击
    • redis推送时间ZTXEvent(自定义事件)
  • B系统
    • 接受到Redis发布的时间
    • 发布事件ZTXEvent
    • ZTXEventListener对ZTXEvent进行事件处理

设计原理

A系统需要和B系统进行通信,A系统推送事件后,B系统收到事件并将该事件发布,B系统实现了该事件的监听器,C系统没有实现该事件的监听器,所以B该事件只对B系统有效。

在这种情况下,所有需要相互交互的系统,都只需要通过redis发布事件即可,若某个系统对该事件感兴趣则只需要实现该事件的监听器即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值