Browse Source

Pull request #8159: KERNEL-10354 bytebuddy / 加解密性能优化 @Harrison

Merge in DESIGN/design from ~HARRISON/design:feature/x to feature/x

* commit '4872caf558c2114e59371900fb99894a1d5e0324':
  无 JIRA 任务,恢复部分代码
  无 JIRA 任务,恢复部分代码
  feat: KERNEL-10354 bytebuddy / 加解密性能优化 @Harrison 加入部分 bytebuddy 相关的单元测试,帮助理解 advice 相关的功能
  feat: KERNEL-10354 bytebuddy / 加解密性能优化 @Harrison 添加单元测试
  feat: KERNEL-10354 bytebuddy / 加解密性能优化 @Harrison 1. 删掉一部分代码,精简整体逻辑
  feat: KERNEL-10354 bytebuddy / 加解密性能优化 @Harrison 1、替换 listener, 从而打印不同的逻辑 2、修复默认的 transformer 的问题。让 Designer-Analyzer 去处理默认的逻辑,而非 Fine-Analyzer 去处理
  feat: KERNEL-10354 bytebuddy / 加解密性能优化 @Harrison 防止整个 UI 堵塞,间歇性进行转换
  feat: KERNEL-10354 bytebuddy / 加解密性能优化 @Harrison 1、FineAnalyzer部分延迟启动 2、FineAnalyzer 补充单元测试 3、补充优化开关
feature/x
Harrison 3 years ago
parent
commit
f7eb6873d3
  1. 4
      designer-base/src/main/java/com/fr/design/env/LocalDesignerWorkspaceInfo.java
  2. 45
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java
  3. 131
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java
  4. 12
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerAdvice.java
  5. 23
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerListener.java
  6. 91
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAssemblyFactory.java
  7. 23
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java
  8. 33
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java
  9. 31
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java
  10. 157
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java
  11. 49
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java
  12. 36
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/TimeAdvice.java
  13. 25
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/TrackAdvice.java
  14. 83
      designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java
  15. 11
      designer-base/src/test/java/com/fr/design/record/analyzer/TestClass.java
  16. 29
      designer-base/src/test/java/com/fr/design/record/analyzer/TestModifyReturnAdvice.java
  17. 19
      designer-base/src/test/java/com/fr/design/record/analyzer/TestThrowExceptionAdvice.java
  18. 37
      designer-base/src/test/java/com/fr/design/record/analyzer/TestTransferValueAdvice.java

4
designer-base/src/main/java/com/fr/design/env/LocalDesignerWorkspaceInfo.java vendored

@ -1,8 +1,6 @@
package com.fr.design.env; package com.fr.design.env;
import com.fr.general.ComparatorUtils; import com.fr.general.ComparatorUtils;
import com.fr.general.GeneralUtils;
import com.fr.locale.InterProviderFactory;
import com.fr.stable.CoreConstants; import com.fr.stable.CoreConstants;
import com.fr.stable.StableUtils; import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
@ -10,8 +8,8 @@ import com.fr.stable.project.ProjectConstants;
import com.fr.stable.xml.XMLPrintWriter; import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLableReader; import com.fr.stable.xml.XMLableReader;
import com.fr.workspace.connect.WorkspaceConnectionInfo; import com.fr.workspace.connect.WorkspaceConnectionInfo;
import com.fr.workspace.engine.exception.MainVersionNotMatchException; import com.fr.workspace.engine.exception.MainVersionNotMatchException;
import java.io.File; import java.io.File;
import java.util.Properties; import java.util.Properties;

45
designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java

@ -0,0 +1,45 @@
package com.fr.design.record.analyzer;
import com.fr.design.record.analyzer.advice.TimeAdvice;
import com.fr.design.record.analyzer.advice.TrackAdvice;
import com.fr.record.analyzer.AnalyzerConfiguration;
import com.fr.record.analyzer.AnalyzerUnit;
import com.fr.record.analyzer.Assistant;
import com.fr.record.analyzer.Metrics;
import com.fr.record.analyzer.Track;
import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory;
import com.fr.stable.ArrayUtils;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.description.type.TypeDescription;
import com.fr.third.net.bytebuddy.dynamic.DynamicType;
import com.fr.third.net.bytebuddy.matcher.ElementMatchers;
import com.fr.third.net.bytebuddy.utility.JavaModule;
/**
* 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(DesignerAssemblyFactory.getInstance());
AnalyzerConfiguration defaultConfiguration = AnalyzerConfiguration.create(new Assistant() {
@Override
public DynamicType.Builder<?> supply(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
return builder
.visit(Advice.to(TimeAdvice.class).on(ElementMatchers.isAnnotatedWith(Metrics.class)))
.visit(Advice.to(TrackAdvice.class).on(ElementMatchers.isAnnotatedWith(Track.class)));
}
});
AnalyzerConfiguration[] allConfigurations = ArrayUtils.add(configurations, defaultConfiguration);
// 准备监听
ANALYZER.setAgentListener(new DesignerAnalyzerListener());
ANALYZER.init(redefineFactory, allConfigurations);
}
}

131
designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java

@ -0,0 +1,131 @@
package com.fr.design.record.analyzer;
import com.fr.base.OptimizeUtil;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.constants.DesignerLaunchStatus;
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.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.event.Null;
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.FineAnalyzer;
import com.fr.record.analyzer.advice.AnalyzerAdviceKey;
import com.fr.record.analyzer.advice.FineAdviceAssistant;
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(() -> {
AnalyzerAssemblyFactory basicFactory = createBasicFactory();
// 兼容逻辑
List<AnalyzerConfiguration> backwardsConfigurations = findMutableBackwards(AnalyzerKey.KEY);
if (!CollectionUtils.isEmpty(backwardsConfigurations)) {
// 直接初始化,不添加默认值,防止和下面的冲突
FineAnalyzer.initDirectly(basicFactory, backwardsConfigurations.toArray(new AnalyzerConfiguration[0]));
}
// 等页面完全打开后,再进行 retransform, 别影响了启动速度
EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, new Listener<Null>() {
@Override
public void on(Event event, Null param) {
ExecutorService es = newSingleThreadExecutor(new NamedThreadFactory("designer-analyzer", true));
try {
// 加入 retransform 部分的逻辑
List<FineAdviceAssistant> 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<FineAdviceAssistant> list) {
return list.stream()
.map(AnalyzerConfiguration::create)
.toArray(AnalyzerConfiguration[]::new);
}
@Override
public void stop() {
}
@Override
public void prepare() {
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(Focus.class),
FocusAdvice.class
));
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(Compute.class),
MonitorAdvice.class
));
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(DBMetrics.class),
DBMonitorAdvice.class
));
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(PerformancePoint.class),
PerformancePointAdvice.class
));
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(FaultTolerance.class),
FaultToleranceAdvice.class
));
}
private AnalyzerAssemblyFactory createBasicFactory() {
AnalyzerAssemblyFactory factory = findSingleton(AnalyzerAssemblyFactory.class);
FineAnalyzerAssemblyFactory basicFactory = new FineAnalyzerAssemblyFactory();
basicFactory.prepare(factory);
return basicFactory;
}
}

12
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 {
}

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

@ -0,0 +1,23 @@
package com.fr.design.record.analyzer;
import com.fr.log.FineLoggerFactory;
import com.fr.third.net.bytebuddy.agent.builder.AgentBuilder;
import com.fr.third.net.bytebuddy.description.type.TypeDescription;
import com.fr.third.net.bytebuddy.dynamic.DynamicType;
import com.fr.third.net.bytebuddy.utility.JavaModule;
/**
* created by Harrison on 2022/03/08
**/
public class DesignerAnalyzerListener extends AgentBuilder.Listener.Adapter {
@Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) {
FineLoggerFactory.getLogger().debug("Designer-Analyzer transform successfully:{}", typeDescription);
}
@Override
public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded, Throwable throwable) {
FineLoggerFactory.getLogger().error("Designer-Analyzer transform error:" + typeName);
}
}

91
designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAssemblyFactory.java

@ -0,0 +1,91 @@
package com.fr.design.record.analyzer;
import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory;
import com.fr.third.net.bytebuddy.agent.builder.AgentBuilder;
import java.util.List;
import java.util.Map;
/**
* 装配 Agent 为后置启动
* <p>必须在一个线程中处理 retransform 的事务否则会阻塞整个的线程导致效果不佳</p>
*
* created by Harrison on 2022/03/07
**/
public class DesignerAssemblyFactory implements AnalyzerAssemblyFactory<Void> {
/**
* 每次执行 1 class retransform
*/
private static final int FIXED_SIZE = 1;
/**
* 单位 ms
* 每次间隔 500 ms, 执行一次
*/
private static final int DELAY_INTERVAL = 500;
private final AgentBuilder.RedefinitionStrategy.BatchAllocator batchAllocator = AgentBuilder.RedefinitionStrategy.BatchAllocator.ForFixedSize.ofSize(FIXED_SIZE);
private final AgentBuilder.RedefinitionStrategy.Listener redefinitionListener = new DelayListener(DELAY_INTERVAL);
public static DesignerAssemblyFactory getInstance() {
return DesignerAssemblyFactoryHolder.INSTANCE;
}
private static class DesignerAssemblyFactoryHolder {
private static final DesignerAssemblyFactory INSTANCE = new DesignerAssemblyFactory();
}
@Override
public AnalyzerAssemblyFactory<Void> prepare(Void material) {
return this;
}
@Override
public AgentBuilder assembly(AgentBuilder raw) {
return raw.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
// 每次只 transform 一部分否则会导致 UI 变慢
.with(batchAllocator)
.with(redefinitionListener)
.with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE);
}
private class DelayListener implements AgentBuilder.RedefinitionStrategy.Listener {
/**
* 单位 ms
*/
private final int interval;
public DelayListener(int interval) {
this.interval = interval;
}
/**
* 执行完后等待一段时间再执行
*/
@Override
public void onBatch(int index, List<Class<?>> batch, List<Class<?>> types) {
try {
Thread.sleep(interval);
} catch (Exception ignore) {
}
}
@Override
public Iterable<? extends List<Class<?>>> onError(int index, List<Class<?>> batch, Throwable throwable, List<Class<?>> types) {
return null;
}
@Override
public void onComplete(int amount, List<Class<?>> types, Map<List<Class<?>>, Throwable> failures) {
}
}
}

23
designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java

@ -0,0 +1,23 @@
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;
/**
* created by Harrison on 2022/03/07
**/
public class DBMonitorAdvice implements DesignerAnalyzerAdvice {
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args) {
if (args.length > 1 && args[1] instanceof DataModel) {
DBMetric meter = ((DataModel) args[1]).getMetric();
DBMeterFactory.getMeter().record(meter);
}
}
}

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

@ -0,0 +1,33 @@
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() 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<Object> callable = () -> method.invoke(self, args);
result = FaultToleranceFactory.getInstance().getScene(faultTolerance.scene()).getProcessor().execute(self, callable, args);
}
}

31
designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java

@ -0,0 +1,31 @@
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.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);
}
}

157
designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java

@ -0,0 +1,157 @@
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.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.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<Object> newArgs = new ArrayList<Object>(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;
}
}

49
designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java

@ -0,0 +1,49 @@
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.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.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<Object> newArgs = new ArrayList<Object>(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()));
}
}
}
}

36
designer-base/src/main/java/com/fr/design/record/analyzer/advice/TimeAdvice.java

@ -0,0 +1,36 @@
package com.fr.design.record.analyzer.advice;
import com.fr.design.record.analyzer.DesignerAnalyzerAdvice;
import com.fr.log.FineLoggerFactory;
import com.fr.record.analyzer.Metrics;
import com.fr.third.net.bytebuddy.asm.Advice;
import java.lang.reflect.Method;
/**
* created by Harrison on 2022/03/08
**/
public class TimeAdvice implements DesignerAnalyzerAdvice {
@Advice.OnMethodEnter
public static void onMethodEnter(@Advice.Local("startTime") Long startTime) {
startTime = (System.currentTimeMillis());
}
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.Origin Method method,
@Advice.Local("startTime") Long startTime) {
Metrics metrics = method.getAnnotation(Metrics.class);
Object prefix;
String description = metrics.description();
if ("".equals(description)) {
prefix = method.getDeclaringClass().getName() + "#" + method.getName();
} else {
prefix = description;
}
FineLoggerFactory.getLogger().info("{} took {} ms.", prefix, System.currentTimeMillis() - startTime);
}
}

25
designer-base/src/main/java/com/fr/design/record/analyzer/advice/TrackAdvice.java

@ -0,0 +1,25 @@
package com.fr.design.record.analyzer.advice;
import com.fr.intelli.record.MetricRegistry;
import com.fr.third.javax.persistence.Entity;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import java.util.List;
/**
* created by Harrison on 2022/03/08
**/
public class TrackAdvice {
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) {
if (result != null) {
Class clazz = result.getClass();
if (clazz.getAnnotation(Entity.class) != null || result instanceof List) {
MetricRegistry.getMetric().submit(result);
}
}
}
}

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

@ -0,0 +1,83 @@
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.Assert;
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) {
Assert.assertNotNull("expected throw exception", 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();
Assert.assertEquals(10, TestTransferValueAdvice.intField);
Assert.assertEquals("[test]stringField", TestTransferValueAdvice.stringField);
Assert.assertEquals("[test]objectField", 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();
Assert.assertEquals("[test]Modify Return Value", print);
}
}

11
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 "";
}
}

29
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";
}
}

19
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");
}
}

37
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;
}
}
Loading…
Cancel
Save