Skip to content

Commit 4f6c367

Browse files
committed
query cache
1 parent 5ff2c46 commit 4f6c367

File tree

10 files changed

+189
-24
lines changed

10 files changed

+189
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.github.lvyahui8.spring.aggregate.consts;
2+
3+
/**
4+
* @author lvyahui (lvyahui8@gmail.com,lvyahui8@126.com)
5+
* @since 2019/6/28 23:53
6+
*/
7+
public interface AggregatorConstant
8+
{
9+
Object EMPTY_MODEL = new Object();
10+
}

spring-boot-data-aggregator-core/src/main/java/io/github/lvyahui8/spring/aggregate/facade/impl/DataBeanAggregateQueryFacadeImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.lang.reflect.InvocationTargetException;
88
import java.util.Collections;
99
import java.util.Map;
10+
import java.util.concurrent.ConcurrentHashMap;
1011

1112
/**
1213
* @author lvyahui (lvyahui8@gmail.com,lvyahui8@126.com)
@@ -27,6 +28,6 @@ public <T> T get(String id, Map<String,Object> invokeParams, Class<T> clazz) thr
2728
if(invokeParams == null) {
2829
invokeParams = Collections.emptyMap();
2930
}
30-
return dataBeanAggregateQueryService.get(id,invokeParams,clazz);
31+
return dataBeanAggregateQueryService.get(id,invokeParams,clazz,new ConcurrentHashMap<>());
3132
}
3233
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package io.github.lvyahui8.spring.aggregate.model;
2+
3+
import lombok.Data;
4+
5+
import java.lang.reflect.Method;
6+
import java.util.Arrays;
7+
import java.util.Objects;
8+
9+
/**
10+
* @author lvyahui (lvyahui8@gmail.com,lvyahui8@126.com)
11+
* @since 2019/6/28 22:42
12+
*/
13+
@Data
14+
public class InvokeSign {
15+
private Method method;
16+
private Object[] args;
17+
18+
public InvokeSign(Method method, Object[] args) {
19+
this.method = method;
20+
this.args = args;
21+
}
22+
23+
@Override
24+
public boolean equals(Object o) {
25+
if (this == o) return true;
26+
if (o == null || getClass() != o.getClass()) return false;
27+
InvokeSign that = (InvokeSign) o;
28+
return Objects.deepEquals(method, that.method) &&
29+
Arrays.deepEquals(args, that.args);
30+
}
31+
32+
@Override
33+
public int hashCode() {
34+
int result = Objects.hash(method);
35+
result = 31 * result + Arrays.hashCode(args);
36+
return result;
37+
}
38+
}

spring-boot-data-aggregator-core/src/main/java/io/github/lvyahui8/spring/aggregate/service/DataBeanAggregateQueryService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.github.lvyahui8.spring.aggregate.service;
22

3+
import io.github.lvyahui8.spring.aggregate.model.InvokeSign;
4+
35
import java.lang.reflect.InvocationTargetException;
46
import java.util.Map;
57

@@ -16,7 +18,9 @@ public interface DataBeanAggregateQueryService {
1618
* @param invokeParams query parameters
1719
* @param resultType final result type
1820
* @param <T> final result type
21+
* @param queryCache Used to cache data during the query
1922
* @return final result
2023
*/
21-
<T> T get(String id, Map<String,Object> invokeParams, Class<T> resultType) throws InterruptedException, InvocationTargetException, IllegalAccessException;
24+
<T> T get(String id, Map<String,Object> invokeParams, Class<T> resultType,final Map<InvokeSign,Object> queryCache)
25+
throws InterruptedException, InvocationTargetException, IllegalAccessException;
2226
}

spring-boot-data-aggregator-core/src/main/java/io/github/lvyahui8/spring/aggregate/service/impl/DataBeanAggregateQueryServiceImpl.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package io.github.lvyahui8.spring.aggregate.service.impl;
22

33
import io.github.lvyahui8.spring.aggregate.config.RuntimeSettings;
4-
import io.github.lvyahui8.spring.aggregate.model.DataConsumeDefination;
5-
import io.github.lvyahui8.spring.aggregate.model.DataProvideDefination;
6-
import io.github.lvyahui8.spring.aggregate.model.DenpendType;
7-
import io.github.lvyahui8.spring.aggregate.model.MethodArg;
4+
import io.github.lvyahui8.spring.aggregate.consts.AggregatorConstant;
5+
import io.github.lvyahui8.spring.aggregate.model.*;
86
import io.github.lvyahui8.spring.aggregate.repository.DataProviderRepository;
97
import io.github.lvyahui8.spring.aggregate.service.DataBeanAggregateQueryService;
108
import lombok.Setter;
@@ -40,8 +38,8 @@ public DataBeanAggregateQueryServiceImpl(DataProviderRepository repository) {
4038
}
4139

4240
@Override
43-
public <T> T get(String id, Map<String, Object> invokeParams, Class<T> resultType) throws InterruptedException,
44-
InvocationTargetException, IllegalAccessException {
41+
public <T> T get(String id, Map<String, Object> invokeParams, Class<T> resultType,final Map<InvokeSign,Object> queryCache)
42+
throws InterruptedException, InvocationTargetException, IllegalAccessException {
4543
Assert.isTrue(repository.contains(id),"id not exisit");
4644
long startTime = System.currentTimeMillis();
4745
DataProvideDefination provider = repository.get(id);
@@ -54,7 +52,7 @@ public <T> T get(String id, Map<String, Object> invokeParams, Class<T> resultTyp
5452
consumeDefinationMap.put(depend.getId(),depend);
5553
Future<?> future = executorService.submit(() -> {
5654
try {
57-
Object o = get(depend.getId(), invokeParams, depend.getClazz());
55+
Object o = get(depend.getId(), invokeParams, depend.getClazz(),queryCache);
5856
return depend.getClazz().cast(o);
5957
} finally {
6058
stopDownLatch.countDown();
@@ -95,8 +93,20 @@ public <T> T get(String id, Map<String, Object> invokeParams, Class<T> resultTyp
9593
}
9694
}
9795
try {
98-
return resultType.cast(provider.getMethod()
99-
.invoke(applicationContext.getBean(provider.getMethod().getDeclaringClass()), args));
96+
/* 如果调用方法是幂等的, 那么当方法签名和方法参数完全一致时, 可以直接使用缓存结果 */
97+
InvokeSign invokeSign = new InvokeSign(provider.getMethod(),args);
98+
Object resultModel;
99+
if(queryCache.containsKey(invokeSign)) {
100+
resultModel = queryCache.get(invokeSign);
101+
}
102+
else {
103+
resultModel = provider.getMethod()
104+
.invoke(applicationContext.getBean(provider.getMethod().getDeclaringClass()), args);
105+
/* Map 中可能不能放空value */
106+
queryCache.put(invokeSign,resultModel != null ? resultModel : AggregatorConstant.EMPTY_MODEL);
107+
}
108+
109+
return resultType.cast(resultModel != AggregatorConstant.EMPTY_MODEL ? resultModel : null);
100110
} finally {
101111
logging(id, startTime, provider);
102112
}
Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package io.github.lvyahui8.spring.example;
22

3-
import io.github.lvyahui8.spring.example.facade.UserQueryFacade;
4-
import lombok.extern.slf4j.Slf4j;
53
import io.github.lvyahui8.spring.aggregate.facade.DataBeanAggregateQueryFacade;
4+
import io.github.lvyahui8.spring.example.facade.UserQueryFacade;
65
import io.github.lvyahui8.spring.example.model.User;
6+
import lombok.extern.slf4j.Slf4j;
77
import org.springframework.boot.SpringApplication;
88
import org.springframework.boot.autoconfigure.SpringBootApplication;
99
import org.springframework.context.ConfigurableApplicationContext;
@@ -22,18 +22,35 @@
2222
public class ExampleApplication {
2323
public static void main(String[] args) throws Exception {
2424
ConfigurableApplicationContext context = SpringApplication.run(ExampleApplication.class);
25-
DataBeanAggregateQueryFacade queryFacade = context.getBean(DataBeanAggregateQueryFacade.class);
25+
try{
26+
DataBeanAggregateQueryFacade queryFacade = context.getBean(DataBeanAggregateQueryFacade.class);
27+
28+
{
29+
User user = queryFacade.get("userWithPosts", Collections.singletonMap("userId",1L), User.class);
30+
Assert.notNull(user,"user not null");
31+
Assert.notNull(user.getPosts(),"user posts not null");
32+
log.info("user.name:{},user.posts.size:{}",
33+
user.getUsername(),user.getPosts().size());
34+
}
35+
36+
log.info("------------------------------------------------------------------");
2637

27-
User user = queryFacade.get("userWithPosts", Collections.singletonMap("userId",1L), User.class);
28-
Assert.notNull(user,"user not null");
29-
Assert.notNull(user.getPosts(),"user posts not null");
30-
log.info("user.name:{},user.posts.size:{}",
31-
user.getUsername(),user.getPosts().size());
38+
{
39+
User user = context.getBean(UserQueryFacade.class).getUserFinal(1L);
40+
Assert.notNull(user.getFollowers(),"user followers not null");
41+
}
3242

33-
user = context.getBean(UserQueryFacade.class).getUserFinal(1L);
34-
Assert.notNull(user.getFollowers(),"user followers not null");
43+
log.info("------------------------------------------------------------------");
3544

36-
ExecutorService executorService = (ExecutorService) context.getBean("aggregateExecutorService");
37-
executorService.shutdown();
45+
{
46+
for (int i = 0; i < 100; i ++) {
47+
String s = queryFacade.get("categoryTitle", Collections.singletonMap("categoryId", 1L), String.class);
48+
Assert.isTrue(org.apache.commons.lang3.StringUtils.isNotEmpty(s),"s not null");
49+
}
50+
}
51+
} finally {
52+
ExecutorService executorService = (ExecutorService) context.getBean("aggregateExecutorService");
53+
executorService.shutdown();
54+
}
3855
}
3956
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.github.lvyahui8.spring.example.model;
2+
3+
import lombok.Data;
4+
5+
import java.util.List;
6+
7+
/**
8+
* @author lvyahui (lvyahui8@gmail.com,lvyahui8@126.com)
9+
* @since 2019/6/28 23:34
10+
*/
11+
@Data
12+
public class Category {
13+
private Long id;
14+
private String name;
15+
List<String> topCategoryNames;
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.github.lvyahui8.spring.example.service;
2+
3+
import io.github.lvyahui8.spring.example.model.Category;
4+
5+
import java.util.List;
6+
7+
/**
8+
* @author lvyahui (lvyahui8@gmail.com,lvyahui8@126.com)
9+
* @since 2019/6/28 23:34
10+
*/
11+
public interface CategoryService {
12+
Category getRootCategory(List<String> topCategoryNames,Long id);
13+
14+
String getCategoryTitle(Category category, List<String> topCategoryNames);
15+
16+
List<String> getTopCategoryNames();
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package io.github.lvyahui8.spring.example.service.impl;
2+
3+
import io.github.lvyahui8.spring.annotation.DataConsumer;
4+
import io.github.lvyahui8.spring.annotation.DataProvider;
5+
import io.github.lvyahui8.spring.annotation.InvokeParameter;
6+
import io.github.lvyahui8.spring.example.model.Category;
7+
import io.github.lvyahui8.spring.example.service.CategoryService;
8+
import lombok.extern.slf4j.Slf4j;
9+
import org.springframework.stereotype.Service;
10+
11+
import java.util.List;
12+
import java.util.Random;
13+
import java.util.stream.Collectors;
14+
import java.util.stream.Stream;
15+
16+
/**
17+
* @author lvyahui (lvyahui8@gmail.com,lvyahui8@126.com)
18+
* @since 2019/6/28 23:38
19+
*/
20+
@Service
21+
@Slf4j
22+
public class CategoryServiceImpl implements CategoryService {
23+
24+
@DataProvider("rootCategory")
25+
@Override
26+
public Category getRootCategory(@DataConsumer("topCategoryNames") List<String> topCategoryNames,@InvokeParameter("categoryId") Long id) {
27+
Category category = new Category();
28+
category.setId(id);
29+
category.setName("youtube");
30+
category.setTopCategoryNames(topCategoryNames);
31+
return category;
32+
}
33+
34+
@DataProvider("categoryTitle")
35+
@Override
36+
public String getCategoryTitle(@DataConsumer("rootCategory") Category category,
37+
@DataConsumer("topCategoryNames") List<String> topCategoryNames) {
38+
if(category.getTopCategoryNames() == topCategoryNames){
39+
log.info("'user.getFollowers()' and 'followers' may be the same object " +
40+
"because the query cache is used. ");
41+
}
42+
return category.getName();
43+
}
44+
45+
@DataProvider("topCategoryNames")
46+
public List<String> getTopCategoryNames() {
47+
Random r = new Random(System.currentTimeMillis());
48+
return Stream.of("feego", "figo", "sam").map(item -> item+r.nextInt(1000))
49+
.collect(Collectors.toList());
50+
}
51+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
spring.main.banner-mode=off
22
io.github.lvyahui8.spring.base-packages=io.github.lvyahui8.spring.example
3-
io.github.lvyahui8.spring.ignore-exception=false
3+
io.github.lvyahui8.spring.ignore-exception=false
4+
io.github.lvyahui8.spring.enable-logging=false

0 commit comments

Comments
 (0)