如果在 spring boot 项目中添加 @EnableTransactionManagement,则 @Aspectj 日志记录会出现问题

issue with @Aspectj logging if @EnableTransactionManagement added in sprig boot project

我尝试使用 @Aspect 记录 所有请求和响应代码 运行ning 很好并且通过简单的 spring boot 成功具有通用配置且没有任何初始化方法或数据库调用的项目。

下面的代码不工作,包括初始配置和数据库调用所需数据使用 @EnableTransactionManagement 它在使用 @Aspect 时出错,而 运行 正在我的应用程序

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class MyContextClass implements ApplicationListener<ContextRefreshedEvent>{

@Autowire
private MyServiceRepository myServiceRepo;
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
          // Added Db call
          CommonUtils.setYears(myServiceRepo.getTotalYears());
    }
}

@Aspect 日志代码

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Aspect
@Component
public class LoggingAspect {
private final Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private HttpServletResponse response;


@Pointcut("within(@org.springframework.stereotype.Repository *)"
            + " || within(@org.springframework.stereotype.Service *)"
            + " || within(@org.springframework.web.bind.annotation.RestController *)")
    public void springBeanPointcut() {
        // Method is empty as this is just a Pointcut, the implementations are in the
        // advices.
        log.info("springBeanPointcut");
    }

 /**
     * Pointcut that matches all Spring beans in the application's main packages.
     */
    @Pointcut("within(com.test.mypackage..*)")
    public void applicationPackagePointcut() {
        // Method is empty as this is just a Pointcut, the implementations are in the
        // advices.
        log.info("applicationPackagePointcut");
    }

 @Around("applicationPackagePointcut() && springBeanPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = methodSignature.getDeclaringType().getSimpleName();
        String methodName = methodSignature.getName();
        String methodParameterNames = methodSignature.getMethod().toString();
        if (request ! = null) {
            log.info(request.getRequestURL());
            log.info(request.getMethod());
        }
       if (response != null) {
            log.info(response.getRequestURL());
            log.info(response.getStatus());
        }
       final StopWatch stopWatch = new StopWatch();
       stopWatch.start();
       Object result = joinPoint.proceed();
       stopWatch.stop();
}

此代码构建成功。但是当我 运行 下面的应用程序错误显示 setYears

中的错误
2021-05-07 20:14:58 [restartedMain] ERROR o.s.boot.SpringApplication-[SpringApplication.java:856]-Application run failed
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
    at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
    at org.springframework.web.context.support.WebApplicationContextUtils.currentRequestAttributes(WebApplicationContextUtils.java:313)
    at org.springframework.web.context.support.WebApplicationContextUtils.access0(WebApplicationContextUtils.java:66)
    at org.springframework.web.context.support.WebApplicationContextUtils$RequestObjectFactory.getObject(WebApplicationContextUtils.java:329)
    at org.springframework.web.context.support.WebApplicationContextUtils$RequestObjectFactory.getObject(WebApplicationContextUtils.java:324)
    at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:292)
    at com.sun.proxy.$Proxy120.getRequestURL(Unknown Source)
    at com.opl.ans.config.utils.LoggingAspect.logAround(LoggingAspect.java:137)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)

这样做正确吗?有什么建议吗?请帮忙。

根据错误堆栈,问题是 request 实例无效。我猜想自动连接到 Aspectrequest 实例可能是陈旧的,或者更确切地说没有与当前线程关联。这意味着 request 实例不为空并且 logAround() 方法中的检查给出了意外的结果。

如果当前没有请求属性绑定到线程,

RequestContextHolder.getRequestAttributes() 将 return null。修改

if (request ! = null) { ..} 检查 if (RequestContextHolder.getRequestAttributes() ! = null) {..} 应该可以解决问题。

另外 spring boot 为您当前通过 AOP 尝试的内容提供开箱即用的解决方案。也请检查一下。