我希望能够跟踪使用某个注释注释的@RequestMapping所覆盖的方法(例如@LooseController)。
我有两个切入点:requestMappings()和looseController()
如果使用@RequestMapping注释的方法位于具有@LooseController的类中,但是如果@LooseController位于子类中,则该方法很有效
例如,当在Controller1上调用update(id)时,它不会被此方面捕获
更新以包含更多信息:
package de.scrum_master.app;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
private static void requestMapping() {}
@Pointcut("@within(de.scrum_master.app.LooseController)")
private static void looseController() {}
// @Pointcut("@this(de.scrum_master.app.LooseController)")
// private static void looseController() {}
@Before("requestMapping() && looseController()")
public void myAdvice(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
package de.scrum_master.app;
import org.springframework.web.bind.annotation.RequestMapping;
//@LooseController
public abstract class PutController {
@RequestMapping("/{id}")
public void update(String id) {
}
}
package de.scrum_master.app;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface LooseController {
}
package de.scrum_master.app;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
@Component
@LooseController
@RequestMapping("/something")
public class Controller1 extends PutController {
}
package de.scrum_master.app;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class AspectApplication implements CommandLineRunner {
@Autowired
private Controller1 controller1;
@Autowired
private ConfigurableApplicationContext context;
public static void main(String[] args) {
SpringApplication.run(AspectApplication.class, "--logging.level.root=WARN", "--spring.main.banner-mode=off");
}
@Override
public void run(String... strings) throws Exception {
controller1.update("test");
context.close();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>aspects</groupId>
<artifactId>aspects</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
</project>
答案 0 :(得分:1)
正如我在评论中所说,我必须推测:
我现在的假设是
@Component
或在配置中声明为Spring bean。但是为了向您展示会发生什么,我将使用AspectJ的独立Java示例,而不是Spring应用程序。我只将spring-web.jar
和sprint-context.jar
放在我的类路径上,以便解析Spring注释。
<强>注释:强>
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface LooseController {}
抽象基类:
package de.scrum_master.app;
import org.springframework.web.bind.annotation.RequestMapping;
public abstract class PutController {
@RequestMapping("/{id}")
public void update(String id) {}
}
子类+ main
方法:
package de.scrum_master.app;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
@Component
@LooseController
@RequestMapping("/something")
public class Controller1 extends PutController {
public static void main(String[] args) {
new Controller1().update("foo");
}
}
我猜您可能会使用的方面:
请注意,您自己的切入点within(@blabla.LooseController)
在语法上无效,因此我将其更改为@within(blabla.LooseController)
。
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
private static void requestMapping() {}
@Pointcut("@within(de.scrum_master.app.LooseController)")
private static void looseController() {}
@Before("requestMapping() && looseController()")
public void myAdvice(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
运行Controller1.main
时的控制台日志:
staticinitialization(de.scrum_master.app.Controller1.<clinit>)
call(void de.scrum_master.app.Controller1.update(String))
现在您看到了问题:AspectJ可以拦截给定切入点的几个连接点,但Spring AOP根据documentation不支持call
和staticinitialization
。
因此,您需要切换到AspectJ with LTW或设计另一个切入点策略。
要继续,我必须在这里打断答案一段时间,因为我有预约,但稍后会再添加一些信息。
更新:好的,这是您的问题和解决方案:@within(de.scrum_master.app.LooseController)
查看带有@LooseController
注释的类,但是您正在尝试使用带注释方法的父类拦截没有那个注释。因此,@within()
不是适合您的切入点类型。您想要表达的是实例,即调用该方法的当前target
对象,属于带注释的类。因此,您需要@target()
切入点:
@Pointcut("@target(de.scrum_master.app.LooseController)")
private static void looseController() {}
或者您也可以使用此解决方法(有点难看,但也有效):
@Pointcut("target(@de.scrum_master.app.LooseController Object)")
private static void looseController() {}
现在控制台日志显示:
execution(void de.scrum_master.app.PutController.update(String))
这也适用于Spring AOP,因为execution()
是支持的切入点类型。