数据聚合

1.问题

微服务的难点:

微服务将单体服务中功能模块按性能拆分成多个微服务项目,已达到性能解耦的目标。但,因为拆分性能同时会将数据存储也进行拆分(甚至有的时候不同的微服务底层应用的数据长久化计划不同,比方:Mysql,MongoDB等),前端申请数据时可能存证跨服务数据返回。

例:

微服务:订单服务,用户服务,CRM服务

前端申请订单数据须要蕴含订单数据(订单服务),订单负责人信息(用户服务),客户信息(CRM服务)。

2.解决方案:

前端解决

前端申请数据后,依据数据再别离申请其余服务。

例如:

  1. 申请订单数据
  2. 依据订单数据中的负责人id,申请用户服务数据
  3. 依据订单数据中的客户数据,申请CRM服务数据

毛病:

  • 减少前端工作量
  • 减少响应工夫。
后端解决

在服务中调用其余服务将数据补全,而后返回到前端

例如:

  1. 订单服务查询数据库失去订单数据
  2. 依据订单数据中的负责人id,申请用户服务数据
  3. 依据订单数据中的客户数据,申请CRM服务数据
  4. 返回数据

毛病:

  • 减少后端工作量
BFF数据聚合(本我的项目采纳的解决方案)

在前后端两头减少BFF数据聚合服务。

3.数据聚合

3.1数据聚合过程

sequenceDiagram前端->>gateway:申请订单数据gateway->>聚合服务:申请订单数据聚合服务->>订单服务:申请订单数据订单服务->>聚合服务:返回订单数据聚合服务->>用户服务:申请负责人数据用户服务->>聚合服务:返回负责人数据聚合服务->>CRM服务:申请客户数据CRM服务->>聚合服务:返回客户数据聚合服务->>gateway:返回订单数据(数据聚合后)gateway->>前端:返回订单数据(数据聚合后)

3.2注解:

Aggregation
  • 应用在办法上,只能应用在Web响应办法上,示意该办法供数据聚合调用返回聚合数据
  • 应用在汇合属性上,配合AggregationParam应用
  • 应用在类上,示意类须要在聚合服务中聚合数据
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Aggregation {    /**     * 参数     * @return     */    AggregationParam[] params() default {};}

AggregationParam

配合Aggregation的属性上应用

public @interface AggregationParam {    /**     * 查问参数名     * @return     */    String name();    /**     * 查问参数援用或者常量值     * @return     */    String value();    /**     * 是否是常量     * @return     */    boolean constant() default false;}
  • name 参数名,与聚合服务提供接口的参数统一
  • value 取值

    • 如果constant为true,则为字面值
    • 如果constant为false,则应用以后对象的名字为value属性值

例如:

需要侧:

public class DepartmentDetail{    private String id; // 假如id值为D0001    private String name;    /** departmentId为服务提供接口的参数     *  因为constant为false     *  value为id,则调用服务提供接口时,参数为departmentId=D0001     */    @Aggregation(params={@AggregationParam(name="departmentId",value="id")})    private List<UserAggregation> members;}

提供侧:

@Aggregationpublic class UserAggregation {    private String id; // id须要和UserAggregationController的PathVariable对应    private String name;    // 省略getter setter}@RestController@RequestMapping("aggregation/users")public class UserAggregationController {    @Aggregation    @GetMapping()    public List<UserAggregation> getAggregation(        @RequestParam("departmentId")String departmentId){        // 返回UserAggregation数组    }}

留神

如果是非空集合则不须要应用@Aggregation

例如:

@Aggregationpublic class UserAggregation {    private String id; // id须要和UserAggregationController的PathVariable对应    private String name;    // 省略getter setter constructure}@RestController@RequestMapping("aggregation/users")public class UserAggregationController {    @Aggregation    @GetMapping("{id}")    public UserAggregation getAggregation(@PathVariable("id")String id){        // 省略返回UserAggregation    }}public class DepartmentDetail{    private String id; // 假如id值为D0001    private String name;    // members在逻辑中会被增加元素,不须要应用@Aggregation    // 会调用GET /aggregation/users/{id}    private List<UserAggregation> members;}@RestController@RequestMapping("departments")public class DepartmentController{    @GetMapping("{id}")    public DepartmentDetail getDepartment(@PathVariable("id")String id){        DepartmentDetail detail = new DepartmentDetail();        List<UserAggregation> list = new ArrayList<>();        list.add(new UserAggregation('U01'));        list.add(new UserAggregation('U02'));        list.add(new UserAggregation('U03'));        detail.setMemebers(list);        return detail;    }}

3.3实现

wy-aggregation-service

实现应用的是Egg框架(node.js)。node 对于IO有好性能。同时,因为js是弱类型语言,更容易对json数据处理。

3.4示例

用户服务

@Aggregationpublic class UserAggregation {    private String id; // id须要和UserAggregationController的PathVariable对应    private String name;    // 省略getter setter}@RestController@RequestMapping("aggregation/users")public class UserAggregationController {    @Aggregation    @GetMapping("{id}")    public UserAggregation getAggregation(@PathVariable("id")String id){        // 省略返回UserAggregation    }    @Aggregation    @GetMapping()    public List<UserAggregation> getAggregation(        @RequestParam("departmentId")String departmentId){        // 返回UserAggregation数组    }}

CRM服务

@Aggregationpublic class ClientAggregation {    private String id;    private String name;    // 省略getter setter}@RestController@RequestMapping("aggregation/cleints")public class CleintAggregationController {    @Aggregation    @GetMapping("{id}")    public ClientAggregation getAggregation(@PathVariable("id")String id){        // 省略返回ClientAggregation    }}

订单服务

public class Order{    private String id;    private String code;    private UserAggregation admin; // 负责人    private CleintAggregation client; // 客户    // 省略getter setter}@RestController@RequestMapping("orders")public class OrderController {    @GetMapping("{id}")    public Order getOne(@PathVariable("id")String id){        Order order = new Order();        order.setAdmin(new UserAggregation('adminId'));// 须要设置adminId        order.setClient(new ClientAggregation('clientId'));//须要设置clientId        return order;    }}

4.代码

https://gitee.com/wenyu7980/w...
https://gitee.com/wenyu7980/w...