有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用byte buddy或某些库进行java评测

我正在尝试构建一个查询日志分析器,它计算每个查询的执行时间,并在查询需要更多时间时记录日志。 与包装器相比,使用AspectJ需要更多的时间。因此,如果有性能改进的余地,我想使用byte buddy或其他库

下面是我当前使用AspectJ的实现

@Aspect
public class QueryLoggerProfiler {
    private static final Logger LOGGER = Logger.getLogger(QueryLoggerProfiler.class.getName());

    public static final String QUERY_LOGGING_POINTCUT = "execution(* com.abc.PreparedStatement.execute*(..))";

    @
    Pointcut(QUERY_LOGGING_POINTCUT)
    private void queryPointcut() {}

    @
    Around("queryPointcut()")
    public Object profile(ProceedingJoinPoint joinPoint) throws Throwable {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        long start = System.currentTimeMillis();
        Object output = joinPoint.proceed();
        long elapsedTime = System.currentTimeMillis() - start;
        if (elapsedTime >= 5) {
            LOGGER.info(">>>>>>>>>>>>>>>>>>>... Going to call the method ... " + method.getName());
            LOGGER.info(">>>>>>>>>>>>>>>>>>>... With parameter ... " + method.getParameters());
            LOGGER.info(">>>>>>>>>>>>>>>>>>>... Method execution time: " + elapsedTime + " milliseconds.");
        }
        return output;
    }
}

在没有性能瓶颈的情况下,是否有办法记录日志


共 (2) 个答案

  1. # 1 楼答案

    实际上我的代码如下

    public static void premain(String agentArgument, Instrumentation instrumentation) {
        System.out.println(">>>>>>>>>>>>>>>>>> Entered premain");
        try {
            new AgentBuilder.Default()
                    .type(ElementMatchers.nameStartsWith("com.mycomp.hikari.LoggingPreparedStatement"))
                    .transform((builder, typeDescription, classLoader) -> builder
                            .method(ElementMatchers.any())
                            .intercept(MethodDelegation.to(new Interceptor())))
                    .installOn(instrumentation);
        } catch (RuntimeException e) {
            System.out.println(">>>>>>>>>>>>>>>>>> Exception instrumenting code : " + e);
            e.printStackTrace();
        }
    }
    

    然后将拦截器分类为

    public class Interceptor {
    @RuntimeType
    public Object intercept(@SuperCall Callable<?> callable, @AllArguments Object[] allArguments, @Origin Method method, @Origin Class clazz) throws Exception {
        long startTime = System.currentTimeMillis();
        Object response;
        try {
            response = callable.call();
        } catch (Exception e) {
            System.out.println(">>>>>>>>>>>>>>>>>>>> .... Exception occurred in method call: " + methodName(clazz, method, allArguments) + " Exception = " + e);
            throw e;
        } finally {
            long elapsedTime = System.currentTimeMillis() - startTime;
            if (elapsedTime > 3)
            System.out.println(">>>>>>>>>>>>>>>>>>>> .... Method " + methodName(clazz, method, allArguments) + " completed in " + elapsedTime + " milliseconds");
        }
        return response;
    }
    
    private String methodName(Class clazz, Method method, Object[] allArguments) {
        StringBuilder builder = new StringBuilder();
        builder.append(clazz.getName());
        builder.append(".");
        builder.append(method.getName());
        builder.append("(");
        for (int i = 0; i < method.getParameters().length; i++) {
    
            builder.append(method.getParameters()[i].getName());
            if (allArguments != null) {
                Object arg = allArguments[i];
                builder.append("=");
                builder.append(arg != null ? arg.toString() : "null");
            }
    
            if (i < method.getParameters().length - 1) {
                builder.append(", ");
            }
        }
        builder.append(")");
        return builder.toString();
      }
    }
    
  2. # 2 楼答案

    最简单的方法是将Advice组件与AgentBuilder组件一起使用。这将允许您定义类似以下内容的代理:

    public static void premain(String arg, Instrumentation inst) {
      new AgentBuilder.Default()
        .type(named("com.abc.PreparedStatement"))
        .transform(new Transformer() {
          public DynamicType.Builder transform(DynamicType.Builder builder) {
           return builder.visit(Advice.to(MyAdvice.class).on(nameStartsWith("execute")));
         } 
        }).installOn(inst);
    }
    

    这将为指定的类型和名称应用MyAdvice类中定义的方法。查看javadoc for Advice以了解如何获取参数或如何指定要调用的方法

    有关如何使用Byte Buddy和JavaAgent插入代码的一般信息,请参见this article