如果在 Spring Boot 项目中添加了 @EnableTransactionManagement,则 @Aspectj 日志记录问题
Posted
技术标签:
【中文标题】如果在 Spring Boot 项目中添加了 @EnableTransactionManagement,则 @Aspectj 日志记录问题【英文标题】:issue with @Aspectj logging if @EnableTransactionManagement added in sprig boot project 【发布时间】:2021-07-29 22:05:41 【问题描述】:我尝试使用@Aspect
来记录所有请求和响应代码运行良好且成功通过一个简单的spring boot
项目具有通用配置并且没有任何初始化方法或数据库调用.
下面的代码不起作用,其中包括初始化配置和 DB 调用所需的数据使用 @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.access$400(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)
这是正确的方法吗?有什么建议吗?请帮忙。
【问题讨论】:
在logAround()
建议中,将条件修改为 RequestContextHolder.getRequestAttributes() != null
而不是 request != null
。在控件返回之前记录response
也是不正确的方法。
看看HTTP Tracing和Spring MVC Metrics。
如果您没有其他问题并且问题已解决,我可以更新答案,您可以关闭问题
【参考方案1】:
根据错误堆栈,问题是request
实例无效。我猜想自动连接到Aspect
的request
实例可能是陈旧的,或者与当前线程无关。这意味着request
实例不为空,并且logAround()
方法中的检查给出了意外的结果。
如果当前没有请求属性绑定到线程,RequestContextHolder.getRequestAttributes() 将返回 null
。修改
if (request ! = null) ..
与if (RequestContextHolder.getRequestAttributes() ! = null) ..
核对应该可以解决问题。
Spring Boot 还为您当前通过 AOP 尝试的解决方案提供了开箱即用的解决方案。也请检查一下。
HTTP Tracing Spring MVC Metrics【讨论】:
此解决方案有效,但如果我从 DB 进行事务处理,则会出现 1 个问题,我的实体类会为@ToString
lombok ```java.lang.***Error: null at java.lang.Long 引发错误。 toString(Long.java:396) 在 java.lang.Long.toString(Long.java:1032) 在 java.lang.String.valueOf(String.java:2994) 在 java.lang.StringBuilder.append(StringBuilder.java :131) ```
请转至this answer
我没有意识到您将我的答案标记为不是答案。您当前的问题与 lombok 相关,与 Aspect 或我分享的解决方案无关。
好的,我会将其标记为已完成,并为此 Lombok 相关问题创建另一个谢谢
np。您的问题的解决方案是排除我分享的答案中指出的 toString() 。祝你好运以上是关于如果在 Spring Boot 项目中添加了 @EnableTransactionManagement,则 @Aspectj 日志记录问题的主要内容,如果未能解决你的问题,请参考以下文章
在 Spring boot 中添加超过 65535 个条目的 jar