Skip to content

Commit 2a3ff12

Browse files
committed
update readme
1 parent 3f083ec commit 2a3ff12

File tree

3 files changed

+292
-229
lines changed

3 files changed

+292
-229
lines changed

README.md

Lines changed: 108 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,46 @@
1-
# Spring Boot Data Bean Parallel Aggregation Support
1+
# Spring Boot 并发数据聚合库
22

3-
[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.lvyahui8/spring-boot-data-aggregator-starter/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.lvyahui8/spring-boot-data-aggregator-starter)
3+
[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
4+
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.lvyahui8/spring-boot-data-aggregator-starter/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.lvyahui8/spring-boot-data-aggregator-starter)
5+
[![GitHub release](https://img.shields.io/github/release/lvyahui8/spring-boot-data-aggregator.svg)](https://github.com/lvyahui8/spring-boot-data-aggregator/releases)
46

5-
## Background and purpose
7+
## 背景与目的
68

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

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

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

13-
## Principle
15+
## 特性
1416

15-
1. CountDownLatch + Future + Recursion
16-
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.**
17+
- **异步获取依赖**
1718

18-
## Instruction
19+
所有 `@DataConsumer` 定义的依赖将异步获取. 当provider方法参数中的所有依赖获取完成, 才执行provider方法
20+
21+
- **不限级嵌套**
22+
23+
依赖关系支持深层嵌套. 下面的示例只有一层
24+
25+
- **异常处理**
26+
27+
目前支持两种处理方式: 忽略or终止
28+
29+
忽略是指provider方法在执行时, 忽略抛出的异常并return null值; 终止是指一旦有一个provider方法抛出了异常, 将逐级向上抛出, 终止后续处理.
30+
31+
配置支持consumer级或者全局, 优先级 : consumer级 > 全局
32+
33+
- **查询缓存**
34+
35+
在调用Facade的query方法的一次查询生命周期内, **方法调用结果可能复用, 只要方法签名以及传参一致, 则默认方法是幂等的, 将直接使用缓存的查询结果.** 但这个不是绝对的, 考虑到多线程的特性, 可能有时候不会使用缓存
36+
37+
- **超时控制**
38+
39+
`@DataProvider` 注解支持配置timeout, 超时将抛出中断异常 (InterruptedException), 遵循异常处理逻辑
40+
41+
## 使用方法
42+
43+
### 配置
1944

2045
pom.xml
2146

@@ -30,122 +55,129 @@ pom.xml
3055
application.properties
3156

3257
```
33-
# Specify the package to scan the annotations
58+
# 指定要扫描注解的包
3459
io.github.lvyahui8.spring.base-packages=io.github.lvyahui8.spring.example
3560
```
3661

37-
- `@DataProvider`: define the data provider
38-
- `@DataConsumer`: define the method parameter dependency type as return the value of other interfaces, the other interface is a `@DataProvider`
39-
- `@InvokeParameter`: define the method parameter dependency type as the user input value
40-
- Spring Bean `dataBeanAggregateQueryFacade`: query data facade API
62+
### 添加注解
4163

42-
## Example
64+
- `@DataProvider` 定义数据提供者
65+
- `@DataConsumer` 定义方法参数依赖类型为其他接口返回值, 其他接口是一个`@DataProvider`
66+
- `@InvokeParameter` 定义方法参数依赖类型为用户输入值
4367

44-
Developing a user summary data interface that includes the user's basic information and blog list.
68+
### 查询
4569

46-
### 1. Define an "atomic" service to provide user data
70+
Spring Bean `DataBeanAggregateQueryFacade` 查询指定的数据的门面
4771

48-
Use `@DataProvider` to define the interface a data provider.
72+
## 示例
4973

50-
Use `@InvokeParameter` to specify the input parameters to pass.
74+
开发一个用户汇总数据接口, 包括用户的基础信息和博客列表
5175

52-
**Blog list service**
76+
### 1. 定义提供基础数据的"原子"服务
5377

54-
require input parameter `userId`.
78+
使用`@DataProvider`定义接口为数据提供者
79+
80+
使用`@InvokeParameter`指定要传递的用户输入参数
81+
82+
**博客列表服务**
83+
84+
需要参数`userId`
5585

5686
```java
5787
@Service
5888
public class PostServiceImpl implements PostService {
59-
    @DataProvider("posts")
60-
    @Override
61-
    public List<Post> getPosts(@InvokeParameter("userId") Long userId) {
89+
@DataProvider("posts")
90+
@Override
91+
public List<Post> getPosts(@InvokeParameter("userId") Long userId) {
6292
try {
63-
            Thread.sleep(1000L);
64-
        } catch (InterruptedException e) {
65-
        }
66-
        Post post = new Post();
67-
        post.setTitle("spring data aggregate example");
68-
        post.setContent("No active profile set, falling back to default profiles");
69-
        return Collections.singletonList(post);
70-
    }
93+
Thread.sleep(1000L);
94+
} catch (InterruptedException e) {
95+
//
96+
}
97+
Post post = new Post();
98+
post.setTitle("spring data aggregate example");
99+
post.setContent("No active profile set, falling back to default profiles");
100+
return Collections.singletonList(post);
101+
}
71102
}
72103
```
73104

74-
**User basic information query service**
105+
**用户基础信息查询服务**
75106

76-
require input parameter `userId`.
107+
需要参数`userId`
77108

78109
```java
79110
@Service
80111
public class UserServiceImpl implements UserService {
81112

82-
    @DataProvider("user")
83-
    @Override
84-
    public User get(@InvokeParameter("userId") Long id) {
113+
@DataProvider("user")
114+
@Override
115+
public User get(@InvokeParameter("userId") Long id) {
116+
/* */
85117
try {
86-
            Thread.sleep(100L);
87-
        } catch (InterruptedException e) {
88-
        }
89-
        /* mock a user*/
90-
        User user = new User();
91-
        user.setId(id);
92-
        user.setEmail("lvyahui8@gmail.com");
93-
        user.setUsername("lvyahui8");
94-
        return user;
95-
    }
118+
Thread.sleep(100L);
119+
} catch (InterruptedException e) {
120+
//
121+
}
122+
/* mock a user*/
123+
User user = new User();
124+
user.setId(id);
125+
user.setEmail("lvyahui8@gmail.com");
126+
user.setUsername("lvyahui8");
127+
return user;
128+
}
96129
}
97130
```
98131

99-
### 2. Define and implement an aggregation layer
132+
### 2. 定义并实现聚合层
100133

101-
Combine `@DataProvider` ( `@DataConsumer` \ `@InvokeParameter` ) to achieve aggregation function
134+
组合`@DataProvider` \ `@DataConsumer` \ `@InvokeParameter` 实现汇聚功能
102135

103136
```java
104137
@Component
105138
public class UserAggregate {
106-
    @DataProvider("userWithPosts")
107-
    public User userWithPosts(
108-
            @DataConsumer("user") User user,
109-
            @DataConsumer("posts") List<Post> posts) {
110-
        user.setPosts(posts);
111-
        return user;
112-
    }
139+
@DataProvider("userWithPosts")
140+
public User userWithPosts(
141+
@DataConsumer("user") User user,
142+
@DataConsumer("posts") List<Post> posts) {
143+
user.setPosts(posts);
144+
return user;
145+
}
113146
}
114147
```
115148

116-
### 3. Call the aggregation layer interface
149+
### 3. 调用聚合层接口
117150

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

120-
Specify queried data id, invoke parameters, and return type to invoke `facade.get` method
153+
指定要查询的data id, 查询参数, 返回值类型, 并调用`facade.get`方法即可
121154

122155
```java
123156
DataBeanAggregateQueryFacade queryFacade = context.getBean(DataBeanAggregateQueryFacade.class);
124-
User user = queryFacade.get(/*data id*/ "userWithPosts",
125-
                            /*Invoke Parameters*/
126-
                            Collections.singletonMap("userId",1L),
127-
                            User.class);
157+
User user = queryFacade.get(/*data id*/ "userWithPosts",
158+
/*Invoke Parameters*/
159+
Collections.singletonMap("userId",1L),
160+
User.class);
128161
Assert.notNull(user,"user not null");
129162
Assert.notNull(user.getPosts(),"user posts not null");
130163
```
131164

132-
**Invoke result**
165+
**运行结果**
133166

134-
As you can see, `user` interface and `posts` interface are executed by the asynchronous thread while `userWithPosts` service is executed by the calling thread.
167+
可以看到, user 和posts是由异步线程执行查询, 而userWithPosts是主调线程执行, 其中
135168

136-
- Basic user information query takes 1000ms
137-
- User blog list query takes 1000ms
138-
- **Total query takes 1005ms**
169+
- 基础user信息查询耗费时间 1000ms
170+
- 用户博客列表查询耗费时间 1000ms
171+
- **总的查询时间 1005ms**
139172

140173
```
141-
[aggregateTask-1] query id: user, costTime: 1000ms, resultType: User, invokeMethod: UserServiceImpl#get
142-
[aggregateTask-2] query id: posts, costTime: 1000ms, resultType: List, invokeMethod: PostServiceImpl#getPosts
143-
[ main] query id: userWithPosts, costTime: 1010ms, resultType: User, invokeMethod: UserAggregate#userWithPosts
144-
[ main] user.name:lvyahui8,user.posts.size:1
174+
[aggregateTask-1] query id: user, costTime: 1000ms, resultType: User, invokeMethod: UserServiceImpl#get
175+
[aggregateTask-2] query id: posts, costTime: 1000ms, resultType: List, invokeMethod: PostServiceImpl#getPosts
176+
[ main] query id: userWithPosts, costTime: 1010ms, resultType: User, invokeMethod: UserAggregate#userWithPosts
177+
[ main] user.name:lvyahui8,user.posts.size:1
145178
```
146179

147-
## Contributors
148-
149-
- Feego (lvyauhi8@gmail.com)
180+
## 贡献者
150181

182+
- Feego(lvyauhi8@gmail.com)
151183
- Iris G

0 commit comments

Comments
 (0)