作者:京东零售 常文标

商卡聚合服务是一个小巧的rpc运用,功用是一致查询商品的促销、自营包邮、价格信息、区域库存、区域可配送等等利益点或其他信息。本文重点共享商卡聚合服务的代码规划,包括合理的Sirector线程调度(cpu运用率低),和可保护性的规划。 简版代码示例如下: git@github.com:changwenbiao/demosoa.git

代码运用sirector-core组件并行调度(运用线程并行履行EventHandler的onEvent办法)恳求上游rpc接口获取各利益点或其他商品信息。由于恳求上游有些通用处理逻辑比方ump监控、调用开关等,所以笼统出一个通用的EventHandler名为AbstractBenefitHandler。详细调用利益点的完成类只需继承AbstractBenefitHandler并重写其笼统办法。

记录一次还算优雅的代码设计

接下来重点讲代码怎么节约cpu运用率和易于保护的规划。

1.怎么节约cpu

AbstractBenefitHandler提供isSwitchOn办法,用于决议是否运用sirector组件分配线程履行调度EventHandler。相对于分配线程履行全部的EventHandler,判别是否需要调用才分配线程调用的方式可有效削减线程调度从而削减cpu运用率。isSwitchOn办法中可参加cms操控开关逻辑比方运用ducc开关,也可参加根据用户参数判别开关的逻辑,比方查询区域库存需要四级地址,若用户不传四级地址则封闭调用EventHandler(恳求上游rpc)。代码完成如下:其中ducc开关在父类中的isSwitchOn中完成,sirector.begin办法承受可变参数列表参数,可将List转化为AbstractBenefitHandler[]作为入参。

@Override
public boolean isSwitchOn() {    
    boolean superSwitchOn = super.isSwitchOn();    
    if (!superSwitchOn) {        
        return false;    
    } else {        
        //正常为四级地址,如果少于四级则封闭调用        
        String area = seckillBenefitRequest.getSeckillParam().getArea();        
        return !StringUtils.isBlank(area) && area.contains("_") && area.split("_").length >= 4;   
    }
}
List<String> handlerNames = Lists.newArrayList("areaStockHandler", "partitionProductsHandler");
List<AbstractBenefitHandler> handlerList = handlerNames.stream()        
.map(handlerName -> applicationContext.getBean(handlerName, AbstractBenefitHandler.class).setBenefitRequestAndBizName(request, "demoAppName"))        
.filter(AbstractBenefitHandler::isSwitchOn).collect(Collectors.toList());
Sirector<MiaoShaEvent> sirector = new Sirector<MiaoShaEvent>(bigSeckillEventProcessThreadPool);
AbstractBenefitHandler[] eventHandlersArr = new AbstractBenefitHandler[handlerList.size()];
handlerList.toArray(eventHandlersArr);
sirector.begin(eventHandlersArr);
sirector.ready();
sirector.publish(new MiaoShaEvent(), 500); //这儿开始运用线程并行履行EventHandler的onEvent办法

2. 怎么简单保护

削减一些模版代码(如ump监控):一切Handler的完成类的ump监控都写在父类中的onEvent中,父类的onEvent调用子类完成的onEvent0(处理详细利益点rpc恳求处理)办法。

矮小代码的完成:AbstractBenefitHandler提供fillResponseInfo办法以向“ResponseVO”中填数据,详细填利益点数据的代码则由相应handler完成类处理。因此各个handler填充利益点“ResponseVO”的代码都是矮小的,避免了代码写在一起的长代码。单个handler填充利益点数据和批量一致填充利益点数据代码分别如下:

@Override
public void fillResponseInfo(List<BftInfo> bftInfoList) {    
    if (MapUtils.isNotEmpty(areaStockMap)) {        
        for (BftInfo result : bftInfoList) {            
            String skuId = result.getBaseInfo().getSkuId();            
            if (areaStockMap.containsKey(skuId)) {                
                result.getCommonInfo().setAreaStock(areaStockMap.get(skuId));            
            }        
        }    
    }
}
handlerList.forEach(h -> h.fillResponseInfo(bftInfoList));

削减一些硬编码:handler完成类配置为原型形式(scope=”prototype”)的spring bean,通过applicationContext.getBean办法一致获取,避免一些创立(new关键字)详细完成类的代码,若新增利益点调用只需编码AbstractBenefitHandler完成类并配置为spring bean即可。批量获取handler代码如下

List<String> handlerNames = Lists.newArrayList("areaStockHandler", "partitionProductsHandler");
List<AbstractBenefitHandler> handlerList = handlerNames.stream()        
.map(handlerName -> applicationContext.getBean(handlerName, AbstractBenefitHandler.class).setBenefitRequestAndBizName(request, "demoAppName"))        
.filter(AbstractBenefitHandler::isSwitchOn).collect(Collectors.toList());