代码之家  ›  专栏  ›  技术社区  ›  JeffNelson

有没有办法在连接点周围的AOP之前进行一次性处理,以使我的方面更具性能?

  •  1
  • JeffNelson  · 技术社区  · 7 年前

    我有个习惯 @Traceable 带有 TraceAspect 实施我们使用 @可追溯 我们希望在方法调用前后记录的方法的注释。我们刚刚添加了通过指定日志级别的功能 value 内的属性 @可追溯 (旧版本总是刚刚使用 INFO ). 我所拥有的一切都很有效,但我想知道是否有办法让它更有表现力。具体来说,检查 价值 设置为 @可追溯 对于给定的方法,如果存在某种方面上下文,则可以在应用程序启动时执行一次。

    @可追溯 注释:

    @Documented
    @Retention(RUNTIME)
    @Target(METHOD)
    public @interface Traceable {
    
        Level value() default Level.INFO;
    }
    

    现在的 跟踪光谱 impl:

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.slf4j.event.Level;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class TraceAspect {
    
        @Around("@annotation(com.collaterate.logging.Traceable)")
        public Object traceAround(ProceedingJoinPoint joinPoint) throws Throwable {
            Traceable traceable = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(Traceable.class);
            Logger classLog = LoggerFactory.getLogger(joinPoint.getSignature().getDeclaringType());
            LoggingHelper loggingHelper = getLoggingHelper(traceable, classLog);
    
            String methodName = joinPoint.getSignature().getName();
            loggingHelper.log("{}() - started", methodName);
            Object returnVal = joinPoint.proceed();
            loggingHelper.log("{}() - ended", methodName);
    
            return returnVal;
        }
    
        private LoggingHelper getLoggingHelper(Traceable traceable, Logger classLog) {
            if (Level.INFO == traceable.value() || null == traceable.value()) {
                // try to avoid the switch below... most of the time it will be INFO
                return (format, args) -> classLog.info(format, args);
            } else {
                switch (traceable.value()) {
                    case ERROR :
                        return (format, args) -> classLog.error(format, args);
                    case WARN :
                        return (format, args) -> classLog.warn(format, args);
                    case DEBUG :
                        return (format, args) -> classLog.debug(format, args);
                    case TRACE :
                        return (format, args) -> classLog.trace(format, args);
                    default :
                        return (format, args) -> classLog.info(format, args);
                }
            }
        }
    
        @FunctionalInterface
        interface LoggingHelper {
    
            void log(String format, Object... args);
    
        }
    }
    

    我唯一的另一个想法是创建多个注释(每个日志级别一个),然后 跟踪光谱 将意味着 @Around 我们避免了运行时的反射/切换。我不喜欢的是我们已经在使用现有的 @可追溯 注释多个项目中的所有生产代码。我希望保留1注释,并允许它通过属性指定日志级别。

    理论上,我想做的应该是可能的,因为所有的信息都在应用程序启动时,当代理创建。每个带注释的方法都必须有某种上下文。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Indra Basak    7 年前

    我做了一些类似于wrt的度量。您可以使用维护日志注册表 class and method pair 作为 钥匙 LoggingHelper 作为 价值 .

    如果类方法对在日志注册表中没有条目,则创建日志助手并将其存储在注册表中。第二次,你只需在注册表中查找。

    注册表是一个定制的Spring bean,应该自动连接到您的方面中。

    下面是一个修改的示例 TraceAspect .

    @Component
    @Aspect
    public class TraceAspect {
    
        private LogRegistry registry;
    
        @Autowired
        public TraceAspect(LogRegistry registry) {
            this.registry = registry;
        }
    
        @Around("@annotation(com.collaterate.logging.Traceable)")
        public Object traceAround(ProceedingJoinPoint joinPoint) throws Throwable {
            String loggerName = joinPoint.getSignature()
               .getDeclaringType().getCanonicalName() + "." 
                  + joinPoint.getSignature().getName();
    
            LoggingHelper loggingHelper = registry.get(loggerName);
            if (loggingHelper == null) {
                Traceable traceable = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(Traceable.class);
                Logger classLog = LoggerFactory.getLogger(joinPoint.getSignature().getDeclaringType());
                loggingHelper = getLoggingHelper(traceable, classLog);
                registry.put(loggerName, loggingHelper)
            }
    
            String methodName = joinPoint.getSignature().getName();
            loggingHelper.log("{}() - started", methodName);
            Object returnVal = joinPoint.proceed();
            loggingHelper.log("{}() - ended", methodName);
    
            return returnVal;
        }
    }