common-event-ao

  • 事件中心核心服务,集成事件接入-事件加工-事件分发

1.事件过滤能力(Filter)

1.1.接入步骤

  1. 先引入common-event-ao-stub
<dependency>
       <groupId>com.hooware.cc.fucomm-event-ao</groupId>
       <artifactId>common-event-ao-stub</artifactId>
       <version>1.0.1</version>
</dependency>

2.实现SPI过滤接口

1.com.hooware.cc.common.event.ao.spi.IEventSpiFilter

3.实现类添加@EventSPI注解

1.SPI注解:com.hooware.cc.common.event.ao.spi.EventSPI

2.同时指定自己对应的渠道com.hooware.cc.common.event.ao.spi.EventChannelTypeEnum

3.自行根据自己的业务完成实现该接口过滤的业务逻辑(确保性能和兜底)

4.提供自己实现类的包及类路径

1.事件中心添加下游实现的SPI包依赖maven坐标;

2.在META-INF/spring.factories中添加实现类路径

  1. 默认事件过滤SPI实现示例
package com.hooware.cc.common.event.ao.infrastructure.spi;


import com.hooware.cc.common.event.ao.spi.EventSPI;
import com.hooware.cc.common.event.ao.spi.EventSpiFilterRequest;
import com.hooware.cc.common.event.ao.spi.IEventSpiFilter;

@EventSPI(DefaultEventSpiFilter.NAME)
public class DefaultEventSpiFilter implements IEventSpiFilter {

    public static final String NAME = "default";

    @Override
    public boolean doFilter(EventSpiFilterRequest request) {
        // default默认放行不过滤
        return true;
    }
}

1.2.核心逻辑

  • 事件过滤采用责任链模式完成事件的链式加工(短路链式,某个实现类如果拦截则会直接返回,后续过滤器不会参与逻辑处理)

事件过滤UML类图

事件过滤UML类图20220916162831479.png

事件过滤基础类图20220916163152108.png

  • SPI相关能力包路径:com.hooware.cc.common.event.ao.spi

    1.事件过滤SPI接口: IEventSpiFilter;

    2.接口基础Req请求:EventSpiFilterRequest;

    3.事件过滤SPI注解:EventSPI;

    4.事件核心过滤器:SpiEventFilter

    5.META-INF/spring.factories文件

  1. IEventSpiFilter: 定义SPI事件过滤器接口,用户下游自行实现决定是否需要过滤事件中心的接受到的事件, 如不过滤则会投递到该下游渠道, 如过滤则直接拦截
package com.hooware.cc.common.event.ao.spi;

/**
 * SPI事件过滤器接口, 用户下游差异性实现决策是否需要过滤事件中心的接受到的事件, 如不过滤则会投递到该下游渠道, 如需要过滤则直接拦截
 */
public interface IEventSpiFilter {

    /**
     * 过滤事件中心的接受到的事件, 如不过滤则会投递到该下游渠道, 如需要过滤则直接拦截
     *
     * @param request 标准请求体
     * @return bool值, true: 需要过滤, false: 无需过滤
     */
    boolean doFilter(EventSpiFilterRequest request);
}
  1. EventSpiFilterRequest:SPI事件过滤器接口基础请求,包含基础用户、资产及事件源报文字段
package com.hooware.cc.common.event.ao.spi;

import lombok.Data;
import lombok.experimental.Accessors;

/**
 * SPI扩展filter请求结构
 */
@Data
@Accessors(chain = true)
public class EventSpiFilterRequest {

    /**
     * 用户唯一标识uin
     */
    private String uin;

    /**
     * 用户唯一标识userId
     */
    private String userId;

    /**
     * 账号唯一标识tradeId
     */
    private String tradeId;

    /**
     * 基金代码fundCode
     */
    private String fundCode;

    /**
     * 原始事件源Json数据串, 如api接口请求则为request串
     */
    private String eventData;

}
  1. EventSPI:事件过滤SPI注解,下游实现类需加该注解并指明对应渠道EventChannelTypeEnum,否则会被过滤掉而不被执行
package com.hooware.cc.common.event.ao.spi;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventSPI {

    /**
     * 表示插件名称,为空表示从配置文件解析插件名称。支持配置文件和该注解同时配置插件名称,优先使用配置文件中配置的名称。
     *
     * @return 插件名称
     */
    String value() default "";

    /**
     * 下游渠道设置, 用于筛选执行
     *
     * @return 下游渠道
     */
    EventChannelTypeEnum channel() default EventChannelTypeEnum.UNKNOWN;

}
  1. SpiEventFilter:事件核心过滤器实现,使用Spring的spring.factories方式实现SPI机制
package com.hooware.cc.common.event.ao.domain.dispatch.filter.impl;

import com.hooware.cc.common.event.ao.application.dto.StandardDispatchEventDTO;
import com.hooware.cc.common.event.ao.domain.dispatch.filter.IEventFilter;
import com.hooware.cc.common.event.ao.domain.dispatch.filter.IEventFilterChain;
import com.hooware.cc.common.event.ao.spi.EventSPI;
import com.hooware.cc.common.event.ao.spi.EventSpiFilterRequest;
import com.hooware.cc.common.event.ao.spi.IEventSpiFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.stereotype.Service;

import java.util.List;


/**
 * spi机制加载外部实现, todo 下游可能存在性能瓶颈, 待后续实际情况优化
 */
@Slf4j
@Service
@Order(0)
public class SpiEventFilter implements IEventFilter, InitializingBean {

    /**
     * spi加载列表
     */
    private List<IEventSpiFilter> spiFilters;

    @Override
    public void afterPropertiesSet() throws Exception {
        // 加载所有的spi扩展点
        // ServiceLoader<IEventSpiFilter> spiFilters = ServiceLoader.load(IEventSpiFilter.class);

        spiFilters = SpringFactoriesLoader.loadFactories(IEventSpiFilter.class,
                Thread.currentThread().getContextClassLoader());
    }

    @Override
    public boolean doFilter(StandardDispatchEventDTO dispatchEventDTO, IEventFilterChain chain) {
        // 构建下游请求request
        EventSpiFilterRequest request = this.buildRequest(dispatchEventDTO);

        for (IEventSpiFilter spiFilter : spiFilters) {

            EventSPI eventSPI = AnnotatedElementUtils.findMergedAnnotation(spiFilter.getClass(), EventSPI.class);
           // 校验spi加载渠道, 非该渠道不参与过滤
            if (eventSPI == null || !eventSPI.channel().equals(
                    dispatchEventDTO.getDispatchConfig().getEventChannel().getChannelType())) {
                continue;
            }
            // 进行spi过滤执行
            if (!spiFilter.doFilter(request)) {
                return false;
            }
        }

        return true;
    }

    private EventSpiFilterRequest buildRequest(StandardDispatchEventDTO dispatchEventDTO) {
        return new EventSpiFilterRequest().setUin(dispatchEventDTO.getUin())
                .setUserId(dispatchEventDTO.getUserId())
                .setFundCode(dispatchEventDTO.getFundCode())
                .setTradeId(dispatchEventDTO.getTradeId())
                .setEventData(dispatchEventDTO.getEventData());
    }
}
  1. spring.factories: Spring采用的是spring.factories方式实现SPI机制,下游实现类需在此处指定用于加载,路径为"META-INF/spring.factories"
com.hooware.cc.common.event.ao.spi.IEventSpiFilter = \
  com.hooware.cc.common.event.ao.infrastructure.spi.DefaultEventSpiFilter

2.事件加工能力(Handler)

  • 事件加工也采用责任链模式完成事件的链式加工(完全链式,每个实现类均会加工处理)

事件加工UML类图

事件加工UML类图20220916164212200.png

1.事件加工接口IEventHandler:

2.事件处理工厂EventHandleFactory:

3.实际加工实现类:DefaultEventHandler,GroovyScriptEventHandler,UserInfoEventHandler

  1. 事件加工接口IEventHandler:顶层事件加工接口,基于源事件和分发事件DTO和分发配置Entity进行链式加工
package com.hooware.cc.common.event.ao.domain.process.handler;

import com.hooware.cc.common.event.ao.application.dto.StandardDispatchEventDTO;
import com.hooware.cc.common.event.ao.application.dto.StandardSourceEventDTO;
import com.hooware.cc.common.event.ao.domain.manage.entity.EventDispatchConfigEntity;

public interface IEventHandler {

    /**
     * 事件加工链式处理
     *
     * @param sourceEvent   原始标准事件源
     * @param dispatchEvent 分发标准事件
     * @param config        事件分配配置,包含加工脚本
     */
    void handle(StandardSourceEventDTO sourceEvent, StandardDispatchEventDTO dispatchEvent,
                EventDispatchConfigEntity config);

}
  1. 事件处理工厂EventHandleFactory:用于串起所有的事件IEventHandler实现类,按照@Order优先级顺序加工处理(可能经过差异性加工后需要进行过滤掉)
package com.hooware.cc.common.event.ao.domain.process.handler;

import com.hooware.cc.common.event.ao.application.dto.StandardDispatchEventDTO;
import com.hooware.cc.common.event.ao.application.dto.StandardSourceEventDTO;
import com.hooware.cc.common.event.ao.domain.manage.entity.EventDispatchConfigEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 事件执行策略工厂, todo 下游处理可能存在性能问题
 */
@Slf4j
@Service
public class EventHandleFactory {

    private final List<IEventHandler> eventHandlerList;

    @Autowired
    public EventHandleFactory(List<IEventHandler> eventHandlerList) {
        this.eventHandlerList = eventHandlerList;
    }

    public void handle(StandardSourceEventDTO sourceEvent, StandardDispatchEventDTO dispatchEvent,
                       EventDispatchConfigEntity config) {

        // 按照@Order优先级顺序处理事件源和事件结果
        for (IEventHandler eventHandler : eventHandlerList) {
            // 链式处理事件
            eventHandler.handle(sourceEvent, dispatchEvent, config);
        }

    }
}
  1. 实际加工实现类:DefaultEventHandler(最高优先级,进行默认的StandardDispatchEventDTO封装处理), GroovyScriptEventHandler(提供Grrovy脚本定制化加工能力), UserInfoEventHandler(用户信息加工,如补全用户的uin,userId等信息)
- 实际加工参照实现类: DefaultEventHandler,GroovyScriptEventHandler,UserInfoEventHandler

3.事件分发能力(Dispatcher)

Q.E.D.


谁言不解广寒情,天边一颗伴月星