蒙面歌王,萧县天气,雌激素-加半天,停止996,假期多半天,新工作方式的倡导者

admin 4个月前 ( 07-12 03:50 ) 0条评论
摘要: 背景接口开发是后端开发中最常见的场景,可能是RESTFul接口,也可能是RPC接口。用户基础信息@ServicepublicclassUserServiceImplimplemen...

布景

接口开发是后端开发中最常见的场景, 或许是RESTFul接口, 也或许是RPC接口. 接口开发往往是从遍地捞出数据, 然后组装成成果, 特别是那些偏事务的接口.

怎么便当快速的开发高功用的接口, 是一个有必要考虑的问题.

例如, 我现在需求完结一个接口, 拉取用户根底信息+用户的博客列表+用户的粉丝数广州大学数字广阔据的整合数据, 假定现已有如下三个接口能够运用, 别离用来获取 用户根底信息 ,用户博客列表, 用户的粉丝数据.

用户根底信息

@Service
public class UserServiceImpl implements UserService {
@Override
public User get(Long id) {
try {Thread.sleep(1000L);} catch (InterruptedException e) {}
/* mock a user*/
User user = new User();
user.setId(id);
user.setEmail("lvyahui8@gmail.com");
user.setUsername("lvyahui8");
return user;
}
}

用户博客列表

@Service
public class PostServiceImpl implements 蒙面歌王,萧县气候,雌激素-加半响,中止996,假日多半响,新工作办法的倡导者PostService {
@Override
public List getPosts(Long userId) {
try { Thread.sleep(1000L); } catch (InterruptedException e) {}
Post post = new Post();
post.setTitle("spring data aggregate example");
post.setContent("No active profile set, falling back to default profiles");
return Collections.singletonList(post);
}
}

用户的粉丝数据

@Service
public class FollowServiceImpl implements FollowService {
@Override
public List getFollowers(Long userId) {
try { Thread.sleep(1000L); } catch (InterruptedException e) {}
int蒙面歌王,萧县气候,雌激素-加半响,中止996,假日多半响,新工作办法的倡导者 siz盛世天龙e = 10;
List users = new山东制作移动养蜂车 ArrayList<>(size);
for(int i = 0 ; i < size; i++) {
User user = new User(蒙面歌王,萧县气候,雌激素-加半响,中止996,假日多半响,新工作办法的倡导者);
user.setUsername("name"+i);
user.setEmail("email"+i+"@fox.com");
user.setId((long) i);
users.add(user);
};
return users;
}
}

留意, 每一个办法都sleep了1s以模仿事务耗时.

咱们需求再封装一个接口, 来组装以上三个接口的数据.

PS: 这样的场景实践在工作中很常见, 并且往往咱们需求凑集的数据, 是要走网络恳求调到第三方去的. 别的或许有人会想, 为何不分红3个恳求? 实践为了客户端网络功用考虑, 往往会在一次网络恳求中, 尽或许多的传输数据, 当然条件是这个数据不能太大, 不然传输的耗时会影响烘托. 蒙面歌王,萧县气候,雌激素-加半响,中止996,假日多半响,新工作办法的倡导者许多APP的主页, 看着杂乱, 实践也只要一个接口334eee, 一次性拉下一切数据, 客户端开发也简略.

串行完结

编写功用优秀的接口不仅是每一位后端程序员的技能寻求, 也是事务的根本诉求. 一般情况下, 为了确保更好的功用, 往往需求编写更杂乱的代码完结.

但俗人皆有慵懒, 因而, 往往咱们会像下面这样编写串行调用的代码

@Component
public class UserQueryFacade {
@Autowired
private FollowService followService;
@Autowired
private PostService postService;
@Autowired
private UserService userService;

public User getUserData(Long userId) {
User user = userService.get(userId);
user.setPosts(postService.getPosts(userId));
user.setFollowers(followService.getFollowers(userId));
return user;
}
}

很明显, 上面的代码, 功率低下, 最少要3s才干拿到成果, 且一旦用到某个接口的数据, 便需求注入相应的service, 复用费事.

并行完结

有寻求的程序员或许立马会考虑到, 这几项数据之间并无强依靠性, 完全能够并行获取嘛, 经过异步影霜碎片线程+CountDownLatch+Future完结, 就像下面这样.

@Component
public class UserQueryFacade {
@Autowired
private FollowService f我的钻石人生ollowService;
@Autowired蒙面歌王,萧县气候,雌激素-加半响,中止996,假日多半响,新工作办法的倡导者
private PostService postService;
@Autowired
private UserService userService;

public User getUserDataByParallel(Long userId) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
CountDownLatch countDownLatch = new CountDownLatch(3);
Future userFuture = executorService.submit(() -> {
try{
return userService.get(userId);
}fi陈子豪戳穿魄狙nally {
countDownLatch.countDown();
}
});
Future> postsFuture = executorService.submit(() -> {
try{
return postService.getPosts(userId);
}finally {
countDownLatch.countDown();
}
});
Future> followersF宁波天唯艺术酒店uture = executorService.submit(() -> {
try{
return followService.getFollowers(userId);
}finally {
countDownLatch.countDown();
}
});
countDownLatch.await();
User user = userFuture.get();
user.setFollowers(followersFuture.get());
蒙面歌王,萧县气候,雌激素-加半响,中止996,假日多半响,新工作办法的倡导者user.setPosts(postsFuture.get());
return user;
}
}

上面的代码, 将串行调用改为并行调用, 在有限并发级别下, 能极大进步功用. 但很明显, 它过于杂乱, 假如每个接口都为了并行履行都写这样一段代码, 简直是噩梦.

高雅的注解完结

了解java的都知道, java有一种十分便当的特性 ~~ 注解. 简直是黑魔法. 往往只需求给类或许办法上增加一些注解, 便能够完结十分杂乱的功用.

有了注解, 再结合Spring依靠主动注入的思维, 那么咱们可不能够经过注解的办法, 主动注入依靠, 主动并行调用接口呢? 答案是必定的.

首要养女小说, 咱们先界说一个聚合接口 (当然也能够不界说聚合类, 一切代码写在原Service类中相同能够)

@Component
public class UserAggregate {
@DataProvider("userFullData")
public User userFullData(@DataConsumer("user") User user,
@DataConsumer金艺贞("posts") List posts,
@DataConsumer("followers") List follo福利区wers) {
user.setFollowers(followers);
user.setPosts(posts);
return user;
}
}

其间

  • @DataProvider 表明这个办法是一个数据提供者, 数据Id为 userFullData
  • @DataCon达瓦里希是什么梗sumer 表明这个办法的参数, 需求消费数据, 数据Id别离为 user ,posts, followers.

当然, 本来的3个原子服务 用户根底信息 ,用户博客列表, 用户的粉丝数据, 也别离需求增加一些注解

@Service
public class UserServiceImpl implements UserService {
@DataProvider("user")
@Override
public User get(@InvokeParameter("userId") Long id) {
@Service
public class PostServiceImpl implements PostSer婚外性vice {
@DataProvider("posts")
@Override
public List getPosts(@InvokeParameter("userId") Long userId) {
@Service
public class FollowServiceImpl implements FollowService {
@DataProvid蒙面歌王,萧县气候,雌激素-加半响,中止996,假日多半响,新工作办法的倡导者er("followers")
@Override
public List getFollowers(@InvokeParameter("userId") Long userId) {

其间

  • @DataProvider 与前面的意义相同, 表明这个办法是一个数据提供者
  • @InvokeParameter 表明办法履行时, 需求手动传入的参数

这儿留意 @InvokeParameter 和 @DataCons易信网页版umer的差异, 前者需求用户在最上层调用时手动传参; 而后者, 是由结构主动剖析依靠, 并异步调用获得成果之后注入的.

最终, 只是只需求调用一个一致的门面(Facade)接口, 传递数据Id, Invoke Parameters,以及返回值类型. 剩余的并行处理, 依靠剖析和注入, 完全由结构主动处理.

@Component
public class UserQueryFacade {
@Autowired
private DataBeanAggregateQueryFacade dataBeanAggregateQueryFacade;
public User getUserFinal(Long userId) throws InterruptedException,
IllegalAccessException, InvocationTargetException {
return dataBeanAggregateQueryFacade.get("userFullData",
Collections.singletonMap("userId", userId), User.class);
}
}

怎么用在你的项目中

上面的功用, 笔者现已封装为一个spring boot starter, 并发布到maven中心库房.

只需在你的项目引进依靠.


io.github.lvyahui8
spring-boot-data-aggregator-starter
1.0.2

并在 application.properties 文件中声明注解的扫描途径.

# 替换成你需求扫描注解的包
io.github.lvyahui8.spring.base-packages=io.github.lvyahui8.spring.example

之后, 就能够运用如下注解和 Spring Bean 完结聚合查询

  • @DataProvider
  • @DataConsumer
  • @InvokeParameter
  • Spring Bean DataBeanAggregateQueryFacade

留意, @DataConsumer 和 @InvokeParameter 能够混合运用, 能够用在同一个办法的不同参数上. 且办法的一切参数有必要有其间一个注解, 不能有没有注解的参数.

特性

  • 异步获取依靠
  • 一切 @DataConsumer 界说的依靠将异步获取. 当provider办法参数中的一切依靠获取完结, 才履行provider方鬼炎佩剑法
  • 不限级嵌套
  • 依靠联系赖俊健支撑深层嵌套. 上面的示例只要一层女子步行街裸舞
  • 反常处理
  • 现在支撑两种处理办法: 疏忽or停止
  • 疏忽是指provider办法在履行时, 疏忽抛出的反常并return null值; 停止是指一旦有一个provider办法抛出了反常, 将逐级向上祼体抛出, 停止后续处理.
  • 装备支撑consumer级或许大局, 优先级 : consumer级 > 大局
  • 超时操控 (待完结)

后期方案

后续小编将持续完善 #超时处理,#缓存,#进步吞吐量 并进一步进步插件的易用性奥特森, 高可用性, 扩展性。

文章版权及转载声明:

作者:admin本文地址:http://i-mediaplus.com/articles/2280.html发布于 4个月前 ( 07-12 03:50 )
文章转载或复制请以超链接形式并注明出处加半天,停止996,假期多半天,新工作方式的倡导者