使用@AfterReturning spring aop时缺少参数

t5fffqht  于 2024-01-05  发布在  Spring
关注(0)|答案(1)|浏览(128)

编辑以提供MCVE。

  1. @Target(ElementType.PARAMETER)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface Random {
  4. }
  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface Audited {
  4. }
  1. @Target(ElementType.PARAMETER)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface Tester {
  4. }
  1. package spring;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
  6. @Slf4j
  7. @SpringBootApplication
  8. public class springLoader extends SpringBootServletInitializer {
  9. public static final Class<springLoader> CLASS = springLoader.class;
  10. public static void main(String[] args) {
  11. try (final var context = SpringApplication.run(CLASS, args)) {
  12. while(true){
  13. Thread.sleep(1000*60*60*24);
  14. }
  15. } catch (InterruptedException e) {
  16. throw new RuntimeException(e);
  17. }
  18. }
  19. }
  1. package spring;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.web.bind.annotation.GetMapping;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. @Slf4j
  9. @RestController
  10. @RequestMapping("/Inventory")
  11. public class springRest {
  12. private List<String> info;
  13. public springRest() {
  14. final var strArr = new String[]{"1234", "2345", "3456", "4567", "5678"};
  15. info = new ArrayList<>();
  16. info.addAll(List.of(strArr));
  17. }
  18. @Audited
  19. @GetMapping()
  20. public List<String> getInfo(@Tester String permittedValues, @Random String randomValues) {
  21. log.info("permitted {}", permittedValues);
  22. log.info("random: {}", randomValues);
  23. List<String> returnedValues = new ArrayList<>();
  24. for (final var str : info) {
  25. if (permittedValues.contains(str) || randomValues.contains(str)) {
  26. log.info("{}", str);
  27. returnedValues.add(str);
  28. } else {
  29. log.info("Not permitted: {}", str);
  30. }
  31. }
  32. return returnedValues;
  33. }
  34. }
  1. package spring;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.aspectj.lang.JoinPoint;
  4. import org.aspectj.lang.annotation.AfterReturning;
  5. import org.aspectj.lang.annotation.AfterThrowing;
  6. import org.aspectj.lang.annotation.Aspect;
  7. import org.aspectj.lang.reflect.MethodSignature;
  8. import org.springframework.stereotype.Component;
  9. import java.time.LocalDate;
  10. import java.time.LocalTime;
  11. import java.util.Arrays;
  12. import java.util.LinkedHashMap;
  13. import java.util.Map;
  14. import java.util.stream.Collectors;
  15. @Component
  16. @Aspect
  17. @Slf4j
  18. public class AuditAspect {
  19. @AfterReturning("@annotation(spring.Audited)")
  20. public void afterReturning(JoinPoint joinPoint) {
  21. auditHelper(joinPoint, null);
  22. }
  23. @AfterThrowing(pointcut = "@annotation(spring.Audited)", throwing = "ex")
  24. public void handleException(JoinPoint joinPoint, Exception ex) {
  25. // This advice will be executed if an exception occurs.
  26. auditHelper(joinPoint, ex);
  27. }
  28. private void auditHelper(JoinPoint joinPoint, Exception ex) {
  29. final var date = LocalDate.now();
  30. final var time = LocalTime.now();
  31. final var method = ((MethodSignature) joinPoint.getSignature()).getMethod();
  32. final var methodname = method.getName();
  33. final var args = joinPoint.getArgs();
  34. final var arguments = Arrays.stream(args).map(Object::toString).collect(Collectors.joining(" | "));
  35. final var base = "accessed " + methodname + " with arguments: " + arguments;
  36. final var statement = (ex == null) ? base : base + " but failed: " + ex.getMessage();
  37. final Map<String, Object> linkedMap = new LinkedHashMap<>();
  38. linkedMap.put("Time", time);
  39. linkedMap.put("Date", date);
  40. linkedMap.put("Log", statement);
  41. log.info(statement);
  42. }
  43. }
  1. package spring;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import org.aspectj.lang.annotation.Around;
  4. import org.aspectj.lang.annotation.Aspect;
  5. import org.aspectj.lang.reflect.MethodSignature;
  6. import org.springframework.stereotype.Component;
  7. import java.lang.annotation.Annotation;
  8. import java.util.ArrayList;
  9. import java.util.Collections;
  10. import java.util.List;
  11. @Component
  12. @Aspect
  13. public class TesterAspect {
  14. private String[] permittedValues = new String[]{"1234", "2345"};
  15. private List<String> randomValues = new ArrayList<>(List.of("1234", "2345", "3456", "4567","5678"));
  16. @Around("execution(* *(.., @spring.Tester (*), ..))")
  17. public Object permittedValues(ProceedingJoinPoint pjp) throws Throwable {
  18. final var args = pjp.getArgs();
  19. final var annotations = ((MethodSignature) pjp.getSignature()).getMethod().getParameterAnnotations();
  20. for (int i = 0; i < args.length; i++) {
  21. for (Annotation annotation : annotations[i]) {
  22. if (annotation.annotationType() == Tester.class) {
  23. args[i] = String.join(",", permittedValues);
  24. }
  25. }
  26. }
  27. Object result = pjp.proceed(args);
  28. return result;
  29. }
  30. @Around("execution(* *(.., @spring.Random (*), ..))")
  31. public Object randomValues(ProceedingJoinPoint pjp) throws Throwable {
  32. final var args = pjp.getArgs();
  33. final var annotations = ((MethodSignature) pjp.getSignature()).getMethod().getParameterAnnotations();
  34. for (int i = 0; i < args.length; i++) {
  35. for (Annotation annotation : annotations[i]) {
  36. if (annotation.annotationType() == Random.class) {
  37. Collections.shuffle(randomValues);
  38. args[i] = randomValues.get(0)+","+randomValues.get(1);
  39. }
  40. }
  41. }
  42. Object result = pjp.proceed(args);
  43. return result;
  44. }
  45. }

下面的代码模拟了我遇到的错误。我在参数级别上为GetMapping添加了两个注解,在方法级别上添加了一个注解。两个Around方面被执行,并且在GetMapping方法中,修改后的参数被正确地注销。但是,在@AfterReturning或@AfterThrowing方面方法中,其中一个参数为null。我通过键入localhost访问了GetMapping:8080/库存到谷歌Chrome。
IDE上的堆栈跟踪为:

  1. 2023-12-06 11:39:14.938 INFO 7905 --- [nio-8080-exec-1] s.springRest : permitted 1234,2345
  2. 2023-12-06 11:46:17.851 INFO 8067 --- [nio-8080-exec-1] s.springRest : random: 3456,5678
  3. 2023-12-06 11:46:17.851 INFO 8067 --- [nio-8080-exec-1] s.springRest : 1234
  4. 2023-12-06 11:46:17.851 INFO 8067 --- [nio-8080-exec-1] s.springRest : 2345
  5. 2023-12-06 11:46:17.851 INFO 8067 --- [nio-8080-exec-1] s.springRest : 3456
  6. 2023-12-06 11:46:17.852 INFO 8067 --- [nio-8080-exec-1] s.springRest : Not permitted: 4567
  7. 2023-12-06 11:46:17.852 INFO 8067 --- [nio-8080-exec-1] s.springRest : 5678
  8. 2023-12-06 11:39:14.942 ERROR 7905 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
  9. java.lang.NullPointerException: null
  10. at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[?:?]
  11. at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) ~[?:?]
  12. at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[?:?]
  13. at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[?:?]
  14. at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[?:?]
  15. at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
  16. at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[?:?]
  17. at spring.AuditAspect.auditHelper(AuditAspect.java:41) ~[classes/:?]
  18. at spring.AuditAspect.afterReturning(AuditAspect.java:24) ~[classes/:?]
  19. at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
  20. at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
  21. at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
  22. at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
  23. at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634) ~[spring-aop-5.3.24.jar:5.3.24]
  24. at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:617) ~[spring-aop-5.3.24.jar:5.3.24]
  25. at org.springframework.aop.aspectj.AspectJAfterReturningAdvice.afterReturning(AspectJAfterReturningAdvice.java:66) ~[spring-aop-5.3.24.jar:5.3.24]
  26. at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:58) ~[spring-aop-5.3.24.jar:5.3.24]
  27. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) ~[spring-aop-5.3.24.jar:5.3.24]
  28. at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.24.jar:5.3.24]
  29. at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.24.jar:5.3.24]
  30. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.24.jar:5.3.24]
  31. at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.24.jar:5.3.24]
  32. at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.24.jar:5.3.24]
  33. at spring.springRest$$EnhancerBySpringCGLIB$$1d14e293.getInfo(<generated>) ~[classes/:?]
  34. at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
  35. at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
  36. at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
  37. at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
  38. at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.24.jar:5.3.24]
  39. at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.24.jar:5.3.24]
  40. at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.24.jar:5.3.24]
  41. at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.24.jar:5.3.24]
  42. at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.24.jar:5.3.24]
  43. at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.24.jar:5.3.24]
  44. at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071) ~[spring-webmvc-5.3.24.jar:5.3.24]
  45. at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964) ~[spring-webmvc-5.3.24.jar:5.3.24]
  46. at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.24.jar:5.3.24]
  47. at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.24.jar:5.3.24]
  48. at javax.servlet.http.HttpServlet.service(HttpServlet.java:670) ~[tomcat-embed-core-9.0.70.jar:4.0.FR]
  49. at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.24.jar:5.3.24]
  50. at javax.servlet.http.HttpServlet.service(HttpServlet.java:779) ~[tomcat-embed-core-9.0.70.jar:4.0.FR]
  51. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
  52. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
  53. at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.70.jar:9.0.70]
  54. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
  55. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
  56. at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.24.jar:5.3.24]
  57. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.24.jar:5.3.24]
  58. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
  59. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
  60. at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.24.jar:5.3.24]
  61. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.24.jar:5.3.24]
  62. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
  63. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
  64. at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.24.jar:5.3.24]
  65. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.24.jar:5.3.24]
  66. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
  67. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
  68. at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177) [tomcat-embed-core-9.0.70.jar:9.0.70]
  69. at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.70.jar:9.0.70]
  70. at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.70.jar:9.0.70]
  71. at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.70.jar:9.0.70]
  72. at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.70.jar:9.0.70]
  73. at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.70.jar:9.0.70]
  74. at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) [tomcat-embed-core-9.0.70.jar:9.0.70]
  75. at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) [tomcat-embed-core-9.0.70.jar:9.0.70]
  76. at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.70.jar:9.0.70]
  77. at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:891) [tomcat-embed-core-9.0.70.jar:9.0.70]
  78. at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1784) [tomcat-embed-core-9.0.70.jar:9.0.70]
  79. at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.70.jar:9.0.70]
  80. at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.70.jar:9.0.70]
  81. at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.70.jar:9.0.70]
  82. at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.70.jar:9.0.70]
  83. at java.lang.Thread.run(Thread.java:840) [?:?]


使用的pom.xml如下,但分发管理模糊。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>org.example</groupId>
  7. <artifactId>demo</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <properties>
  10. <maven.compiler.source>17</maven.compiler.source>
  11. <maven.compiler.target>17</maven.compiler.target>
  12. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13. </properties>
  14. <dependencies>
  15. <dependency>
  16. <groupId>org.springframework</groupId>
  17. <artifactId>spring-web</artifactId>
  18. <version>5.3.24</version>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-web</artifactId>
  23. <version>2.7.7</version>
  24. <exclusions>
  25. <exclusion>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-logging</artifactId>
  28. </exclusion>
  29. </exclusions>
  30. </dependency>
  31. <dependency>
  32. <groupId>org.springframework.boot</groupId>
  33. <artifactId>spring-boot-starter-data-jpa</artifactId>
  34. <version>2.7.7</version>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-starter-log4j2</artifactId>
  39. <version>2.7.7</version>
  40. <exclusions>
  41. <exclusion>
  42. <groupId>org.apache.logging.log4j</groupId>
  43. <artifactId>log4j-slf4j-impl</artifactId>
  44. </exclusion>
  45. </exclusions>
  46. </dependency>
  47. <dependency>
  48. <groupId>org.apache.logging.log4j</groupId>
  49. <artifactId>log4j-slf4j2-impl</artifactId>
  50. <version>2.20.0</version>
  51. </dependency>
  52. <dependency>
  53. <groupId>org.apache.logging.log4j</groupId>
  54. <artifactId>log4j-api</artifactId>
  55. <version>2.20.0</version>
  56. </dependency>
  57. <dependency>
  58. <groupId>org.apache.logging.log4j</groupId>
  59. <artifactId>log4j-core</artifactId>
  60. <version>2.20.0</version>
  61. </dependency>
  62. <dependency>
  63. <groupId>org.projectlombok</groupId>
  64. <artifactId>lombok</artifactId>
  65. <version>1.18.24</version>
  66. <scope>compile</scope>
  67. </dependency>
  68. <dependency>
  69. <groupId>javax.xml.bind</groupId>
  70. <artifactId>jaxb-api</artifactId>
  71. <version>2.4.0-b180830.0359</version>
  72. </dependency>
  73. <dependency>
  74. <groupId>com.h2database</groupId>
  75. <artifactId>h2</artifactId>
  76. <version>2.1.214</version>
  77. <scope>runtime</scope>
  78. </dependency>
  79. </dependencies>
  80. <build>
  81. <plugins>
  82. <plugin>
  83. <groupId>org.apache.maven.plugins</groupId>
  84. <artifactId>maven-surefire-plugin</artifactId>
  85. <version>2.22.2</version>
  86. </plugin>
  87. </plugins>
  88. </build>
  89. <distributionManagement>
  90. <repository>
  91. <id>nexus-es</id>
  92. <name>Internal Release Repository</name>
  93. <url>https://nexus/repository/my-docker/</url>
  94. <layout>default</layout>
  95. </repository>
  96. <snapshotRepository>
  97. <id>nexus-snapshot</id>
  98. <name>Internal Snapshot Repository</name>
  99. <url>https://nexus/repository/snapshot/</url>
  100. </snapshotRepository>
  101. </distributionManagement>
  102. </project>

dphi5xsq

dphi5xsq1#

您的错误只是发生了,因为AuditAspect::auditHelper中的代码并不期望Arrays.stream(args).map(Object::toString)可以包含null元素,但它确实包含了,这会使后续的.collect(Collectors.joining(" | "))调用脱轨。
如果将.map(Object::toString)替换为.map(o -> o == null ? "null" : o.toString()),则审计方面可以正常工作。应用程序将记录如下内容:

  1. springRest : permitted 1234,2345
  2. springRest : random: 1234,2345
  3. springRest : 1234
  4. springRest : 2345
  5. springRest : Not permitted: 3456
  6. springRest : Not permitted: 4567
  7. springRest : 5678
  8. AuditAspect : accessed getInfo with arguments: 1234,2345 | null

字符串
为什么第二个参数为null?你可能会期望它是类似于“2345,5678”的东西,因为你对Spring AOP的工作原理有一个错误的想法。虽然在两个around advice的情况下,内部的可以看到外部的输入参数变化,after通知显然不能。它看起来像是看到了传入最里面的around通知的参数,而不是后者传递给目标方法的参数。
实际上,在Spring AOP和AOP J中,继续的语义看起来是不同的。(可能已更改)参数传递到目标方法,而在原生ANOJ中,只有当它们与args绑定时才能传递更改的参数,这就不那么灵活了。当比较两者时,我实际上也很惊讶,这是不一样的,因为在许多其他方面,Spring AOP试图模仿原生AOP J。
现在关注Spring AOP,您将TesterAspect中最内层的around通知的参数传递给AuditAspect的解决方法是将after通知转换为around通知。
您还需要确保TesterAspect的方面优先级高于AuditAspect,也就是说,您将@Order(1)注解放在TesterAspect上,并将@Order(2)注解放在AuditAspect上。数字越小,优先级越高。优先级越高,意味着proceed()之前和之后的所有内容都比优先级较低的方面执行得更早。这就是您想要的,因为您想要在方法执行之后进行审计,并且在继续进行审计方面之前,tester方面应该已经完成了它的魔术,操纵它的输入参数。

  1. @Component
  2. @Aspect
  3. @Order(1)
  4. public class TesterAspect {
  5. // ...
  6. }
  1. package de.scrum_master.spring.q77576228;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.aspectj.lang.JoinPoint;
  4. import org.aspectj.lang.ProceedingJoinPoint;
  5. import org.aspectj.lang.annotation.Around;
  6. import org.aspectj.lang.annotation.Aspect;
  7. import org.aspectj.lang.reflect.MethodSignature;
  8. import org.springframework.core.annotation.Order;
  9. import org.springframework.stereotype.Component;
  10. import java.lang.reflect.Method;
  11. import java.time.LocalDate;
  12. import java.time.LocalTime;
  13. import java.util.Arrays;
  14. import java.util.LinkedHashMap;
  15. import java.util.Map;
  16. import java.util.stream.Collectors;
  17. @Component
  18. @Aspect
  19. @Slf4j
  20. @Order(2)
  21. public class AuditAspect {
  22. @Around("@annotation(Audited)")
  23. public Object auditHelper(ProceedingJoinPoint pjp) throws Throwable {
  24. try {
  25. Object result = pjp.proceed();
  26. auditHelper(pjp, null);
  27. return result;
  28. } catch (Exception e) {
  29. auditHelper(pjp, e);
  30. throw e;
  31. }
  32. }
  33. private void auditHelper(JoinPoint joinPoint, Exception ex) {
  34. LocalDate date = LocalDate.now();
  35. LocalTime time = LocalTime.now();
  36. Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
  37. String methodname = method.getName();
  38. Object[] args = joinPoint.getArgs();
  39. String arguments = Arrays.stream(args)
  40. .map(o -> o == null ? "null" : o.toString())
  41. .collect(Collectors.joining(" | "));
  42. String base = "accessed " + methodname + " with arguments: " + arguments;
  43. String statement = (ex == null) ? base : base + " but failed: " + ex.getMessage();
  44. Map<String, Object> linkedMap = new LinkedHashMap<>();
  45. linkedMap.put("Time", time);
  46. linkedMap.put("Date", date);
  47. linkedMap.put("Log", statement);
  48. log.info(statement);
  49. }
  50. }

的数据
控制台日志将更改为:

  1. springRest : permitted 1234,2345
  2. springRest : random: 1234,2345
  3. springRest : 1234
  4. springRest : 2345
  5. springRest : Not permitted: 3456
  6. springRest : Not permitted: 4567
  7. springRest : 5678
  8. AuditAspect : accessed getInfo with arguments: 1234,2345 | 1234,5678

展开查看全部

相关问题