Skip to content

Commit 6645618

Browse files
committed
feat: supports the redisTemplate component provided by spring data redis
1 parent 7831d54 commit 6645618

File tree

16 files changed

+481
-37
lines changed

16 files changed

+481
-37
lines changed

arex-agent/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@
106106
<artifactId>arex-redission-v3</artifactId>
107107
<version>${project.version}</version>
108108
</dependency>
109+
<dependency>
110+
<groupId>${project.groupId}</groupId>
111+
<artifactId>arex-spring-data-redis</artifactId>
112+
<version>${project.version}</version>
113+
</dependency>
109114
<dependency>
110115
<groupId>${project.groupId}</groupId>
111116
<artifactId>arex-dynamic</artifactId>

arex-instrumentation/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<module>redis/arex-lettuce-v5</module>
3333
<module>redis/arex-lettuce-v6</module>
3434
<module>redis/arex-redission-v3</module>
35+
<module>redis/arex-spring-data-redis</module>
3536
<module>dynamic/arex-dynamic</module>
3637
<module>dynamic/arex-dynamic-common</module>
3738
<module>dynamic/arex-cache</module>

arex-instrumentation/redis/arex-jedis-v2/src/main/java/io/arex/inst/jedis/v2/JedisWrapper.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.arex.agent.bootstrap.model.MockResult;
44
import io.arex.agent.bootstrap.util.ArrayUtils;
55
import io.arex.inst.runtime.context.ContextManager;
6+
import io.arex.inst.runtime.context.RepeatedCollectManager;
67
import io.arex.inst.runtime.serializer.Serializer;
78
import io.arex.inst.redis.common.RedisExtractor;
89
import io.arex.inst.redis.common.RedisKeyUtil;
@@ -546,6 +547,9 @@ private <U> U call(String command, Object key, Callable<U> callable, U defaultVa
546547
}
547548

548549
private <U> U call(String command, Object key, Object field, Callable<U> callable, U defaultValue) {
550+
if (ContextManager.needRecord()) {
551+
RepeatedCollectManager.enter();
552+
}
549553
if (ContextManager.needReplay()) {
550554
RedisExtractor extractor = new RedisExtractor(this.url, command, key, field);
551555
MockResult mockResult = extractor.replay();
@@ -561,7 +565,7 @@ private <U> U call(String command, Object key, Object field, Callable<U> callabl
561565
try {
562566
result = callable.call();
563567
} catch (Exception e) {
564-
if (ContextManager.needRecord()) {
568+
if (ContextManager.needRecord() && RepeatedCollectManager.exitAndValidate()) {
565569
RedisExtractor extractor = new RedisExtractor(this.url, command, key, field);
566570
extractor.record(e);
567571
}
@@ -573,7 +577,7 @@ private <U> U call(String command, Object key, Object field, Callable<U> callabl
573577
return defaultValue;
574578
}
575579

576-
if (ContextManager.needRecord()) {
580+
if (ContextManager.needRecord() && RepeatedCollectManager.exitAndValidate()) {
577581
RedisExtractor extractor = new RedisExtractor(this.url, command, key, field);
578582
extractor.record(result);
579583
}

arex-instrumentation/redis/arex-jedis-v4/src/main/java/io/arex/inst/jedis/v4/JedisWrapper.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.arex.agent.bootstrap.util.ArrayUtils;
44
import io.arex.inst.runtime.context.ContextManager;
5+
import io.arex.inst.runtime.context.RepeatedCollectManager;
56
import io.arex.inst.runtime.serializer.Serializer;
67
import io.arex.agent.bootstrap.model.MockResult;
78
import io.arex.inst.redis.common.RedisExtractor;
@@ -598,6 +599,10 @@ private <U> U call(String command, String key, Callable<U> callable, U defaultVa
598599
}
599600

600601
private <U> U call(String command, String key, String field, Callable<U> callable, U defaultValue) {
602+
if (ContextManager.needRecord()) {
603+
RepeatedCollectManager.enter();
604+
}
605+
601606
if (ContextManager.needReplay()) {
602607
RedisExtractor extractor = new RedisExtractor(this.url, command, key, field);
603608
MockResult mockResult = extractor.replay();
@@ -613,7 +618,7 @@ private <U> U call(String command, String key, String field, Callable<U> callabl
613618
try {
614619
result = callable.call();
615620
} catch (Exception e) {
616-
if (ContextManager.needRecord()) {
621+
if (ContextManager.needRecord() && RepeatedCollectManager.exitAndValidate()) {
617622
RedisExtractor extractor = new RedisExtractor(this.url, command, key, field);
618623
extractor.record(e);
619624
}
@@ -625,7 +630,7 @@ private <U> U call(String command, String key, String field, Callable<U> callabl
625630
return defaultValue;
626631
}
627632

628-
if (ContextManager.needRecord()) {
633+
if (ContextManager.needRecord() && RepeatedCollectManager.exitAndValidate()) {
629634
RedisExtractor extractor = new RedisExtractor(this.url, command, key, field);
630635
extractor.record(result);
631636
}

arex-instrumentation/redis/arex-redis-common/src/main/java/io/arex/inst/redis/common/RedisKeyUtil.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
import io.arex.agent.bootstrap.util.StringUtil;
5+
import java.util.Collection;
56
import java.util.Iterator;
67
import java.util.Map;
78

arex-instrumentation/redis/arex-redis-common/src/main/java/io/arex/inst/redis/common/lettuce/wrapper/RedisCommandWrapper.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.arex.inst.redis.common.RedisKeyUtil;
77
import io.arex.inst.redis.common.lettuce.RedisCommandBuilderImpl;
88
import io.arex.inst.runtime.context.ContextManager;
9+
import io.arex.inst.runtime.context.RepeatedCollectManager;
910
import io.lettuce.core.AbstractRedisAsyncCommands;
1011
import io.lettuce.core.GetExArgs;
1112
import io.lettuce.core.KeyValue;
@@ -704,6 +705,10 @@ public <T> RedisFuture<T> dispatch(Supplier<RedisFuture<T>> supplier, RedisComma
704705
}
705706

706707
public <T> RedisFuture<T> dispatch(Supplier<RedisFuture<T>> supplier, RedisCommand<K, V, T> cmd, String key, String redisUri, String field) {
708+
if (ContextManager.needRecord()) {
709+
RepeatedCollectManager.enter();
710+
}
711+
707712
if (ContextManager.needReplay()) {
708713
AsyncCommand<K, V, T> asyncCommand = new AsyncCommand<>(cmd);
709714
RedisExtractor extractor = new RedisExtractor(redisUri, cmd.getType().name(), key, field);
@@ -720,7 +725,7 @@ public <T> RedisFuture<T> dispatch(Supplier<RedisFuture<T>> supplier, RedisComma
720725

721726
RedisFuture<T> resultFuture = supplier.get();
722727

723-
if (ContextManager.needRecord()) {
728+
if (ContextManager.needRecord() && RepeatedCollectManager.exitAndValidate()) {
724729
try (TraceTransmitter traceTransmitter = TraceTransmitter.create()) {
725730
resultFuture.whenComplete((v, throwable) -> {
726731
RedisExtractor extractor = new RedisExtractor(redisUri, cmd.getType().name(), key, field);

arex-instrumentation/redis/arex-redission-v3/src/main/java/io/arex/inst/redisson/v3/RedissonWrapperCommon.java

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@
55
import io.arex.inst.redisson.v3.common.RFutureWrapper;
66
import io.arex.inst.runtime.context.ContextManager;
77
import io.arex.inst.redis.common.RedisExtractor;
8+
import io.arex.inst.runtime.context.RepeatedCollectManager;
9+
import java.util.function.Supplier;
810
import org.redisson.api.RFuture;
911

10-
import java.util.concurrent.Callable;
11-
1212
/**
1313
* RedissonWrapperCommon
1414
*/
1515
public class RedissonWrapperCommon {
1616
public static <R> RFuture<R> delegateCall(String redisUri, String cmd, String key,
17-
Callable<RFuture<R>> resultFuture) {
18-
return delegateCall(redisUri, cmd, key, null, resultFuture);
17+
Supplier<RFuture<R>> futureSupplier) {
18+
return delegateCall(redisUri, cmd, key, null, futureSupplier);
1919
}
2020

2121
public static <R> RFuture<R> delegateCall(String redisUri, String cmd, String key, String field,
22-
Callable<RFuture<R>> futureCallable) {
22+
Supplier<RFuture<R>> futureSupplier) {
23+
if (ContextManager.needRecord()) {
24+
RepeatedCollectManager.enter();
25+
}
2326
if (ContextManager.needReplay()) {
2427
RedisExtractor extractor = new RedisExtractor(redisUri, cmd, key, field);
2528
MockResult mockResult = extractor.replay();
@@ -31,20 +34,9 @@ public static <R> RFuture<R> delegateCall(String redisUri, String cmd, String ke
3134
}
3235
}
3336

34-
RFuture<R> resultFuture = null;
35-
try {
36-
resultFuture = futureCallable.call();
37-
} catch (Exception e) {
38-
// The following codes may not execute, just catch checked exception
39-
if (ContextManager.needRecord()) {
40-
RedisExtractor extractor = new RedisExtractor(redisUri, cmd, key, field);
41-
extractor.record(e);
42-
}
43-
44-
return resultFuture;
45-
}
37+
RFuture<R> resultFuture = futureSupplier.get();
4638

47-
if (resultFuture != null && ContextManager.needRecord()) {
39+
if (resultFuture != null && ContextManager.needRecord() && RepeatedCollectManager.exitAndValidate()) {
4840
try (TraceTransmitter traceTransmitter = TraceTransmitter.create()) {
4941
resultFuture.whenComplete((v, throwable) -> {
5042
traceTransmitter.transmit();

arex-instrumentation/redis/arex-redission-v3/src/test/java/io/arex/inst/redisson/v3/RedissonWrapperCommonTest.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.arex.inst.runtime.context.ContextManager;
44
import io.arex.agent.bootstrap.model.MockResult;
55
import io.arex.inst.redis.common.RedisExtractor;
6+
import java.util.function.Supplier;
67
import org.junit.jupiter.api.AfterAll;
78
import org.junit.jupiter.api.BeforeAll;
89
import org.junit.jupiter.api.extension.ExtendWith;
@@ -16,7 +17,6 @@
1617
import org.redisson.misc.CompletableFutureWrapper;
1718

1819
import java.util.Objects;
19-
import java.util.concurrent.Callable;
2020
import java.util.function.Predicate;
2121
import java.util.stream.Stream;
2222

@@ -38,28 +38,28 @@ static void tearDown() {
3838

3939
@ParameterizedTest
4040
@MethodSource("delegateCallCase")
41-
void delegateCall(Runnable mocker, Callable<RFuture<String>> futureCallable, Predicate<RFuture> predicate) {
41+
void delegateCall(Runnable mocker, Supplier<RFuture<String>> futureSupplier, Predicate<RFuture> predicate) {
4242
try(MockedConstruction<RedisExtractor> extractor = Mockito.mockConstruction(RedisExtractor.class, (mock, context) -> {
4343
Mockito.when(mock.replay()).thenReturn(MockResult.success(true,"mock"));
4444
})) {
4545
mocker.run();
46-
RFuture result = RedissonWrapperCommon.delegateCall("", "", "", futureCallable);
46+
RFuture result = RedissonWrapperCommon.delegateCall("", "", "", futureSupplier);
4747
assertTrue(predicate.test(result));
4848
}
4949

5050
try(MockedConstruction<RedisExtractor> extractor = Mockito.mockConstruction(RedisExtractor.class, (mock, context) -> {
5151
Mockito.when(mock.replay()).thenReturn(MockResult.success(false,"mock"));
5252
})) {
5353
mocker.run();
54-
RFuture result = RedissonWrapperCommon.delegateCall("", "", "", futureCallable);
54+
RFuture result = RedissonWrapperCommon.delegateCall("", "", "", futureSupplier);
5555
assertTrue(predicate.test(result));
5656
}
5757

5858
try(MockedConstruction<RedisExtractor> extractor = Mockito.mockConstruction(RedisExtractor.class, (mock, context) -> {
5959
Mockito.when(mock.replay()).thenReturn(MockResult.success(new Throwable()));
6060
})) {
6161
mocker.run();
62-
RFuture result = RedissonWrapperCommon.delegateCall("", "", "", futureCallable);
62+
RFuture result = RedissonWrapperCommon.delegateCall("", "", "", futureSupplier);
6363
assertTrue(predicate.test(result));
6464
}
6565
}
@@ -72,16 +72,13 @@ static Stream<Arguments> delegateCallCase() {
7272
Mockito.when(ContextManager.needReplay()).thenReturn(false);
7373
Mockito.when(ContextManager.needRecord()).thenReturn(true);
7474
};
75-
Callable<RFuture<String>> futureCallable = () -> new CompletableFutureWrapper<>("mock");
76-
Callable<RFuture<String>> futureCallable1 = () -> new CompletableFutureWrapper<>(new NullPointerException());
77-
Callable futureCallable2 = NullPointerException::new;
78-
Predicate<RFuture> predicate1 = Objects::isNull;
75+
Supplier<RFuture<String>> futureSupplier = () -> new CompletableFutureWrapper<>("mock");
76+
Supplier<RFuture<String>> futureSupplier1 = () -> new CompletableFutureWrapper<>(new NullPointerException());
7977
Predicate<RFuture> predicate2 = Objects::nonNull;
8078
return Stream.of(
81-
arguments(mocker1, futureCallable, predicate2),
82-
arguments(mocker2, futureCallable, predicate2),
83-
arguments(mocker2, futureCallable1, predicate2),
84-
arguments(mocker2, futureCallable2, predicate1)
79+
arguments(mocker1, futureSupplier, predicate2),
80+
arguments(mocker2, futureSupplier, predicate2),
81+
arguments(mocker2, futureSupplier1, predicate2)
8582
);
8683
}
87-
}
84+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>arex-instrumentation-parent</artifactId>
7+
<groupId>io.arex</groupId>
8+
<version>${revision}</version>
9+
<relativePath>../../pom.xml</relativePath>
10+
</parent>
11+
<modelVersion>4.0.0</modelVersion>
12+
13+
<artifactId>arex-spring-data-redis</artifactId>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>io.arex</groupId>
18+
<artifactId>arex-redis-common</artifactId>
19+
<version>${project.version}</version>
20+
<scope>compile</scope>
21+
</dependency>
22+
<dependency>
23+
<groupId>org.springframework.data</groupId>
24+
<artifactId>spring-data-redis</artifactId>
25+
<version>2.2.4.RELEASE</version>
26+
<scope>provided</scope>
27+
</dependency>
28+
</dependencies>
29+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package io.arex.inst.spring.data.redis;
2+
3+
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
4+
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
5+
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
6+
import io.arex.inst.extension.MethodInstrumentation;
7+
import java.util.Collection;
8+
import java.util.Map;
9+
10+
public class MethodCollector {
11+
12+
static final String[] ONE_OBJECT_KEY = new String[]{
13+
// DefaultValueOperations
14+
"get", "set", "getAndSet", "setIfPresent", "increment", "decrement", "append", "sismember", "setIfAbsent",
15+
"size", "getBit", "setBit", "bitField",
16+
// DefaultListOperations
17+
"index", "leftPop", "leftPush", "leftPushAll", "leftPushIfPresent", "range", "remove", "rightPop", "rightPush",
18+
"rightPushAll", "rightPushIfPresent", "trim",
19+
// DefaultSetOperations
20+
"add", "isMember", "members", "move", "pop", "randomMember", "scan", "distinctRandomMembers",
21+
"randomMembers", "remove",
22+
// DefaultZSetOperations
23+
"incrementScore", "reverseRange", "rangeWithScores", "reverseRangeWithScores", "rangeByScore",
24+
"rangeByScoreWithScores", "rangeByLex", "reverseRangeByScore", "reverseRangeByScoreWithScores",
25+
"rank", "reverseRank", "removeRange", "removeRangeByScore", "score", "count", "zCard",
26+
// DefaultHashOperations
27+
"keys", "values", "entries", "randomKey", "randomEntry", "randomKeys", "randomEntries","delete"
28+
};
29+
30+
static final String[] TWO_OBJECT_KEY = new String[]{
31+
// DefaultListOperations
32+
"rightPopAndLeftPush",
33+
// DefaultSetOperations
34+
"difference", "differenceAndStore", "intersect", "intersectAndStore", "union", "unionAndStore",
35+
// DefaultHashOperations
36+
"hasKey", "increment", "lengthOfValue", "get", "put", "putIfAbsent"
37+
};
38+
39+
static final String[] COLLECTION_KEY = new String[]{
40+
// DefaultValueOperations
41+
"multiGet",
42+
// DefaultSetOperations
43+
"difference", "differenceAndStore", "intersect", "intersectAndStore", "union", "unionAndStore"
44+
};
45+
46+
static final String[] MAP_KEY = new String[]{
47+
// DefaultValueOperations
48+
"multiSet", "multiSetIfAbsent"
49+
};
50+
51+
static final String[] OBJECT_AND_COLLECTION_KEY = new String[]{
52+
// DefaultSetOperations
53+
"difference", "differenceAndStore", "intersect", "intersectAndStore", "union", "unionAndStore",
54+
// DefaultHashOperations
55+
"multiGet"
56+
};
57+
58+
static final String[] OBJECT_AND_MAP_KEY = new String[]{
59+
// DefaultHashOperations
60+
"putAll"
61+
};
62+
63+
public static MethodInstrumentation arg1IsObjectKey(String adviceClassName) {
64+
return new MethodInstrumentation(isMethod().and(namedOneOf(ONE_OBJECT_KEY)).
65+
and(takesArgument(0, Object.class)), adviceClassName);
66+
}
67+
68+
public static MethodInstrumentation arg1AndArg2AreObjectKey(String adviceClassName) {
69+
return new MethodInstrumentation(isMethod().and(namedOneOf(TWO_OBJECT_KEY)).
70+
and((takesArgument(0, Object.class))).and((takesArgument(1, Object.class))), adviceClassName);
71+
}
72+
73+
public static MethodInstrumentation arg1IsObjectKeyArg2IsCollectionKey(String adviceClassName) {
74+
return new MethodInstrumentation(isMethod().and(namedOneOf(OBJECT_AND_COLLECTION_KEY)).
75+
and((takesArgument(0, Object.class))).and((takesArgument(1, Collection.class))), adviceClassName);
76+
}
77+
78+
public static MethodInstrumentation arg1IsObjectKeyArg2IsMapKey(String adviceClassName) {
79+
return new MethodInstrumentation(isMethod().and(namedOneOf(OBJECT_AND_MAP_KEY)).
80+
and((takesArgument(0, Object.class))).and((takesArgument(1, Map.class))), adviceClassName);
81+
}
82+
83+
public static MethodInstrumentation arg1IsCollectionKey(String adviceClassName) {
84+
return new MethodInstrumentation(isMethod().and(namedOneOf(COLLECTION_KEY)).
85+
and((takesArgument(0, Collection.class))), adviceClassName);
86+
}
87+
88+
public static MethodInstrumentation arg1IsMapKey(String adviceClassName) {
89+
return new MethodInstrumentation(isMethod().and(namedOneOf(MAP_KEY)).
90+
and((takesArgument(0, Map.class))), adviceClassName);
91+
}
92+
}

0 commit comments

Comments
 (0)