注解+反射实现动态调用

一. 业务场景说明

    微服务开发,有两个独立的应用服务:a 和 b,a是聚合入口服务,单向调用关系,即 a -> b。又有一个开放平台服务c,需要先调用a,然后再a中回调通知b。但开发平台回调通知的时间有很多,在a中不想对每一个通知时间都写一个方法rest接口来接收,而是想用一个rest方法统一收归开放平台的各种通知,然后根据通知类型分派到b中不同的api里,这样保证了a作为聚合入口服务的纯粹性,开放平台也只需要和a的这一个统一收归的接口交互,真正的业务处理放到b中,各自职责明确。那么如何实现呢?

二. 通过注解动态获取类,并反射调用api

a服务中

  1. 自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Event {
    OpenPlatformEventEnum type();
}
  1. 开放平台通知枚举定义
/**
 * 开放平台event枚举类
 */
public enum OpenPlatformEventEnum {
    /**
     * 删除货源
     */
    DELETE_CARGO("ymm.cargo.delete");
   
    private String code;
    
    OpenPlatformEventEnum(String code) {
        this.code = code;
    }
    
    public String getCode() {
        return code;
    }
    
    public static OpenPlatformEventEnum getEventByCode(String code){
        OpenPlatformEventEnum[] values = values();
        for (OpenPlatformEventEnum value : values) {
            if (value.getCode().equals(code)) {
                return value;
            }
        }
        return null;
    } 
}
  1. 通知事件处理器定义
public interface EventHandler {
    Response invoke(CallBackResultDto callBackResultDto);
}

@Event(type= OpenPlatformEventEnum.DELETE_CARGO)
public class DeleteCargoEventHandlerImpl implements EventHandler {
    // b服务的RPC api类
    @Autowired
    private CallBackFacade callBackFacade;

    @Override
    public Response invoke(CallBackResultDto callBackResultDto) {
        BaseResponse baseResponse = callBackFacade.deleteCargo(callBackResultDto.getEvent(), callBackResultDto.getData());
        if (!baseResponse.isSuccess()) {
            return Response.newFailResponse(Integer.valueOf(ErrorEnum.SERVER_ERROR.getCode()), baseResponse.getMsg());
        }
        return Response.SUCCESS;
    }
}
  1. 事件处理管理器定义
@Component
public class EventHandlerManager implements BeanPostProcessor {
    private Map<OpenPlatformEventEnum,EventHandler> eventHandlerMap = Maps.newConcurrentMap();

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 实例化阶段,过滤掉非EventHandler
        if (!(bean instanceof EventHandler)) {
            return bean;
        }
		
		// 扫描注解,在项目启动阶段检查必要信息是否缺失
        Event event = AnnotationUtils.findAnnotation(bean.getClass(), Event.class);
        if (event == null) {
            throw new BeanCreationException("EventHandler must mark @Event annotation");
        }
        OpenPlatformEventEnum eventType = event.type();
        EventHandler eventHandler = eventHandlerMap.get(eventType);
        if(eventHandler == null){
            eventHandlerMap.put(eventType,(EventHandler) bean);
        }
        return bean;
    }

    public EventHandler getEventHandlerByType(OpenPlatformEventEnum type){
        if(type == null){
            return null;
        }
        return eventHandlerMap.get(type);
    }
}
  1. Rest接口api定义
/**
* 开放平台回调处理类
*/
@RestController
@Slf4j
public class OpenPlatformController {
    @Autowired
    private EventHandlerManager eventHandlerManager;

    /**
     * 开放平台回调处理方法
     * 开放平台的各种通知统一收归到一个入口
     * @param request 请求对象
     * @return 处理结果
     */
    @RequestMapping(value = "/openPlatform/dealCallBack", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
    public OpenPlatformResult dealCallBack(@RequestBody DealCallBackRequest request) {
        OpenPlatformResult response = new OpenPlatformResult();
        if (request == null || StringUtils.isEmpty(request.getResult())) {
            log.error("开放平台返回的请求为空");
            return response;
        }

        String result = request.getResult();
        if (request.getEncrypt() == 1) {
            try {
                result = AESHexUtil.decryptBase64DecorateAES(result, OpenPlatformLionConfig.getOpenPlatformDecryptKey());
            } catch (Exception e) {
                log.error("开放平台解密失败");
                return response;
            }
        }

        CallBackResultDto callBackResultDto = JSON.parseObject(result, CallBackResultDto.class);
        log.info("开放平台回调的请求,{}", JSON.toJSONString(callBackResultDto));
        if (callBackResultDto == null || StringUtils.isEmpty(callBackResultDto.getEvent())) {
            log.error("开放平台转换后的请求对象为空");
            return response;
        }

        // 从枚举类中获取反射的类
        EventHandler eventHandler = eventHandlerManager.getEventHandlerByType(OpenPlatformEventEnum.getEventByCode(callBackResultDto.getEvent()));
        if (eventHandler == null) {
            log.warn("根据开放平台的eventCode没有找到对应的处理类,eventCode:{}", callBackResultDto.getEvent());
            return response;
        }

        // invoke调用各自的业务类
        if (reflectCall(callBackResultDto, eventHandler)) {
            return response;
        }
        response.setResult("success");
        return response;
    }

    /**
     * 反射到子类调用是否抛异常
     *
     * @param callBackResultDto 请求参数
     * @return 调用结果
     */
    private boolean reflectCall(CallBackResultDto callBackResultDto, EventHandler eventHandler) {
        try {
            Response response = eventHandler.invoke(callBackResultDto);
            if (!response.success()) {
                log.error("调用失败", response.getMsg());
                return true;
            }
        } catch (Exception e) {
            log.error("调用失败", e);
            return true;
        }
        return false;
    }
}

a服务与b服务之间是通过RPC调用的。

<bean id="callBackFacade" class="com.dianping.dpsf.spring.ProxyBeanFactory" init-method="init">
    <property name="serviceName" value="http://service.tms.com/pigeon/callBackFacade_1.0.0"/>
    <property name="iface" value="com.saas.tms.trans.api.facade.CallBackFacade"/>
    <property name="serialize" value="hessian"/>
    <property name="callMethod" value="sync"/>
    <property name="timeout" value="5000"/>
</bean>

b服务中

  • 回调处理类
public interface CallBackFacade{
	/**
	* 删除货源通知
	*/
	BaseResponse deleteCargo(String event,String data);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值