【问题标题】:Spring AOP Doesn't Apply on Methods with Generic Type Return ValuesSpring AOP 不适用于具有泛型类型返回值的方法
【发布时间】:2020-06-13 21:27:34
【问题描述】:

编辑:已解决,因为开头的双星号,我从书中复制了它:Spring Microservices in Action。

我正在尝试建议一些控制器方法。

这是方面类:

@Aspect
public class PBLogger {

    @Pointcut("execution(** com.sunwell.product..*.*(..))")
    public void standardMethod() {
    }

    @Around("standardMethod()")
    public Object log(ProceedingJoinPoint jp) {
           ...
    }

...
}

这是目标方法,我已经确定包名是正确的。

这个不起作用(不调用建议方法):

@RequestMapping(value = "resources/items", method = RequestMethod.GET,
                    produces = "application/json"
            )
public ResponseEntity<Map<String,Object>> getItems(
                    @RequestHeader(value="Authorization", required = false) String _auth, @RequestParam(value="systemId", required = false) Integer _i ) throws Exception 
{ ... }

没有通用返回类型,它可以工作:

@RequestMapping(value = "resources/items", method = RequestMethod.GET,
                        produces = "application/json"
                )
public void getItems(@RequestHeader(value="Authorization", required = false) String _auth, @RequestParam(value="systemId", required = false) Integer _i ) throws Exception 
{ ... }

它也可以使用带注释的切入点而不是执行

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Example
{
    public String msg();
}

@Aspect
public class PBLogger {


        @Pointcut("@annotation(Example)")
        public void standardMethod() {
        }

        @Around("standardMethod()")
        public Object log(ProceedingJoinPoint jp) {
           ...
        }

    ...
}

//target method:
        @RequestMapping(value = "resources/items", method = RequestMethod.GET,
                    produces = "application/json"
            )
        @Example
public ResponseEntity<Map<String,Object>> getItems(
                    @RequestHeader(value="Authorization", required = false) String _auth, @RequestParam(value="systemId", required = false) Integer _ ) throws Exception 
{ ... }

【问题讨论】:

  • getItems() 方法之间有很大的不同。首先,一个有参数和返回类型,第二个没有。请分享确切的代码。
  • @dassum 抱歉,我已经编辑了第二个 getItems 方法。参数和返回值都可以,只要它们不是通用的。
  • @Mideel ,这个问题留下了很多东西让其他人猜测和回答。如果可以共享有效/有问题的确切代码,我们将很容易为您提供帮助。
  • 实际上我查看了“Spring Microservices in Action”,但那里甚至没有提到 AOP。所以我不认为你有你的** 从那里。但我在“Spring in Action”中多次发现这种奇怪的语法。
  • 实际上我查看了“Spring Microservices in Action”,但那里甚至没有提到 AOP。所以我不认为你有你的** 从那里。但是我在 “Spring in Action” 中多次发现这种奇怪的语法 - 不幸的是,特别是在第 4 章中,源代码 ZIP 不包含任何内容。这真是倒霉:书中的代码错误 + 缺少那一章的源代码。

标签: spring spring-boot aop spring-aop


【解决方案1】:

目标方法签名不是问题,泛型与否。看我的MCVE

目标类:

请注意,您不能将这两种方法放在同一个类中,因为它们具有相同的类型擦除。编译器会抱怨这个。

package de.scrum_master.spring.q60474362;

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Map;

@Component
public class MyTargetClass {
  @RequestMapping(
    value = "resources/items", method = RequestMethod.GET,
    produces = "application/json"
  )
  public ResponseEntity<Map<String, Object>> getItems(
    @RequestHeader(value = "Authorization", required = false) String _auth,
    @RequestParam(value = "systemId", required = false) Integer _i
  ) throws Exception
  {
    System.out.println("MyTargetClass.getItems");
    return null;
  }
}
package de.scrum_master.spring.q60474362;

import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Component
public class MyOtherTargetClass {
  @RequestMapping(
    value = "resources/items", method = RequestMethod.GET,
    produces = "application/json"
  )
  public void getItems(
    @RequestHeader(value = "Authorization", required = false) String _auth,
    @RequestParam(value = "systemId", required = false) Integer _i
  ) throws Exception
  {
    System.out.println("MyOtherTargetClass.getItems");
  }
}

方面:

请注意,您的示例切入点中的** 没有意义,我将其更改为使用*。如果** 有效,那么您很幸运,语法检查并不严格,但我的 IDE 实际上会抱怨。此外,你真的不需要my.package..*.*(..),如果类名和方法名都不重要,my.package..*(..) 就足够了。

package de.scrum_master.spring.q60474362;

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.stereotype.Component;

@Aspect
@Component
public class PBLogger {
  @Pointcut("execution(* de.scrum_master.spring..*(..))")
  public void standardMethod() {}

  @Around("standardMethod()")
  public Object log(ProceedingJoinPoint jp) throws Throwable {
    System.out.println(jp);
    return jp.proceed();
  }
}

Spring驱动应用&配置:

package de.scrum_master.spring.q60474362;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class Application {
  public static void main(String[] args) throws Exception {
    try (ConfigurableApplicationContext appContext = SpringApplication.run(Application.class, args)) {
      doStuff(appContext);
    }
  }

  private static void doStuff(ConfigurableApplicationContext appContext) throws Exception {
    MyTargetClass myTargetClass = appContext.getBean(MyTargetClass.class);
    myTargetClass.getItems("x", 11);
    MyOtherTargetClass myOtherTargetClass = appContext.getBean(MyOtherTargetClass.class);
    myOtherTargetClass.getItems("y", 22);
  }
}

控制台日志:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.2.RELEASE)

(...)
2020-03-02 09:00:49.712  INFO 24028 --- [           main] d.s.spring.q60474362.Application         : Started Application in 3.554 seconds (JVM running for 5.157)
execution(ResponseEntity de.scrum_master.spring.q60474362.MyTargetClass.getItems(String,Integer))
MyTargetClass.getItems
execution(void de.scrum_master.spring.q60474362.MyOtherTargetClass.getItems(String,Integer))
MyOtherTargetClass.getItems
(...)

如果它对您不起作用,那么您还有其他一些问题,例如有问题的目标类没有被组件扫描拾取,例如由于忘记了@Component 注释或其他原因。

【讨论】:

  • 谢谢,这是因为开头的双星号,在我删除双星号后才起作用,但我在某处读到**表示任何方法访问说明符以及任何返回类型。跨度>
  • 无论你在哪里读到,都是假的。此外,您介意接受答案吗?
猜你喜欢
  • 2020-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-24
  • 1970-01-01
相关资源
最近更新 更多