From 8b2b81926c76f52e6a26e967f6cc37f04fdaf803 Mon Sep 17 00:00:00 2001 From: Harrison Date: Mon, 7 Mar 2022 16:33:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20KERNEL-10354=20bytebuddy=20/=20?= =?UTF-8?q?=E5=8A=A0=E8=A7=A3=E5=AF=86=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96?= =?UTF-8?q?=20@Harrison=201=E3=80=81FineAnalyzer=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=BB=B6=E8=BF=9F=E5=90=AF=E5=8A=A8=202=E3=80=81FineAnalyzer?= =?UTF-8?q?=20=E8=A1=A5=E5=85=85=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=203?= =?UTF-8?q?=E3=80=81=E8=A1=A5=E5=85=85=E4=BC=98=E5=8C=96=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../record/analyzer/DesignerAnalyzer.java | 22 +++ .../analyzer/DesignerAnalyzerActivator.java | 121 +++++++++++++ .../analyzer/DesignerAnalyzerAdvice.java | 12 ++ .../analyzer/advice/DBMonitorAdvice.java | 29 ++++ .../analyzer/advice/FaultToleranceAdvice.java | 35 ++++ .../record/analyzer/advice/FocusAdvice.java | 32 ++++ .../record/analyzer/advice/MonitorAdvice.java | 159 ++++++++++++++++++ .../advice/PerformancePointAdvice.java | 54 ++++++ .../analyzer/BytebuddyRedefineTest.java | 81 +++++++++ .../fr/design/record/analyzer/TestClass.java | 11 ++ .../analyzer/TestModifyReturnAdvice.java | 29 ++++ .../analyzer/TestThrowExceptionAdvice.java | 19 +++ .../analyzer/TestTransferValueAdvice.java | 37 ++++ .../main/java/com/fr/start/MainDesigner.java | 2 + 14 files changed, 643 insertions(+) create mode 100644 designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java create mode 100644 designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java create mode 100644 designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerAdvice.java create mode 100644 designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java create mode 100644 designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java create mode 100644 designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java create mode 100644 designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java create mode 100644 designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java create mode 100644 designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java create mode 100644 designer-base/src/test/java/com/fr/design/record/analyzer/TestClass.java create mode 100644 designer-base/src/test/java/com/fr/design/record/analyzer/TestModifyReturnAdvice.java create mode 100644 designer-base/src/test/java/com/fr/design/record/analyzer/TestThrowExceptionAdvice.java create mode 100644 designer-base/src/test/java/com/fr/design/record/analyzer/TestTransferValueAdvice.java diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java new file mode 100644 index 0000000000..fe4b308065 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java @@ -0,0 +1,22 @@ +package com.fr.design.record.analyzer; + +import com.fr.record.analyzer.AnalyzerConfiguration; +import com.fr.record.analyzer.AnalyzerUnit; +import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory; +import com.fr.record.analyzer.configuration.impl.RedefineAssemblyFactory; + +/** + * created by Harrison on 2022/03/08 + **/ +public class DesignerAnalyzer { + + private static final AnalyzerUnit ANALYZER = new AnalyzerUnit(); + + public static synchronized void init(AnalyzerAssemblyFactory factory, AnalyzerConfiguration... configurations) { + + AnalyzerAssemblyFactory redefineFactory = factory.prepare(RedefineAssemblyFactory.getInstance()); + + ANALYZER.init(redefineFactory, configurations); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java new file mode 100644 index 0000000000..60b65b1a19 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java @@ -0,0 +1,121 @@ +package com.fr.design.record.analyzer; + +import com.fr.base.OptimizeUtil; +import com.fr.concurrent.NamedThreadFactory; +import com.fr.design.record.analyzer.advice.DBMonitorAdvice; +import com.fr.design.record.analyzer.advice.FaultToleranceAdvice; +import com.fr.design.record.analyzer.advice.FocusAdvice; +import com.fr.design.record.analyzer.advice.MonitorAdvice; +import com.fr.design.record.analyzer.advice.PerformancePointAdvice; +import com.fr.intelli.metrics.Compute; +import com.fr.intelli.record.Focus; +import com.fr.intelli.record.PerformancePoint; +import com.fr.module.Activator; +import com.fr.module.extension.Prepare; +import com.fr.record.analyzer.AnalyzerConfiguration; +import com.fr.record.analyzer.AnalyzerKey; +import com.fr.record.analyzer.DBMetrics; +import com.fr.record.analyzer.FineAdviceTransformer; +import com.fr.record.analyzer.FineAnalyzer; +import com.fr.record.analyzer.advice.AnalyzerAdviceConfiguration; +import com.fr.record.analyzer.advice.AnalyzerAdviceKey; +import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory; +import com.fr.record.analyzer.configuration.FineAnalyzerAssemblyFactory; +import com.fr.stable.collections.CollectionUtils; +import com.fr.third.net.bytebuddy.matcher.ElementMatchers; +import com.fr.tolerance.FaultTolerance; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.concurrent.ExecutorService; + +/** + * created by Harrison on 2022/03/04 + **/ +public class DesignerAnalyzerActivator extends Activator implements Prepare { + + @Override + public void start() { + + OptimizeUtil.open(() -> { + ExecutorService es = newSingleThreadExecutor(new NamedThreadFactory("designer-analyzer", true)); + + try { + AnalyzerAssemblyFactory basicFactory = createBasicFactory(); + + // 兼容逻辑 + List backwardsConfigurations = findMutableBackwards(AnalyzerKey.KEY); + if (!CollectionUtils.isEmpty(backwardsConfigurations)) { + es.submit(() -> { + FineAnalyzer.init(basicFactory, backwardsConfigurations.toArray(new AnalyzerConfiguration[0])); + }); + } + + // 加入 retransform 部分的逻辑 + List adviceConfigurations = findMutable(AnalyzerAdviceKey.KEY); + + if (!CollectionUtils.isEmpty(adviceConfigurations)) { + AnalyzerConfiguration[] configurations = convertConfigurations(adviceConfigurations); + es.submit(() -> { + DesignerAnalyzer.init(basicFactory, configurations); + }); + } + + } finally { + es.shutdown(); + } + }); + } + + @NotNull + private AnalyzerConfiguration[] convertConfigurations(List list) { + + return list.stream() + .map((e) -> AnalyzerConfiguration.create(e.getMatcher(), new FineAdviceTransformer(e.getMatcher(), e.getAdviceClass()))) + .toArray(AnalyzerConfiguration[]::new); + } + + @Override + public void stop() { + + } + + @Override + public void prepare() { + + addMutable(AnalyzerAdviceKey.KEY, AnalyzerAdviceConfiguration.create( + ElementMatchers.isAnnotatedWith(Focus.class), + FocusAdvice.class + )); + + addMutable(AnalyzerAdviceKey.KEY, AnalyzerAdviceConfiguration.create( + ElementMatchers.isAnnotatedWith(Compute.class), + MonitorAdvice.class + )); + + addMutable(AnalyzerAdviceKey.KEY, AnalyzerAdviceConfiguration.create( + ElementMatchers.isAnnotatedWith(DBMetrics.class), + DBMonitorAdvice.class + )); + + addMutable(AnalyzerAdviceKey.KEY, AnalyzerAdviceConfiguration.create( + ElementMatchers.isAnnotatedWith(PerformancePoint.class), + PerformancePointAdvice.class + )); + + addMutable(AnalyzerAdviceKey.KEY, AnalyzerAdviceConfiguration.create( + ElementMatchers.isAnnotatedWith(FaultTolerance.class), + FaultToleranceAdvice.class + )); + + } + + + private AnalyzerAssemblyFactory createBasicFactory() { + + AnalyzerAssemblyFactory factory = findSingleton(AnalyzerAssemblyFactory.class); + FineAnalyzerAssemblyFactory basicFactory = new FineAnalyzerAssemblyFactory(); + basicFactory.prepare(factory); + return basicFactory; + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerAdvice.java new file mode 100644 index 0000000000..301634aa6d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerAdvice.java @@ -0,0 +1,12 @@ +package com.fr.design.record.analyzer; + +import com.fr.record.analyzer.advice.AnalyzerAdvice; + +/** + * 仅作为标志 + * 没有方法 + * + * created by Harrison on 2022/03/04 + **/ +public interface DesignerAnalyzerAdvice extends AnalyzerAdvice { +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java new file mode 100644 index 0000000000..9b22e07b24 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java @@ -0,0 +1,29 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.general.data.DataModel; +import com.fr.measure.DBMeterFactory; +import com.fr.measure.metric.DBMetric; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; + +/** + * created by Harrison on 2022/03/07 + **/ +public class DBMonitorAdvice implements DesignerAnalyzerAdvice { + + @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.Thrown(typing = Assigner.Typing.DYNAMIC) Exception e) { + + if (args.length > 1 && args[1] instanceof DataModel) { + DBMetric meter = ((DataModel) args[1]).getMetric(); + DBMeterFactory.getMeter().record(meter); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java new file mode 100644 index 0000000000..f0d089b3ed --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java @@ -0,0 +1,35 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; +import com.fr.tolerance.FaultTolerance; +import com.fr.tolerance.FaultToleranceFactory; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * created by Harrison on 2022/03/07 + **/ +public class FaultToleranceAdvice implements DesignerAnalyzerAdvice { + + @Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class) + public static int onMethodEnter(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self, + @Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args) throws Exception { + return 0; + } + + @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) throws Exception { + + + FaultTolerance faultTolerance = method.getAnnotation(FaultTolerance.class); + Callable callable = () -> method.invoke(self, args); + result = FaultToleranceFactory.getInstance().getScene(faultTolerance.scene()).getProcessor().execute(self, callable, args); + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java new file mode 100644 index 0000000000..653ce91093 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java @@ -0,0 +1,32 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.intelli.record.Focus; +import com.fr.intelli.record.FocusPoint; +import com.fr.intelli.record.FocusPolicy; +import com.fr.log.counter.DefaultLimitedMetric; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; + +/** + * created by Harrison on 2022/03/07 + **/ +public class FocusAdvice implements DesignerAnalyzerAdvice { + + private static final String FOCUS_POINT_ID_PREFIX = "function_"; + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) throws Exception { + + if (FocusPolicy.IGNORE == result) { + return; + } + Focus focus = method.getAnnotation(Focus.class); + String id = FOCUS_POINT_ID_PREFIX + focus.id(); + DefaultLimitedMetric.INSTANCE.submit(FocusPoint.create(id, focus.text(), focus.source()), id); + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java new file mode 100644 index 0000000000..826cc1e645 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java @@ -0,0 +1,159 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.general.GeneralUtils; +import com.fr.intelli.metrics.Compute; +import com.fr.intelli.metrics.SupervisoryConfig; +import com.fr.intelli.record.Measurable; +import com.fr.intelli.record.MeasureObject; +import com.fr.intelli.record.MeasureUnit; +import com.fr.intelli.record.MetricRegistry; +import com.fr.measure.DBMeterFactory; +import com.fr.stable.ArrayUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.web.Session; +import com.fr.stable.web.SessionProvider; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; +import com.fr.web.core.SessionPoolManager; +import com.fr.web.session.SessionLocalManager; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * created by Harrison on 2022/03/07 + **/ +public class MonitorAdvice implements DesignerAnalyzerAdvice { + + private static final Pattern P = Pattern.compile("-?\\d+"); + private static final int MIN_ERROR_CODE = 10000000; + + @Advice.OnMethodEnter + public static void onMethodEnter(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self, + @Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, + @Advice.Local("startTime") Long startTime, + @Advice.Local("registeredSession") Boolean registeredSession) { + + startTime = (System.currentTimeMillis()); + registeredSession = (findSessionAnnotation(method, args)); + } + + @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.Thrown(typing = Assigner.Typing.DYNAMIC) Exception e, + @Advice.Local("startTime") Long startTime, + @Advice.Local("registeredSession") Boolean registeredSession) throws Exception { + + String error = StringUtils.EMPTY; + + try { + + if (e != null) { + try { + error = getErrorContent(e); + } catch (Exception ignore) { + } + } + } finally { + try { + if (self instanceof Measurable) { + long consume = System.currentTimeMillis() - startTime; + Compute once = method.getAnnotation(Compute.class); + Measurable measurable = (Measurable) self; + MeasureObject measureObject = MeasureObject.create(); + recordMemory(once, measurable, measureObject); + recordSQL(once, measureObject); + measureObject.consume(consume); + measureObject.error(error); + String id = UUID.randomUUID().toString(); + List newArgs = new ArrayList(Arrays.asList(args)); + newArgs.add(id); + recordSQLDetail(id); + Object message; + try { + message = measurable.durableEntity(measureObject, newArgs.toArray()); + } catch (Throwable ignore) { + //埋点生成失败,降级逻辑 + message = measurable.fallBackEntity(); + } + if (message != null) { + SessionProvider provider = SessionLocalManager.getSession(); + if (provider == null) { + MetricRegistry.getMetric().submit(message); + } else { + MetricRegistry.getMetric().submitAccumulativeData(provider.getSessionID(), message); + } + } + } + } catch (Exception ignore) { + //埋点信息入库失败应该不能影响业务流程 + } finally { + if (registeredSession) { + // 如果上面记录了,这里就要释放 + SessionLocalManager.releaseSession(); + } + } + } + } + + private static String getErrorContent(Exception e) { + int errorCode = GeneralUtils.objectToNumber( + extractCodeFromString(e.getMessage()) + ).intValue(); + // 提取字符串中的第一个数字,最小的错误码为10000000 + return e.getClass().getName() + ":" + (errorCode >= MIN_ERROR_CODE ? errorCode : StringUtils.EMPTY); + } + + private static String extractCodeFromString(String errorMsg) { + Matcher m = P.matcher(errorMsg); + if (m.find()) { + return m.group(); + } + return StringUtils.EMPTY; + } + + private static void recordSQLDetail(String uuid) { + DBMeterFactory.getMeter().submit(uuid); + } + + private static void recordSQL(Compute once, MeasureObject measureObject) { + if (SupervisoryConfig.getInstance().isEnableMeasureSql() && once.computeSql()) { + measureObject.sqlTime(SessionLocalManager.getSqlTime()); + measureObject.sql(SessionLocalManager.getSql()); + } + } + + private static void recordMemory(Compute once, Measurable measurable, MeasureObject measureObject) { + if (SupervisoryConfig.getInstance().isEnableMeasureMemory() && once.computeMemory()) { + MeasureUnit unit = measurable.measureUnit(); + measureObject.memory(unit.measureMemory()); + } + } + + private static boolean findSessionAnnotation(Method method, Object[] args) { + Annotation[][] all = method.getParameterAnnotations(); + int len = ArrayUtils.getLength(args); + for (int i = 0; i < len; i++) { + Annotation[] current = all[i]; + for (Annotation annotation : current) { + if (annotation.annotationType().equals(Session.class)) { + SessionLocalManager.setSession( + SessionPoolManager.getSessionIDInfor(GeneralUtils.objectToString(args[i]), SessionProvider.class)); + return true; + } + } + } + return false; + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java new file mode 100644 index 0000000000..80aab8bd1d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java @@ -0,0 +1,54 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.intelli.record.ConsumePoint; +import com.fr.intelli.record.MetricRegistry; +import com.fr.intelli.record.PerformancePoint; +import com.fr.intelli.record.PerformancePointRecord; +import com.fr.stable.StringUtils; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * created by Harrison on 2022/03/07 + **/ +public class PerformancePointAdvice implements DesignerAnalyzerAdvice { + + @Advice.OnMethodEnter + public static void onMethodEnter(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self, + @Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, + @Advice.Local("startTime") Long startTime) { + + startTime = (System.currentTimeMillis()); + } + + @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.Thrown(typing = Assigner.Typing.DYNAMIC) Exception e, + @Advice.Local("startTime") Long startTime) { + + PerformancePoint point = method.getAnnotation(PerformancePoint.class); + String id = point.id(); + long endTime = System.currentTimeMillis(); + long consume = endTime - startTime; + if (self instanceof PerformancePointRecord) { + PerformancePointRecord measurable = (PerformancePointRecord) self; + List newArgs = new ArrayList(Arrays.asList(args)); + ConsumePoint consumePoint = ConsumePoint.create(id, startTime, endTime, consume, point.source()); + MetricRegistry.getMetric().submit(measurable.recordPoint(consumePoint, newArgs.toArray())); + } else { + if (StringUtils.isNotEmpty(id)) { + MetricRegistry.getMetric().submit(ConsumePoint.create(id, consume, point.source())); + } + } + } +} diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java b/designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java new file mode 100644 index 0000000000..f9ec6e21eb --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java @@ -0,0 +1,81 @@ +package com.fr.design.record.analyzer; + +import com.fr.third.net.bytebuddy.ByteBuddy; +import com.fr.third.net.bytebuddy.agent.ByteBuddyAgent; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.dynamic.loading.ClassReloadingStrategy; +import com.fr.third.net.bytebuddy.matcher.ElementMatchers; +import org.junit.Test; + +/** + * 测试一下,通过 redefine 去处理代码时 + * 相应的 advice 应该怎么写 + */ +public class BytebuddyRedefineTest { + + /** + * 测试一下是否可以直接抛出异常 + */ + @Test + public void testThrowException() { + + try { + ByteBuddyAgent.install(); + + new ByteBuddy() + .redefine(TestClass.class) + .visit(Advice.to(TestThrowExceptionAdvice.class).on(ElementMatchers.named("testPrint"))) + .make() + .load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + + TestClass testClass = new TestClass(); + testClass.testPrint(); + } catch (Throwable throwable) { + + } + } + + /** + * 测试是否可以直接传值 + */ + @Test + public void testTransferValue() { + + ByteBuddyAgent.install(); + + new ByteBuddy() + .redefine(TestClass.class) + .visit(Advice.to(TestTransferValueAdvice.class).on(ElementMatchers.named("testPrint"))) + .make() + .load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + + TestClass testClass = new TestClass(); + String print = testClass.testPrint(); + + System.out.println(TestTransferValueAdvice.intField); + System.out.println(TestTransferValueAdvice.stringField); + System.out.println(TestTransferValueAdvice.objectField); + + } + + /** + * 测试是否可以改变返回值 + */ + @Test + public void testModifyReturn() { + + ByteBuddyAgent.install(); + + new ByteBuddy() + .redefine(TestClass.class) + .visit(Advice.to(TestModifyReturnAdvice.class).on(ElementMatchers.named("testPrint"))) + .make() + .load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + + TestClass testClass = new TestClass(); + String print = testClass.testPrint(); + + System.out.println(print); + } + +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/TestClass.java b/designer-base/src/test/java/com/fr/design/record/analyzer/TestClass.java new file mode 100644 index 0000000000..e1a2761aaa --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/TestClass.java @@ -0,0 +1,11 @@ +package com.fr.design.record.analyzer; + +/** + * created by Harrison on 2022/03/04 + **/ +public class TestClass { + + public String testPrint() { + return ""; + } +} diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/TestModifyReturnAdvice.java b/designer-base/src/test/java/com/fr/design/record/analyzer/TestModifyReturnAdvice.java new file mode 100644 index 0000000000..7c2dae455a --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/TestModifyReturnAdvice.java @@ -0,0 +1,29 @@ +package com.fr.design.record.analyzer; + +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; + +/** + * created by Harrison on 2022/03/07 + **/ +public class TestModifyReturnAdvice { + + @Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class) + public static int onMethodEnter() throws Exception { + + return 0; + } + + @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) throws Exception { + + result = "[test]Modify Return Value"; + + } + +} diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/TestThrowExceptionAdvice.java b/designer-base/src/test/java/com/fr/design/record/analyzer/TestThrowExceptionAdvice.java new file mode 100644 index 0000000000..53c54c28d8 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/TestThrowExceptionAdvice.java @@ -0,0 +1,19 @@ +package com.fr.design.record.analyzer; + +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; + +/** + * created by Harrison on 2022/03/07 + **/ +public class TestThrowExceptionAdvice { + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Thrown(typing = Assigner.Typing.DYNAMIC) Exception e) throws Exception { + throw new RuntimeException("[test] throw exception in advice"); + } +} diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/TestTransferValueAdvice.java b/designer-base/src/test/java/com/fr/design/record/analyzer/TestTransferValueAdvice.java new file mode 100644 index 0000000000..fa0bf6f095 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/TestTransferValueAdvice.java @@ -0,0 +1,37 @@ +package com.fr.design.record.analyzer; + +import com.fr.third.net.bytebuddy.asm.Advice; + +/** + * created by Harrison on 2022/03/07 + **/ +public class TestTransferValueAdvice { + + public static int intField; + + public static String stringField; + + public static Object objectField; + + @Advice.OnMethodEnter + public static void onMethodEnter(@Advice.Local("int") int intField, + @Advice.Local("string") String stringField, + @Advice.Local("Object") Object objectField) { + + intField = 10; + stringField = "[test]stringField"; + objectField = "[test]objectField"; + } + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.Local("int") int intField, + @Advice.Local("string") String stringField, + @Advice.Local("Object") Object objectField) throws Exception { + + TestTransferValueAdvice.intField = intField; + TestTransferValueAdvice.stringField = stringField; + TestTransferValueAdvice.objectField = objectField; + + } + +} diff --git a/designer-realize/src/main/java/com/fr/start/MainDesigner.java b/designer-realize/src/main/java/com/fr/start/MainDesigner.java index ce355076ba..5d4055fbca 100644 --- a/designer-realize/src/main/java/com/fr/start/MainDesigner.java +++ b/designer-realize/src/main/java/com/fr/start/MainDesigner.java @@ -136,6 +136,8 @@ public class MainDesigner extends BaseDesigner { } FineLoggerFactory.getLogger().info("Designer started.Time used {} ms", watch.getTime()); watch.stop(); + + } /**