Giter Site home page Giter Site logo

lvyahui8 / spring-boot-data-aggregator Goto Github PK

View Code? Open in Web Editor NEW
177.0 16.0 57.0 620 KB

基于注解实现并行地依赖注入(数据聚合),可以看做 Spring Async 注解的升级版

Home Page: https://github.com/lvyahui8/spring-boot-data-aggregator/wiki/%E5%A6%82%E4%BD%95%E5%BC%80%E5%A7%8B

License: Apache License 2.0

Java 100.00%
data-aggregation spring-boot bean-mapping parallel-processing concurrency

spring-boot-data-aggregator's Introduction

Spring Boot 并行数据聚合库

Build Status Codecov License Maven Central GitHub release

Total alerts Language grade: Java

基于注解实现并行地依赖注入(调用),可以看做 Spring @Async 注解的升级版。

image-20200309230202047

特性

  • 异步获取依赖

    所有 @DataConsumer 定义的依赖将异步获取. 当provider方法参数中的所有依赖获取完成, 才执行provider方法

  • 不限级嵌套

    依赖关系支持深层嵌套. 下面的示例只有一层

  • 异常处理

    目前支持两种处理方式: 忽略or终止

    忽略是指provider方法在执行时, 忽略抛出的异常并return null值; 终止是指一旦有一个provider方法抛出了异常, 将逐级向上抛出, 终止后续处理.

    配置支持consumer级或者全局, 优先级 : consumer级 > 全局

  • 查询缓存

    在调用Facade的query方法的一次查询生命周期内, 方法调用结果可能复用, 只要方法签名以及传参一致, 则默认方法是幂等的, 将直接使用缓存的查询结果. 但这个不是绝对的, 考虑到多线程的特性, 可能有时候不会使用缓存

  • 超时控制

    @DataProvider 注解支持配置timeout, 超时将抛出中断异常 (InterruptedException), 遵循异常处理逻辑

使用方法

1. 配置

pom.xml

<dependency>
  <groupId>io.github.lvyahui8</groupId>
  <artifactId>spring-boot-data-aggregator-starter</artifactId>
  <version>{$LATEST_VERSION}</version>
</dependency>

application.properties

# 指定要扫描注解的包
io.github.lvyahui8.spring.base-packages=io.github.lvyahui8.spring.example

2. 添加注解

  • @DataProvider 定义数据提供者
  • @DataConsumer 定义方法参数依赖类型为其他接口返回值, 其他接口是一个@DataProvider
  • @InvokeParameter 定义方法参数依赖类型为用户输入值

3. 查询

通过 DataFacade.get 静态门面查询指定数据

示例

开发一个用户汇总数据接口, 包括用户的基础信息和博客列表

1. 定义提供基础数据的"原子"服务

使用@DataProvider定义接口为数据提供者

使用@InvokeParameter指定要传递的用户输入参数

博客列表服务

需要参数userId

@Service
public class PostServiceImpl implements PostService {
    @DataProvider("posts")
    @Override
    public List<Post> getPosts(@InvokeParameter("userId") Long userId) {

用户基础信息查询服务

需要参数userId

@Service
public class UserServiceImpl implements UserService {
    @DataProvider("user")
    @Override
    public User get(@InvokeParameter("userId") Long id) {

2. 调用聚合接口

方式一: 函数式调用

注意这里不能将函数式调用改为Lambda表达式, 两者的实际行为是不一致的.

User user = DataFacade.get(
     Collections.singletonMap("userId", 1L), 
     new Function2<User, List<Post>, User>() {
            @Override
            public User apply(@DataConsumer("user") User user, 
                              @DataConsumer("posts") List<Post> posts) {
                user.setPosts(posts);
                return user;
            }
     });
Assert.notNull(user,"User must not be NULL");
Assert.notNull(user.getPosts(),"User's posts must not be NULL");

方式二: 定义聚合层查询

组合@DataProvider \ @DataConsumer \ @InvokeParameter 实现汇聚功能

@Component
public class UserAggregate {
    @DataProvider("userWithPosts")
    public User userWithPosts(
            @DataConsumer("user") User user,
            @DataConsumer("posts") List<Post> posts) {
        user.setPosts(posts);
        return user;
    }
}

指定要查询的data id, 查询参数, 返回值类型, 并调用facade.get方法即可

User user = DataFacade.get(/*data id*/ "userWithPosts",
                            /*Invoke Parameters*/
                            Collections.singletonMap("userId",1L), 
                            User.class);
Assert.notNull(user,"User must not be NULL");
Assert.notNull(user.getPosts(),"User's posts must not be NULL");

运行结果

可以看到, user 和posts是由异步线程执行查询, 而userWithPosts是主调线程执行, 其中

  • 基础user信息查询耗费时间 1000ms
  • 用户博客列表查询耗费时间 1000ms
  • 总的查询时间 1005ms
[aggregateTask-1]  query id: user, costTime: 1000ms, resultType: User,  invokeMethod: UserServiceImpl#get
[aggregateTask-2]  query id: posts, costTime: 1000ms, resultType: List,  invokeMethod: PostServiceImpl#getPosts
[           main]  query id: userWithPosts, costTime: 1010ms, resultType: User,  invokeMethod: UserAggregate#userWithPosts
[           main]  user.name:lvyahui8,user.posts.size:1

贡献者

spring-boot-data-aggregator's People

Contributors

dependabot[bot] avatar lvyahui8 avatar snoopylovefiona avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spring-boot-data-aggregator's Issues

还在维护升级吗

项目想法很赞,的确能解决实际问题,希望作者能继续维护开发,保存活跃

异步线程中的异常被吞

io/github/lvyahui8/spring/aggregate/service/impl/DataBeanAggregateQueryServiceImpl.java:129

 } catch (Exception e) {
            interceptorChain.applyExceptionHandle(context,provider,e);
            return null;
        }

提交查询任务时, 增加线程上下文传递入口.

一次调用会是一个树状结构. 树中的每一个节点都可能被任何异步线程处理.

当由当前线程提交一个子查询任务给线程池时, 提供一个拷贝线程上下文的入口(功能), 并支持执行完之后清理掉上下文.

需要实现此功能的原因是许多业务使用了ThreadLocal来存放上下文.

Exception handling in asynchronous threads

Treatment plan

  • Ignore, asynchronous methods will return NULL values
  • abort, the entire aggregation process is aborted, throwing an exception
  • Retry, temporarily not implemented

Configuration

Globally, to define the default processing scheme

Local, you can control each interface

  • DataConsumer can be configured
  • Priority DataConsumer > Global

处理方案

  • 忽略, 异步方法将返回NULL值
  • 中止, 整个聚合过程中止, 抛出异常
  • 重试, 暂时不实现

配置方案

全局, 要定义默认处理方案

局部, 可以控制每个接口

  • DataConsumer 可以配置
  • 优先级 DataConsumer > 全局

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.