java - Spring AOP自定义注解,使用注解参数获取Null

标签 java spring spring-boot annotations spring-aop

我使用这个自定义注释来记录执行时间,注释可以出现在所有公共(public)方法都具有它的方法或类上。一切正常,除非方法级别“LogExecutionTime logExecutionTime”为空。这会引发 NPE。

@Around("@annotation(logExecutionTime) || @within(logExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
    final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());

    final String name = joinPoint.toShortString();
    final StopWatch stopWatch = new StopWatch(name);

    stopWatch.start(name);
    try {
      return joinPoint.proceed();

    } finally {
      stopWatch.stop();
      if (logExecutionTime.value()) {
        logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeSeconds());
      }
    }
  }

如果我颠倒顺序-

@Around("@within(logExecutionTime) || @annotation(logExecutionTime)")

行为相反,我在方法级别得到一个有效的对象,在类级别带注释的方法上得到 null。

我通过使用 2 个显式方法并将两者分开来解决这个问题 -

@Around("@within(logExecutionTime)")
public Object logExecutionTimeClassLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
    return logExecutionTimeMethodLevel(joinPoint, logExecutionTime);
  }

@Around("@annotation(logExecutionTime)")
public Object logExecutionTimeMethodLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
    final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());

    final String name = joinPoint.toShortString();
    final StopWatch stopWatch = new StopWatch(name);

    stopWatch.start(name);
    try {
      return joinPoint.proceed();

    } finally {
      stopWatch.stop();
      if (logExecutionTime.value()) {
        logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeMillis());
      }
    }

当我们使用 OR '||' 时,希望理解这种行为有两个切入点。

类(class)级别

@LogExecutionTime
@Component
public class CleanUpService implements ICleanUpService { ... }

方法级别

@Scheduled(fixedDelay = 100)
@LogExecutionTime(false)
public void processMessageQueue() { ... }

最佳答案

我来运行你的示例,并重现与你的示例相同的示例,当涉及到运行时表达式时,它同样很奇怪,因为当你在类级别指定注释并编写此表达式时

@Around(" @within(logExecutionTime) || @annotation(logExecutionTime) ")

对于您的类,切入点将评估为 true(如果您注释其在 joinPoint.getTarget().getClass().getAnnotations() 中可用,)

现在,当涉及到绑定(bind)变量时,编译器会检查所有表示绑定(bind)的表达式 @within(logExecutionTime)变量 logExecutionTime 和 @annotation(logExecutionTime) 对于同一个变量,如果该方法没有注释,它将为 null,=> 覆盖初始 with,这会导致您提到的所有情况。

尝试输入此表达式 @within(logExecutionTime) || @annotation(logExecutionTime) || @within(logExecutionTime) 你会得到变量 not null 这证明了我最后所说的 @within(logExecutionTime)覆盖先例

这里的关键是,用于选择切入点匹配的逻辑在上下文绑定(bind)时并不相同

现在,当谈到 AOP 切入点时,你必须小心并遵循他们提到的 Spring 团队的最佳实践 here以避免奇怪的运行时结果

干杯

关于java - Spring AOP自定义注解,使用注解参数获取Null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48678593/

相关文章:

java - 通过代理使用 mySql 重新连接后抛出由 : java. sql.SQLException : Callable statements not supported. 引起的

java - MQ 最大连接数问题

java - 将 ObjectMapper 注入(inject) Spring Kafka 序列化器/反序列化器

java - 简单的 jdbcTemplate.query() 应该返回一个列表,但不是

java 根据键列表从 immutablemap 获取排序值

java - Spring LockRegistry : when to call LockRegistry. 获取()

java - 如何获取公共(public)类中注入(inject)的bean的值

java - 在 Spring-WS 中支持 SOAP 1.1 和 SOAP 1.2 消息

java - JAVA 中 "ABC-1234"的正则表达式验证

java - Struts 2.s :property. 如何获取名称作为参数传递给jsp的变量的值?