为什么 AOP 日志记录在我的项目中不起作用

Why is AOP Logging not working in my project

我现在在 AOP 日志设置上浪费了很多时间。 我不知道为什么 AOP 在我的项目中不起作用。 我想我已经完成了所有我能做的设置。 如果你们有解决方案,请告诉我。 谢谢。

@EnableAspectJAutoProxy
@SpringBootApplication
@ComponentScan(basePackages = "com.demo.apiservice")
@MapperScan("com.demo.apiservice.mapper")
public class ApiServiceApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
      return builder.sources(ApiServiceApplication.class);
    }

    public static void main(String[] args) {
      SpringApplication.run(ApiServiceApplication.class, args);
    }

    @Bean
    public ModelMapper modelMapper() {
       return new CustmizedModelMapper();
    }

    @Bean
    public AopLoggingConfig loggingAspect(){
       return new AopLoggingConfig();
    }
}

以下应该有效:

package com.demo.apiservice.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopLoggingConfig {

    Logger logger =  LoggerFactory.getLogger(AopLoggingConfig.class);

    static String name = "";

    static String type = "";

    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    public void controllerClassMethods() {}

    @Around("controllerClassMethods()")
    public Object logPrint(ProceedingJoinPoint joinPoint) throws Throwable {
        type = joinPoint.getSignature().getDeclaringTypeName();

        if (type.indexOf("Controller")  -1) {
            name = "Controller  \t:  ";
        }
        else if (type.indexOf("Service")  -1) {
            name = "ServiceImpl  \t:  ";
        }
        else if (type.indexOf("DAO")  -1) {
            name = "DAO  \t\t:  ";
        }
        logger.debug(name + type + ".@@@@@@@@@@@@@@@@@@@@@@@@@ " + joinPoint.getSignature().getName() + "()");
        return joinPoint.proceed();
    }
}

这将匹配所有 类 中用 @RestController 注释的所有方法。

你的方面被触发了。我添加了一个显式控制器方法调用以检查:

  public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(ApiServiceApplication.class, args);
    context.getBean(CustomerController.class).retrieveAll();
  }

然后我修正了您代码中的一些拼写错误,就像我之前评论中提到的那样。

您的问题可能是您没有看到日志输出,因为您忘记了应用程序包的日志配置 com.demo.apiservice:

logging:
  level:
    org:
      springframework.web: DEBUG
      hibernate: DEBUG
    com:
      atoz_develop:
        mybatissample:
          repository: TRACE
      demo.apiservice: DEBUG

顺便说一句,我还将您的错字 hibernat 更正为 hibernate,但这与手头的问题无关。

然后我在日志中看到了这个:

[  restartedMain] o.s.b.w.e.t.TomcatWebServer              : Tomcat started on port(s): 8080 (http) with context path ''
[  restartedMain] c.d.a.ApiServiceApplication              : Started ApiServiceApplication in 5.101 seconds (JVM running for 6.117)
[  restartedMain] c.d.a.c.AopLoggingConfig                 : Controller     :  com.demo.apiservice.customer.CustomerController.@@@@@@@@@@@@@@@@@@@@@@@@@ retrieveAll()
[  restartedMain] c.d.a.c.AopLoggingConfig                 : Controller     :  com.demo.apiservice.customer.CustomerController.@@@@@@@@@@@@@@@@@@@@@@@@@ retrieveAll()
[  restartedMain] c.d.a.c.CustomerController               : Start of CustomerController::retrieveAll method

你看到问题了吗?您会得到重复的日志记录,因为方面被组件扫描拾取一次,并在您的应用程序配置中再次实例化为一个 bean。所以你需要ApiServiceApplication中删除这部分:

  @Bean
  public AopLoggingConfig loggingAspect() {
    return new AopLoggingConfig();
  }

现在重复的日志记录消失了。

接下来,也许您想稍微简化一下方面并简单地记录 joinPointjoinPoint.getSignature()。您还希望创建 nametype 局部变量,因为静态字段不是线程安全的。相反,您可能需要方面的静态记录器。

@Component
@Aspect
public class AopLoggingConfig {
  private static Logger logger = LoggerFactory.getLogger(AopLoggingConfig.class);

  @Around("execution(* com.demo.apiservice.customer.*Controller.*(..))")
  public Object logPrint(ProceedingJoinPoint joinPoint) throws Throwable {
    String type = joinPoint.getSignature().getDeclaringTypeName();
    String name = "";

    if (type.contains("Controller")) {
      name = "Controller  \t:  ";
    }
    else if (type.contains("Service")) {
      name = "ServiceImpl  \t:  ";
    }
    else if (type.contains("DAO")) {
      name = "DAO  \t\t:  ";
    }

    logger.debug(name + joinPoint.getSignature());
    return joinPoint.proceed();
  }
}

日志行变为:

Controller      :  ResponseEntity com.demo.apiservice.customer.CustomerController.retrieveAll()

但实际上,包名和class名称都表明我们正在与控制器、DAO 或服务打交道。那么,为什么首先要为 if-else 的东西烦恼呢?为什么把简单的事情弄复杂,让事情变慢?此外,如果你只想记录一些东西而不影响控制流、方法参数或 return 值,一个简单的 @Before 建议就可以了,昂贵的 @Around 是不必要的。

@Component
@Aspect
public class AopLoggingConfig {
  private static Logger logger = LoggerFactory.getLogger(AopLoggingConfig.class);

  @Before("execution(* com.demo.apiservice.customer.*Controller.*(..))")
  public void logPrint(JoinPoint joinPoint) {
    logger.debug(joinPoint.getSignature().toString());
  }
}

日志行变为:

ResponseEntity com.demo.apiservice.customer.CustomerController.retrieveAll()

这还不够吗?

或者更简单:

    logger.debug(joinPoint.toString());

日志:

execution(ResponseEntity com.demo.apiservice.customer.CustomerController.retrieveAll())

保持简单!