• PGET,一个简单、易用的并行获取数据框架


    使用场景

    当我们的服务收到一个请求后,需要大量调用下游服务获取业务数据,然后对数据进行转换、计算后,响应给请求方。

    如果我们采用串行获取下游数据,势必会增加响应时长,降低接口的qps。如果是并行获取下游数据,则是不错的。

    最直接想到的并行获取方法,无非是将一个个获取数据的方法封装成一个个task,然后放到线程池里执行。但这种没经过设计的使用方式,易用性很低,可复用性也很低。

    经本人在实际的业务系统中,多次思考与设计。终于设计出当前这个框架。

    特点:绝对的简单、绝对的易用。

    相关概念

    • BizData

    业务数据对象。用于将下游获取到的数据封装到此对象中。

    开发者需自定义给对象,并实现IBizData接口

    • BizDataProvider

    业务数据对象提供者。此对象类似于分成结构中的Service层,其调用下游数据源(可以是rpc调用等)将得到的数据封装到BizData对象中。

    此类需要添加@BizDataProvider注解。其方法返回值一定要是BizData对象

    使用

    在spring的xml中配置:

    <!-- 初始化框架,并设置用于并行获取业务数据的线程池配置  -->
        <bean class="com.dyz.pget.core.BizDataManager" init-method="init" destroy-method="destroy">
            <property name="corePoolSize" value="12"/>
            <property name="maximumPoolSize" value="200"/>
            <property name="keepAliveTime" value="0"/>
            <property name="queueSize" value="1000"/>
        </bean>

    第一步:自定义BizData对象

    public class UserInfoBizData implements IBizData{
        private Long userId;
        private String name;
        private Integer age;
    
        /**
         * 必须提供默认构造参数
         */
        public UserInfoBizData() {
        }
    
        public UserInfoBizData(Long userId, String name, Integer age) {
            this.userId = userId;
            this.name = name;
            this.age = age;
        }
    
        /**
         * 如果此数据对象获取失败时的默认兜底值。如果不支持兜底,则返回null即可。
         * @return
         */
        @Override
        public IBizData defaultBizData() {
            return null;
        }
    
        @Override
        public String format2String() {
            return new StringBuilder()
                    .append("ID:").append(userId)
                    .append(",名字:").append(name)
                    .append(",年龄:").append(age)
                    .toString();
        }
    }
    //篇幅问题,此处只贴了一个BizData的代码

    第二步:编写对应的BizDataProvider

    @BizDataProvider
    public class TestBizDataProvider {
    
        /**
         * 异常要抛出,框架会捕获
         * @param userId
         * @return
         * @throws Exception
         */
        public UserInfoBizData getUserInfoBizData(long userId)throws Exception{
            //调用远程rpc或者其他数据源得到数据,并封装到Test1BizData对象中
            return new UserInfoBizData(userId,"张三",20);
        }
    
        public ProductInfoBizData getProductInfoBizData(long shopId,long productId)throws Exception{
            //调用远程rpc或者其他数据源得到数据,并封装到ProductInfoBizData对象中
            return new ProductInfoBizData(productId,shopId,"啤酒");
        }
    }

    第三步:获取数据

    ①Getter模式:

    使用案例代码:

      @Test
        public void testGetter() throws BizDataFetchException {
            long userId = 1345L;
            long shopId = 11L;
            long productId = 11011L;
            //并行获取用户信息、商品信息、门店信息三个数据。超时时间是100毫秒
            List<IBizData> bizDataList = BizDataGetter.build()
                    .get(UserInfoBizData.class,userId)
                    .get(ProductInfoBizData.class,shopId,productId)
                    .get(ShopInfoBizData.class,shopId)
                    .doGet(100L);
    
            UserInfoBizData userInfoBizData = (UserInfoBizData)bizDataList.get(0);
            ProductInfoBizData productInfoBizData = (ProductInfoBizData)bizDataList.get(1);
            ShopInfoBizData shopInfoBizData = (ShopInfoBizData)bizDataList.get(2);
    
            System.out.println(userInfoBizData.format2String());
            System.out.println(productInfoBizData.format2String());
            System.out.println(shopInfoBizData.format2String());
        }

    ②Injector模式:

    定义一个数据包裹对象,存放所需要的数据对象

    public class BizDataWrapper {
        private UserInfoBizData userInfoBizData;
        private ShopInfoBizData shopInfoBizData;
        private ProductInfoBizData productInfoBizData;
    
    
        public UserInfoBizData getUserInfoBizData() {
            return userInfoBizData;
        }
    
        public ShopInfoBizData getShopInfoBizData() {
            return shopInfoBizData;
        }
    
        public ProductInfoBizData getProductInfoBizData() {
            return productInfoBizData;
        }
    }

    使用案例代码:

      @Test
       public void testGetter() throws BizDataFetchException {
            long userId = 1345L;
            long shopId = 11L;
            long productId = 11011L;
            BizDataWrapper bizDataWrapper = new BizDataWrapper();
            //并行获取用户信息、商品信息、门店信息三个数据。并注入到bizDataWrapper中,以方便使用。超时时间是100毫秒
            BizDataInjector.build(bizDataWrapper)
                    .inject(UserInfoBizData.class,userId)
                    .inject(ProductInfoBizData.class,shopId,productId)
                    .inject(ShopInfoBizData.class,shopId)
                    .doInject(100L);
            
            System.out.println(bizDataWrapper.getUserInfoBizData().format2String());
            System.out.println(bizDataWrapper.getProductInfoBizData().format2String());
            System.out.println(bizDataWrapper.getShopInfoBizData().format2String());
        }

    结尾

    相信你使用后,一定会觉着简单易用。

    不多说了,贴上github地址:

    注:使用时,没必要把源代码粘到业务系统中,自己打个jar包,让业务系统依赖下就OK了。

  • 相关阅读:
    MVVM CopyValuesTo接触属性上下级关联
    怎样控制WPF GroupBox.HeaderTemplate中的控件
    wpf动态创建DataGrid
    mvvm 绑定textbox焦点丢失问题
    C# 导出CSV文件
    使用C#选择文件夹、打开文件夹、选择文件或者如何使用C#选择文件夹
    EF 强制从数据库刷新集合
    WPF及Silverlight中将DataGrid数据导出
    VS 2005中winForm开发(C#)—图片上传到数据库与显示(sql server 2005)
    数据导出为csv文件时 数值型数据为科学计数法 时间被截取的解决方法
  • 原文地址:https://www.cnblogs.com/metoy/p/12349641.html
Copyright © 2020-2023  润新知