Browse Source

feat: KERNEL-10354 bytebuddy / 加解密性能优化 @Harrison

修复 FaultToleranceAdvice 的 Callable 问题
feature/x
Harrison 3 years ago
parent
commit
fb70596c1d
  1. 8
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerListener.java
  2. 21
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java
  3. 56
      designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java
  4. 50
      designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableAdvice.java
  5. 15
      designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableHelper.java

8
designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerListener.java

@ -6,6 +6,8 @@ import com.fr.third.net.bytebuddy.description.type.TypeDescription;
import com.fr.third.net.bytebuddy.dynamic.DynamicType; import com.fr.third.net.bytebuddy.dynamic.DynamicType;
import com.fr.third.net.bytebuddy.utility.JavaModule; import com.fr.third.net.bytebuddy.utility.JavaModule;
import java.io.File;
/** /**
* created by Harrison on 2022/03/08 * created by Harrison on 2022/03/08
**/ **/
@ -14,6 +16,12 @@ public class DesignerAnalyzerListener extends AgentBuilder.Listener.Adapter {
@Override @Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) { public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) {
FineLoggerFactory.getLogger().debug("Designer-Analyzer transform successfully:{}", typeDescription); FineLoggerFactory.getLogger().debug("Designer-Analyzer transform successfully:{}", typeDescription);
try {
dynamicType.saveIn(new File("/Users/3dot141/Temp/bytebuddy"));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
} }
@Override @Override

21
designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java

@ -1,6 +1,8 @@
package com.fr.design.record.analyzer.advice; package com.fr.design.record.analyzer.advice;
import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; import com.fr.design.record.analyzer.DesignerAnalyzerAdvice;
import com.fr.record.analyzer.advice.AdviceContext;
import com.fr.record.analyzer.advice.DefaultAdviceCallable;
import com.fr.third.net.bytebuddy.asm.Advice; import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import com.fr.tolerance.FaultTolerance; import com.fr.tolerance.FaultTolerance;
@ -15,19 +17,30 @@ import java.util.concurrent.Callable;
public class FaultToleranceAdvice implements DesignerAnalyzerAdvice { public class FaultToleranceAdvice implements DesignerAnalyzerAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class) @Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class)
public static int onMethodEnter() throws Exception { public static boolean onMethodEnter(@Advice.Local("context") AdviceContext adviceContext) throws Exception {
return 0;
adviceContext = AdviceContext
.builder()
.onAdviceCall()
.build();
// 如果是切面调用,则忽视当前方法
return adviceContext.isOnAdviceCall();
} }
@Advice.OnMethodExit(onThrowable = Exception.class) @Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self, public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self,
@Advice.Origin Method method, @Advice.Origin Method method,
@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args,
@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) throws Exception { @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result,
@Advice.Local("context")AdviceContext adviceContext) throws Exception {
// 如果是切面调用,则忽视不继续 exit
if (adviceContext != null && adviceContext.isOnAdviceCall()) {
return;
}
FaultTolerance faultTolerance = method.getAnnotation(FaultTolerance.class); FaultTolerance faultTolerance = method.getAnnotation(FaultTolerance.class);
Callable<Object> callable = () -> method.invoke(self, args); Callable<Object> callable = new DefaultAdviceCallable<>(self, method, args);
result = FaultToleranceFactory.getInstance().getScene(faultTolerance.scene()).getProcessor().execute(self, callable, args); result = FaultToleranceFactory.getInstance().getScene(faultTolerance.scene()).getProcessor().execute(self, callable, args);
} }
} }

56
designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java

@ -5,9 +5,12 @@ import com.fr.third.net.bytebuddy.agent.ByteBuddyAgent;
import com.fr.third.net.bytebuddy.asm.Advice; import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.dynamic.loading.ClassReloadingStrategy; import com.fr.third.net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import com.fr.third.net.bytebuddy.matcher.ElementMatchers; import com.fr.third.net.bytebuddy.matcher.ElementMatchers;
import com.fr.third.org.apache.commons.lang3.time.StopWatch;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.util.concurrent.TimeUnit;
/** /**
* 测试一下通过 redefine 去处理代码时 * 测试一下通过 redefine 去处理代码时
* 相应的 advice 应该怎么写 * 相应的 advice 应该怎么写
@ -80,4 +83,57 @@ public class BytebuddyRedefineTest {
} }
@Test
public void testCallable() throws Exception {
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(TestClass.class)
.visit(Advice.to(TestCallableAdvice.class).on(ElementMatchers.named("testPrint")))
.make()
.load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
TestClass testClass = new TestClass();
String print = testClass.testPrint();
Assert.assertEquals("[test]Callable", print);
}
@Test
public void testCallablePerformance() throws Exception {
// 千
int loop = 1000;
StopWatch stopWatch = new StopWatch();
stopWatch.start();
TestClass rawClass = new TestClass();
for (int i = 0; i < loop; i++) {
rawClass.testPrint();
}
System.out.printf("raw class run %s cost %s ms \n", loop, stopWatch.getTime(TimeUnit.MILLISECONDS));
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(TestClass.class)
.visit(Advice.to(TestCallableAdvice.class).on(ElementMatchers.named("testPrint")))
.make()
.load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
stopWatch.reset();
stopWatch.start();
TestClass retransformClass = new TestClass();
for (int i = 0; i < loop; i++) {
retransformClass.testPrint();
}
System.out.printf("retransformClass class run %s cost %s ms \n", loop, stopWatch.getTime(TimeUnit.MILLISECONDS));
Assert.assertEquals("[test]Callable", retransformClass.testPrint());
}
} }

50
designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableAdvice.java

@ -0,0 +1,50 @@
package com.fr.design.record.analyzer;
import com.fr.record.analyzer.advice.AdviceCallable;
import com.fr.record.analyzer.advice.AdviceContext;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import com.fr.tolerance.FaultTolerance;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
/**
* created by Harrison on 2022/03/09
**/
public class TestCallableAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class)
public static boolean onMethodEnter(@Advice.Local("context")AdviceContext adviceContext) {
adviceContext = AdviceContext
.builder()
.onAdviceCall()
.build();
// 如果是切面调用,则忽视当前方法
return adviceContext.isOnAdviceCall();
}
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self,
@Advice.Origin Method method,
@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args,
@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result,
@Advice.Local("context") AdviceContext adviceContext) throws Exception {
// 如果是切面调用,则忽视不继续 exit
if (adviceContext != null && adviceContext.isOnAdviceCall()) {
return;
}
FaultTolerance faultTolerance = method.getAnnotation(FaultTolerance.class);
Callable<Object> callable = new AdviceCallable<Object>() {
@Override
public Object call() throws Exception {
return method.invoke(self, args);
}
};
result = TestCallableHelper.test(callable);
}
}

15
designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableHelper.java

@ -0,0 +1,15 @@
package com.fr.design.record.analyzer;
import java.util.concurrent.Callable;
/**
* created by Harrison on 2022/03/09
**/
public class TestCallableHelper {
public static String test(Callable<Object> callable) throws Exception {
callable.call();
return "[test]Callable";
}
}
Loading…
Cancel
Save