Spring-boot 配置Aop获取controller里的request中的参数以及其返回值

本文介绍如何在Spring Boot项目中使用AOP进行日志记录。通过定义一个切面类,实现了对所有Controller请求的统一处理,包括请求开始时记录请求参数及请求结束时输出Controller的返回值。

首先在你的Maven的pom文件里加入aop的依赖:

  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
  </dependency>

在spring boot里面一切配置都是很简单的,下面为我所有被请求到的controller加上Aop的功能吧,看码:

package me.jiaobuchong.admin.config;

import javax.servlet.http.HttpServletRequest;

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.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;;

/**
 * Created by jiaobuchong on 12/23/15.
 */
@Aspect   //定义一个切面
@Configuration
public class LogRecordAspect {
private static final Logger logger = LoggerFactory.getLogger(UserInterceptor.class);

    // 定义切点Pointcut
    @Pointcut("execution(* com.jiaobuchong.web.*Controller.*(..))")
    public void excudeService() {
    }

    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();

        String url = request.getRequestURL().toString();
        String method = request.getMethod();
        String uri = request.getRequestURI();
        String queryString = request.getQueryString();
        logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, queryString);

        // result的值就是被拦截方法的返回值
        Object result = pjp.proceed();
        Gson gson = new Gson();
        logger.info("请求结束,controller的返回值是 " + gson.toJson(result));
        return result;
    }
}

只要加上上面这个类,Aop就算配置好了,不信,去访问以下你的Controller试试。对比以前配置aop的方式(xml文件),现在的配置都到Java代码里来了,@Configuration这个Annotation就是JavaConfig的典型代表,Spring boot在启动时会会自动去加载这些配置,实现相应的配置功能。这个简单的小例子算是抛砖引玉吧,我也是参考别人的博客,更多细节,查看下面的博客:
http://ysj5125094.iteye.com/blog/2151855

Error creating bean with name 'webMvcObjectMapperConfigurer' defined in class path resource [springfox/documentation/spring/web/SpringfoxWebMvcConfiguration.class]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:628) ~[spring-beans-5.3.28.jar:5.3.28] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.28.jar:5.3.28] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.28.jar:5.3.28] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.28.jar:5.3.28] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.28.jar:5.3.28] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) ~[spring-beans-5.3.28.jar:5.3.28] at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:270) ~[spring-context-5.3.28.jar:5.3.28] at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:764) ~[spring-context-5.3.28.jar:5.3.28] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:567) ~[spring-context-5.3.28.jar:5.3.28] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.13.jar:2.7.13] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) [spring-boot-2.7.13.jar:2.7.13] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.13.jar:2.7.13] at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.7.13.jar:2.7.13] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) [spring-boot-2.7.13.jar:2.7.13] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) [spring-boot-2.7.13.jar:2.7.13] at com.hzb.ServerApplication.main(ServerApplication.java:12) [classes/:na] Caused by: java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:319) ~[aspectjweaver-1.9.7.jar:na] at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:227) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.aop.aspectj.AspectJExpressionPointcut.obtainPointcutExpression(AspectJExpressionPointcut.java:198) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:177) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:226) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:289) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:321) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:128) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:97) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:78) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:341) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:293) ~[spring-aop-5.3.28.jar:5.3.28] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:455) ~[spring-beans-5.3.28.jar:5.3.28] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1808) ~[spring-beans-5.3.28.jar:5.3.28] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) ~[spring-beans-5.3.28.jar:5.3.28] ... 15 common frames omitted
最新发布
06-25
<think>我们正在处理一个SpringBoot应用启动时出现的Bean创建失败问题,具体错误是:Errorcreatingbeanwithname'webMvcObjectMapperConfigurer'causedbyjava.lang.IllegalArgumentException:errorat::0formalunboundinpointcut根据引用[1]到[5]的信息,这个错误通常与AOP切点表达式的编写有关。错误信息“formalunboundinpointcut”意味着在切点表达式中使用了未绑定的形式参数。例如,在切点表达式中我们可能引用了通知方法中的参数,但在切点表达式中没有正确地绑定这些参数。从引用[2]中我们可以看到,在配置AOP时,如果在切点表达式中使用了`args`来指定参数,那么这些参数必须在通知方法中声明,并且顺序和类型要匹配。引用[3]和[4]则指出,在使用注解配置AOP时,如果通知方法中声明了参数(比如`JoinPoint`和返回值等),那么切点表达式中必须通过`returning`或`throwing`等属性来绑定,并且表达式中的参数名必须与通知方法中的参数名一致。具体到我们的错误,错误发生在名为`webMvcObjectMapperConfigurer`的Bean上,这可能是Springfox(Swagger的Spring集成库)中的一个配置类。Springfox使用AOP来生成API文档,因此可能是其切面配置出了问题。根据引用[5]中的示例,我们注意到在`@AfterReturning`注解中,我们使用了`returning`属性来指定返回值参数名(例如`returning="result"`),并且在通知方法中有一个对应的参数`Objectresult`。如果切点表达式没有正确绑定这个参数,就会报错。**解决方案步骤:**1.**检查切点表达式**:查看与`webMvcObjectMapperConfigurer`相关的切点表达式,特别是使用了`args`的地方。确保在切点表达式中引用的参数在通知方法中都有对应的参数,并且通过`args`、`returning`或`throwing`进行了绑定。2.**检查通知方法参数**:确保通知方法中声明的参数在切点表达式中被正确引用。例如,如果通知方法中有一个`JoinPoint`参数,那么它不需要在切点表达式中绑定;但如果有一个返回值参数,则必须在`@AfterReturning`注解中使用`returning`属性绑定,并且属性值必须与参数名一致。3.**检查Springfox配置**:由于错误发生在Springfox的Bean上,我们需要检查Springfox的配置。在SpringBoot中,我们通常通过`Docket`来配置Springfox。但是,这个错误可能不是由我们的显式配置引起的,而是Springfox内部的切面配置。因此,我们需要考虑Springfox版本是否与当前SpringBoot版本兼容。4.**升级或降级Springfox版本**:有时候,版本不兼容会导致这样的问题。尝试升级到最新的Springfox版本,或者查看Springfox的issue列表是否有类似问题。5.**避免使用有问题的切点表达式**:如果确认是Springfox内部的问题,并且没有可用的修复版本,我们可以尝试通过排除有问题的自动配置类来绕过。但这样做可能会影响Swagger的功能。**具体到我们的错误信息:**错误信息指向`webMvcObjectMapperConfigurer`,这是Springfox中的一个配置类,用于配置ObjectMapper。根据错误,可能是这个配置类被AOP代理了,并且在代理过程中切点表达式有问题。由于我们没有提供具体的切点表达式,我们可以参考引用[2]和[4]中的例子,检查类似下面的表达式:```xml<aop:pointcutexpression="execution(*com.example..*.*(..))andargs(request,response)".../>```或者注解方式:```java@Pointcut("execution(*com.example..*.*(..))&&args(request,response)")publicvoidpointcutName(HttpServletRequestrequest,HttpServletResponseresponse){}```在注解方式中,切点方法中的参数`request`和`response`必须与切点表达式中的`args(request,response)`绑定。如果通知方法中使用了这些参数,那么它们必须被声明。**在我们的场景中,可能Springfox内部的某个切点表达式使用了类似`args`的绑定,但实际通知方法中没有对应的参数,或者参数名不匹配。****临时解决方案:**由于我们无法直接修改Springfox的代码,我们可以尝试以下方法:1.**排除有问题的自动配置**:在`@SpringBootApplication`注解中排除相关的自动配置类。但是,这可能会使Swagger不可用。```java@SpringBootApplication(exclude={SpringfoxWebMvcConfiguration.class})```2.**升级Springfox**:检查当前使用的Springfox版本,尝试升级到最新版本(如3.0.0)或与当前SpringBoot兼容的版本。3.**改用Springdoc**:如果问题无法解决,考虑使用Springdoc替代Springfox,Springdoc是另一个Swagger的SpringBoot集成库,支持OpenAPI3。**结论:**这个错误是由于AOP切点表达式中的形式参数未绑定导致的。具体到Springfox,可能是其内部的切面配置存在问题。建议先尝试升级Springfox版本,如果问题依旧,考虑改用Springdoc。§§相关问题§§1.如何解决SpringAOP中“formalunboundinpointcut”的错误?2.SpringBoot中如何配置Springfox(Swagger)?3.如何排除SpringBoot中的特定自动配置类?4.SpringBoot中如何将Swagger从Springfox迁移到Springdoc?</think>### 解决 Spring BootSpringfox 配置导致的切面表达式错误 您的错误 `Error creating bean with name 'webMvcObjectMapperConfigurer' caused by java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut` 是 Spring AOP 配置中常见的切点表达式绑定问题,核心原因是 **切点表达式中的参数未在通知方法中正确声明或绑定**。以下是逐步解决方案: --- ### 原因分析 1. **参数绑定不匹配** 切点表达式(如 `args(request,response)`)中声明的参数未在通知方法参数列表中匹配,或未通过 `returning/throwing` 属性显式绑定[^2][^4]。 2. **Springfox 的特定问题** `webMvcObjectMapperConfigurer` 是 Springfox 内部组件,其 AOP 配置可能因以下原因失败: - 表达式使用了未声明的形式参数(如 `args(...)` 中变量未绑定) - 通知方法中缺少 `JoinPoint` 或返回值参数声明 - 切点表达式语法错误(如使用 JDK 代理而非 CGLIB) --- ### 解决方案 #### ✅ 步骤 1:检查切点表达式语法 在 Springfox 配置类中(通常为 `SwaggerConfig.java`),确保: ```java @Configuration @EnableSwagger2 public class SwaggerConfig { // 修复点 1:移除未绑定的 args 表达式 @Pointcut("execution(* com.example.controller.*.*(..))") // ✅ 正确:无未绑定参数 public void apiPointcut() {} } ``` **关键点**: - 删除 `and args(...)` 这类未绑定参数的表达式[^2][^4] - 若需参数,需在通知方法中声明并绑定(见步骤 2) #### ✅ 步骤 2:显式绑定通知方法参数 若切点需使用参数,按以下格式声明通知方法: ```java @Aspect @Component public class LogAspect { // 绑定返回值示例 @AfterReturning( pointcut = "apiPointcut()", returning = "result" // ✅ 显式绑定 ) public void logResult(JoinPoint jp, Object result) { // 方法参数需包含 returning 声明的变量 } } ``` **必须匹配**: 1. `returning = "result"` 中的变量名 `result` 2. 方法参数中的 `Object result`(类型可调整)[^3][^5] #### ✅ 步骤 3:强制使用 CGLIB 代理 在 `application.properties` 中添加: ```properties spring.aop.proxy-target-class=true # 强制使用 CGLIB ``` 或在 XML 中配置: ```xml <aop:config proxy-target-class="true"/> <!-- 解决 JDK 代理问题 --> ``` #### ✅ 步骤 4:验证 Springfox 兼容性 检查依赖兼容性(Spring Boot 2.x 推荐): ```gradle dependencies { implementation 'io.springfox:springfox-boot-starter:3.0.0' implementation 'io.springfox:springfox-swagger2:3.0.0' implementation 'io.springfox:springfox-swagger-ui:3.0.0' } ``` **注意**: - Springfox 3.x 需 Java 8+ 和 Spring 5.x[^1] - 旧版 Spring Boot 可降级 Springfox 至 `2.9.2` --- ### 备选方案:迁移到 Springdoc 若问题持续,改用 **Springdoc**(支持 OpenAPI 3): 1. 移除 Springfox 依赖 2. 添加 Springdoc: ```gradle implementation 'org.springdoc:springdoc-openapi-ui:1.6.9' ``` 3. 配置 Swagger: ```java @Configuration public class OpenApiConfig { @Bean public OpenAPI customOpenAPI() { return new OpenAPI().info(new Info().title("API Docs")); } } ``` --- ### 总结 | 问题根源 | 解决措施 | |------------------------|----------------------------------| | 切点表达式未绑定参数 | 移除 `args(...)` 或显式绑定参数 | | 通知方法参数缺失 | 添加 `returning/throwing` 绑定 | | 代理模式冲突 | 强制使用 `proxy-target-class=true` | | Springfox 版本不兼容 | 升级至 3.x 或改用 Springdoc | > 根据 Spring 官方文档,AOP 配置中形式参数必须通过 `args()` 或通知注解属性显式绑定到切点表达式,否则会抛出 `IllegalArgumentException`[^3][^4]。
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值