有没有办法在围绕连接点的 AOP 之前进行一次性处理,以使我的方面性能更高?
Is there a way to do one-time processing before an AOP around joinpoint to make my aspect more performant?
我有一个带有 TraceAspect
实现的自定义 @Traceable
注释。我们在方法调用前后要记录的方法上使用 @Traceable
注释。我们刚刚添加了通过 @Traceable
中的 value
属性指定要使用的日志级别的功能(旧版本总是只使用 INFO
)。我有什么工作,但我想知道是否有办法提高它的性能。具体来说,如果存在某种方面上下文,可以在应用程序启动时检查给定方法在 @Traceable
上设置的 value
。
@Traceable
注解:
@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface Traceable {
Level value() default Level.INFO;
}
当前 TraceAspect
实现:
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);
}
}
我唯一的另一个想法是创建多个注释(每个日志级别一个),然后 TraceAspect
将为每个注释实现一个 @Around
处理程序,我们避免反射/切换在运行时。我不喜欢的是我们已经在多个项目的生产代码中使用现有的 @Traceable
注释。我想保留 1 注释并允许它通过属性指定日志级别。
理论上,我想做的应该是可能的,因为在创建代理时应用程序启动时所有信息都在那里。每个带注释的方法都必须有某种上下文。
我对指标做了类似的事情。您可以使用 class and method pair
作为 key 和 LoggingHelper
作为 value.
维护日志注册表
如果 class 方法对在日志注册表中没有条目,请创建一个日志记录助手并将其存储在注册表中。第二次,您只需在注册表中查找即可。
注册表是一个自定义 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;
}
}
我有一个带有 TraceAspect
实现的自定义 @Traceable
注释。我们在方法调用前后要记录的方法上使用 @Traceable
注释。我们刚刚添加了通过 @Traceable
中的 value
属性指定要使用的日志级别的功能(旧版本总是只使用 INFO
)。我有什么工作,但我想知道是否有办法提高它的性能。具体来说,如果存在某种方面上下文,可以在应用程序启动时检查给定方法在 @Traceable
上设置的 value
。
@Traceable
注解:
@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface Traceable {
Level value() default Level.INFO;
}
当前 TraceAspect
实现:
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);
}
}
我唯一的另一个想法是创建多个注释(每个日志级别一个),然后 TraceAspect
将为每个注释实现一个 @Around
处理程序,我们避免反射/切换在运行时。我不喜欢的是我们已经在多个项目的生产代码中使用现有的 @Traceable
注释。我想保留 1 注释并允许它通过属性指定日志级别。
理论上,我想做的应该是可能的,因为在创建代理时应用程序启动时所有信息都在那里。每个带注释的方法都必须有某种上下文。
我对指标做了类似的事情。您可以使用 class and method pair
作为 key 和 LoggingHelper
作为 value.
如果 class 方法对在日志注册表中没有条目,请创建一个日志记录助手并将其存储在注册表中。第二次,您只需在注册表中查找即可。
注册表是一个自定义 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;
}
}