Skip to content

Commit 0d66fdd

Browse files
committed
optimize document
1 parent 9a4ad2e commit 0d66fdd

File tree

2 files changed

+223
-87
lines changed

2 files changed

+223
-87
lines changed

README.md

Lines changed: 89 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,133 @@
1-
# Spring Boot Data Bean 并发聚合支持
1+
# Spring Boot Data Bean Parallel Aggregation Support
22

3-
## 背景
3+
## Background and purpose
44

5-
**后台接口在调用一些接口时, 为了写代码方便, 多数时候我们习惯串行调用, 即使这些接口调用并无依赖性.**
5+
When developing the background interface, in order to improve the development efficiency, we often write serial execution codes to call different interfaces, even if there is no dependency among these interfaces, which causes the last developed interface performance is low, and the data is not convenient to reuse.
66

7-
**此框架目的旨在保持开发的简便性, 并同时很方便地支持并发和数据复用**
7+
**This framework is designed to support parallel and data reuse while maintaining the development efficiency.**
88

9-
## 原理
9+
Of course, in an extremely high concurrent scenario, the parallel call interface is not that helpful for performance improvement. However, it doesn't mean that this project is meaningless because most applications in the Internet don't have very high concurrent traffic.
1010

11-
1. CountDownLatch + Future
12-
2. 目标参数依赖中, 需要查询接口获取的数据, 封装为一个任务交给线程池处理, 处理完成之后, 再统一目标方法
11+
## Principle
1312

14-
## 使用方法
13+
1. CountDownLatch + Future + Recursion
14+
2. In order to get the target data, it will recursively analyze and obtain the dependencies required by the data. **There are two kinds of dependencies; one is other interface return value, the other is input parameter. The former needs to call other interfaces, this call will be packed as a task which is an asynchronous execution to get the result.**
1515

16-
- DataBeanProvider 定义数据model提供者
17-
- DataBeanConsumer 定义方法将要消费的model
18-
- InvokeParameter 指定用户手动传入的参数
19-
- DataBeanAggregateQueryFacade 查询指定的model
16+
## Instruction
2017

21-
## 示例
18+
- `@DataProvider`: define the data provider
19+
- `@DataConsumer`: define the method parameter dependency type as return the value of other interfaces, the other interface is a @DataProvider
20+
- `@InvokeParameter`: define the method parameter dependency type as the user input value
21+
- Spring Bean `dataBeanAggregateQueryFacade`: query data facade API
2222

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

25-
**1. 定义提供基础数据的"原子"服务**
25+
Developing a user summary data interface that includes the user's basic information and blog list.
2626

27-
使用DataBeanProvider定义要提供的数据, 使用InvokeParameter指定查询时要传递的参数
27+
### 1. Define an "atomic" service to provide user data
2828

29-
博客列表服务, 需要参数userId
29+
Use `@DataProvider` to define the interface a data provider.
30+
31+
Use `@InvokeParameter` to specify the input parameters to pass.
32+
33+
**Blog list service**
34+
35+
require input parameter `userId`.
3036

3137
```java
3238
@Service
33-
public class PostServiceImpl implements PostService {
34-
@DataBeanProvider(id = "posts")
35-
@Override
36-
public List<Post> getPosts(@InvokeParameter("userId") Long userId) {
37-
try {
38-
Thread.sleep(1000L);
39-
} catch (InterruptedException e) {
40-
//
41-
}
42-
Post post = new Post();
43-
post.setTitle("spring data aggregate example");
44-
post.setContent("No active profile set, falling back to default profiles");
45-
return Collections.singletonList(post);
46-
}
39+
Public class PostServiceImpl implements PostService {
40+
    @DataProvider(id = "posts")
41+
    @Override
42+
    Public List<Post> getPosts(@InvokeParameter("userId") Long userId) {
43+
        Try {
44+
            Thread.sleep(1000L);
45+
        } catch (InterruptedException e) {
46+
        }
47+
        Post post = new Post();
48+
        post.setTitle("spring data aggregate example");
49+
        post.setContent("No active profile set, falling back to default profiles");
50+
        Return Collections.singletonList(post);
51+
    }
4752
}
48-
4953
```
5054

51-
用户基础信息查询服务, 需要参数userId
55+
**User basic information query service**
56+
57+
require input parameter `userId`.
5258

5359
```java
5460
@Service
55-
public class UserServiceImpl implements UserService {
56-
57-
@DataBeanProvider(id = "user")
58-
@Override
59-
public User get(@InvokeParameter("userId") Long id) {
60-
/* */
61-
try {
62-
Thread.sleep(100L);
63-
} catch (InterruptedException e) {
64-
//
65-
}
66-
/* mock a user*/
67-
User user = new User();
68-
user.setId(id);
69-
user.setEmail("[email protected]");
70-
user.setUsername("lvyahui8");
71-
return user;
72-
}
61+
Public class UserServiceImpl implements UserService {
62+
63+
    @DataProvider(id = "user")
64+
    @Override
65+
    Public User get(@InvokeParameter("userId") Long id) {
66+
        /* */
67+
        Try {
68+
            Thread.sleep(100L);
69+
        } catch (InterruptedException e) {
70+
        }
71+
        /* mock a user*/
72+
        User user = new User();
73+
        user.setId(id);
74+
        user.setEmail("[email protected]");
75+
        user.setUsername("lvyahui8");
76+
        Return user;
77+
    }
7378
}
7479
```
7580

76-
**2. 定义并实现聚合层**
81+
### 2. Define and implement an aggregation layer
7782

78-
组合DataBeanProvider\DataBeanConsumer\InvokeParameter实现汇聚功能
83+
Combine `@DataProvider` ( `@DataConsumer` \ `@InvokeParameter` ) to achieve aggregation function
7984

8085
```java
8186
@Component
82-
public class UserAggregate {
83-
@DataBeanProvider(id="userWithPosts")
84-
public User userWithPosts(
85-
@DataBeanConsumer(id = "user") User user,
86-
@DataBeanConsumer(id = "posts") List<Post> posts) {
87-
user.setPosts(posts);
88-
return user;
89-
}
87+
Public class UserAggregate {
88+
    @DataProvider(id="userWithPosts")
89+
    Public User userWithPosts(
90+
            @DataConsumer(id = "user") User user,
91+
            @DataConsumer(id = "posts") List<Post> posts) {
92+
        user.setPosts(posts);
93+
        Return user;
94+
    }
9095
}
9196
```
9297

93-
**3. 调用聚合层接口**
98+
### 3. Call the aggregation layer interface
9499

95-
注解了DataBeanProvider方法的接口都不能直接调用, 而需要通过门面类DataBeanAggregateQueryFacade访问.
100+
Note that the interface of the `@DataProvider` method shouldn't to be called directly, but accessed through the facade class `DataBeanAggregateQueryFacade`.
96101

97-
指定要查询的DataBeanProvider.id, 查询参数, 返回值类型即可
102+
Specify queried data id, invoke parameters, and return type to invoke `facade.get` method
98103

99104
```java
100-
@SpringBootApplication
101-
public class ExampleApplication {
102-
public static void main(String[] args) throws Exception {
103-
ConfigurableApplicationContext context = SpringApplication.run(ExampleApplication.class);
104-
DataBeanAggregateQueryFacade queryFacade = context.getBean(DataBeanAggregateQueryFacade.class);
105-
User user = queryFacade.get("userWithPosts", Collections.singletonMap("userId",1L), User.class);
106-
Assert.notNull(user,"user not null");
107-
Assert.notNull(user.getPosts(),"user posts not null");
108-
System.out.println(user);
109-
}
110-
}
105+
DataBeanAggregateQueryFacade queryFacade = context.getBean(DataBeanAggregateQueryFacade.class);
106+
User user = queryFacade.get(/*data id*/ "userWithPosts",
107+
                            /*Invoke Parameters*/
108+
                            Collections.singletonMap("userId",1L),
109+
                            User.class);
110+
Assert.notNull(user,"user not null");
111+
Assert.notNull(user.getPosts(),"user posts not null");
111112
```
112113

113-
**运行结果**
114+
**Invoke result**
114115

115-
可以看到, user 和posts是由异步线程进行的查询, 而userWithPosts是主调线程
116+
As you can see, `user` interface and `posts` interface are executed by the asynchronous thread while `userWithPosts` service is executed by the calling thread.
116117

117-
其中
118-
119-
- 基础user信息查询时间 1000ms
120-
- 用户博客列表查询时间 1000ms
121-
- **总的查询时间 1005ms**
118+
- Basic user information query takes 1000ms
119+
- User blog list query takes 1000ms
120+
- **Total query takes 1005ms**
122121

123122
```
124-
2019-06-03 23:56:52.254 INFO 9088 --- [aggregateTask-2] f.s.a.s.DataBeanAgregateQueryServiceImpl : query id: posts, costTime: 1000ms, model: List, params: 1
125-
2019-06-03 23:56:52.254 INFO 9088 --- [aggregateTask-1] f.s.a.s.DataBeanAgregateQueryServiceImpl : query id: user, costTime: 1000ms, model: User, params: 1
126-
2019-06-03 23:56:52.255 INFO 9088 --- [ main] f.s.a.s.DataBeanAgregateQueryServiceImpl : query id: userWithPosts, costTime: 1005ms, model: User, params: User...........
123+
[aggregateTask-1] query id: user, costTime: 1000ms, resultType: User, invokeMethod: UserServiceImpl#get
124+
[aggregateTask-2] query id: posts, costTime: 1000ms, resultType: List, invokeMethod: PostServiceImpl#getPosts
125+
[ main ] query id: userWithPosts, costTime: 1010ms, resultType: User, invokeMethod: UserAggregate#userWithPosts
126+
[ main] user.name:lvyahui8,user.posts.size:1
127127
```
128128

129-
## 作者
129+
## Contributors
130+
131+
130132

131-
133+
- Iris G

README_CN.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Spring Boot Data Bean 并发聚合支持
2+
3+
## 背景与目的
4+
5+
在开发后台接口时, 为了开发效率, 我们往往习惯编写串行执行的代码, 去调用不同的接口, 即使这些接口之间并无依赖, 这使得最后开发的接口性能低下, 且数据不方便复用
6+
7+
**此框架目的旨在保持开发效率的同时, 很方便地支持并发和数据复用**
8+
9+
当然, 在极端高并发的场景下, 并行调用接口对性能提升并不明显, 但不代表这个项目没有价值. 因为互联网世界的大部分应用, 并不会有非常高的并发访问量
10+
11+
## 原理
12+
13+
1. CountDownLatch + Future + 递归
14+
2. 为了得到目标数据, 会递归分析并获取数据做需要的依赖项, **数据的依赖项有两种: 其他接口返回值或者输入参数, 前一种需要调用其他接口, 这个调用将封装为任务异步执行并获取结果**
15+
16+
## 使用方法
17+
18+
- `@DataProvider` 定义数据提供者
19+
- `@DataConsumer` 定义方法参数依赖类型为其他接口返回值, 其他接口是一个`@DataProvider`
20+
- `@InvokeParameter` 定义方法参数依赖类型为用户输入值
21+
- Spring Bean `DataBeanAggregateQueryFacade` 查询指定的数据的门面
22+
23+
## 示例
24+
25+
开发一个用户汇总数据接口, 包括用户的基础信息和博客列表
26+
27+
### 1. 定义提供基础数据的"原子"服务
28+
29+
使用`@DataProvider`定义接口为数据提供者
30+
31+
使用`@InvokeParameter`指定要传递的用户输入参数
32+
33+
**博客列表服务**
34+
35+
需要参数`userId`
36+
37+
```java
38+
@Service
39+
public class PostServiceImpl implements PostService {
40+
@DataProvider(id = "posts")
41+
@Override
42+
public List<Post> getPosts(@InvokeParameter("userId") Long userId) {
43+
try {
44+
Thread.sleep(1000L);
45+
} catch (InterruptedException e) {
46+
//
47+
}
48+
Post post = new Post();
49+
post.setTitle("spring data aggregate example");
50+
post.setContent("No active profile set, falling back to default profiles");
51+
return Collections.singletonList(post);
52+
}
53+
}
54+
```
55+
56+
**用户基础信息查询服务**
57+
58+
需要参数`userId`
59+
60+
```java
61+
@Service
62+
public class UserServiceImpl implements UserService {
63+
64+
@DataProvider(id = "user")
65+
@Override
66+
public User get(@InvokeParameter("userId") Long id) {
67+
/* */
68+
try {
69+
Thread.sleep(100L);
70+
} catch (InterruptedException e) {
71+
//
72+
}
73+
/* mock a user*/
74+
User user = new User();
75+
user.setId(id);
76+
user.setEmail("[email protected]");
77+
user.setUsername("lvyahui8");
78+
return user;
79+
}
80+
}
81+
```
82+
83+
### 2. 定义并实现聚合层
84+
85+
组合`@DataProvider` \ `@DataConsumer` \ `@InvokeParameter` 实现汇聚功能
86+
87+
```java
88+
@Component
89+
public class UserAggregate {
90+
@DataProvider(id="userWithPosts")
91+
public User userWithPosts(
92+
@DataConsumer(id = "user") User user,
93+
@DataConsumer(id = "posts") List<Post> posts) {
94+
user.setPosts(posts);
95+
return user;
96+
}
97+
}
98+
```
99+
100+
### 3. 调用聚合层接口
101+
102+
注解了`@DataProvider`方法的接口不需要直接调用, 而是通过门面类`DataBeanAggregateQueryFacade`访问.
103+
104+
指定要查询的data id, 查询参数, 返回值类型, 并调用`facade.get`方法即可
105+
106+
```java
107+
DataBeanAggregateQueryFacade queryFacade = context.getBean(DataBeanAggregateQueryFacade.class);
108+
User user = queryFacade.get(/*data id*/ "userWithPosts",
109+
/*Invoke Parameters*/
110+
Collections.singletonMap("userId",1L),
111+
User.class);
112+
Assert.notNull(user,"user not null");
113+
Assert.notNull(user.getPosts(),"user posts not null");
114+
```
115+
116+
**运行结果**
117+
118+
可以看到, user 和posts是由异步线程执行查询, 而userWithPosts是主调线程执行, 其中
119+
120+
- 基础user信息查询耗费时间 1000ms
121+
- 用户博客列表查询耗费时间 1000ms
122+
- **总的查询时间 1005ms**
123+
124+
```
125+
[aggregateTask-1] query id: user, costTime: 1000ms, resultType: User, invokeMethod: UserServiceImpl#get
126+
[aggregateTask-2] query id: posts, costTime: 1000ms, resultType: List, invokeMethod: PostServiceImpl#getPosts
127+
[ main] query id: userWithPosts, costTime: 1010ms, resultType: User, invokeMethod: UserAggregate#userWithPosts
128+
[ main] user.name:lvyahui8,user.posts.size:1
129+
```
130+
131+
## 贡献者
132+
133+
134+
- Iris G

0 commit comments

Comments
 (0)