spring-boot-data-aggregator Spring Boot Data Bean 开源项目

我要开发同款
匿名用户2019年06月10日
39阅读
开发技术Java
所属分类其他
授权协议Apache

作品详情

背景与目的

在开发后台接口时,为了开发效率,我们往往习惯编写串行执行的代码,去调用不同的接口,即使这些接口之间并无依赖,这使得最后开发的接口性能低下,且数据不方便复用

此框架目的旨在保持开发效率的同时,很方便地支持并发和数据复用

当然,在极端高并发的场景下,并行调用接口对性能提升并不明显,但不代表这个项目没有价值.因为互联网世界的大部分应用,并不会有非常高的并发访问量

原理CountDownLatch+Future+递归为了得到目标数据,会递归分析并获取数据做需要的依赖项, 数据的依赖项有两种:其他接口返回值或者输入参数,前一种需要调用其他接口,这个调用将封装为任务异步执行并获取结果特性

异步获取依赖

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

不限级嵌套

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

异常处理

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

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

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

查询缓存

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

超时控制

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

使用方法

pom.xml

<dependency><groupId>io.github.lvyahui8</groupId><artifactId>spring-boot-data-aggregator-starter</artifactId><version>1.0.2</version></dependency>

application.properties

#指定要扫描注解的包io.github.lvyahui8.spring.base-packages=io.github.lvyahui8.spring.example@DataProvider 定义数据提供者@DataConsumer 定义方法参数依赖类型为其他接口返回值,其他接口是一个@DataProvider@InvokeParameter 定义方法参数依赖类型为用户输入值SpringBean DataBeanAggregateQueryFacade 查询指定的数据的门面示例

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

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

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

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

博客列表服务

需要参数userId

@ServicepublicclassPostServiceImplimplementsPostService{@DataProvider("posts")@OverridepublicList<Post>getPosts(@InvokeParameter("userId")LonguserId){try{Thread.sleep(1000L);}catch(InterruptedExceptione){//}Postpost=newPost();post.setTitle("springdataaggregateexample");post.setContent("Noactiveprofileset,fallingbacktodefaultprofiles");returnCollections.singletonList(post);}}

用户基础信息查询服务

需要参数userId

@ServicepublicclassUserServiceImplimplementsUserService{@DataProvider("user")@OverridepublicUserget(@InvokeParameter("userId")Longid){/**/try{Thread.sleep(100L);}catch(InterruptedExceptione){//}/*mockauser*/Useruser=newUser();user.setId(id);user.setEmail("lvyahui8@gmail.com");user.setUsername("lvyahui8");returnuser;}}2.定义并实现聚合层

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

@ComponentpublicclassUserAggregate{@DataProvider("userWithPosts")publicUseruserWithPosts(@DataConsumer("user")Useruser,@DataConsumer("posts")List<Post>posts){user.setPosts(posts);returnuser;}}3.调用聚合层接口

注解了@DataProvider方法的接口不需要直接调用,而是通过门面类DataBeanAggregateQueryFacade访问.

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

DataBeanAggregateQueryFacadequeryFacade=context.getBean(DataBeanAggregateQueryFacade.class);Useruser=queryFacade.get(/*dataid*/"userWithPosts",/*InvokeParameters*/Collections.singletonMap("userId",1L),User.class);Assert.notNull(user,"usernotnull");Assert.notNull(user.getPosts(),"userpostsnotnull");

运行结果

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

基础user信息查询耗费时间1000ms用户博客列表查询耗费时间1000ms总的查询时间1005ms[aggregateTask-1]queryid:user,costTime:1000ms,resultType:User,invokeMethod:UserServiceImpl#get[aggregateTask-2]queryid:posts,costTime:1000ms,resultType:List,invokeMethod:PostServiceImpl#getPosts[main]queryid:userWithPosts,costTime:1010ms,resultType:User,invokeMethod:UserAggregate#userWithPosts[main]user.name:lvyahui8,user.posts.size:1
声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!
下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态

评论