class 或 subclass 的方面注释为
Aspect for class or subclass annotated with
我希望能够跟踪使用@RequestMapping 进行注释的方法,这些方法使用特定注释(例如@LooseController)进行注释。
我有两个切入点:requestMappings() 和 looseController()
如果使用@RequestMapping 注释的方法位于具有@LooseController 的class 中,但如果@LooseController 位于子class
中,则此方法效果很好
例如,当在 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>
正如我在评论中所说,我不得不推测:
- 它以您的确切切入点(您没有显示)开始
- 并继续询问您是使用 Spring AOP 还是通过 LTW(加载时织入)的完整 AspectJ。
- 在前一种情况下,您不解释您的目标 class 是否是实际的 Spring bean,因为 Spring AOP 只能代理 Spring beans/components .
- 在后一种情况下,您有更多选择,但必须以不同的方式配置您的应用程序。
- 您也不会显示您自己的注释的实现,尤其是如果它具有所需的运行时保留。
我现在的假设是
- 您使用基于代理的 Spring AOP 和
- 所有 class 元素和方面都是
@Component
或以其他方式在您的配置中声明为 Spring bean。
但是为了向您展示发生了什么,我将使用 AspectJ 的独立 Java 示例,而不是 Spring 应用程序。我只将 spring-web.jar
和 sprint-context.jar
放在我的 class 路径上,以便解析 Spring 注释。
译注:
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface LooseController {}
抽象基础class:
package de.scrum_master.app;
import org.springframework.web.bind.annotation.RequestMapping;
public abstract class PutController {
@RequestMapping("/{id}")
public void update(String id) {}
}
Subclass + 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 可以拦截给定切入点的几个连接点,但是根据 [=33],Spring AOP 不支持 call
和 staticinitialization
=].
所以要么你需要切换到 AspectJ with LTW 要么设计另一个切入点策略。
未完待续,因为我有预约,我不得不在这里打断一下回答,但稍后会添加更多信息。
更新: 好的,这是您的问题和解决方案:@within(de.scrum_master.app.LooseController)
使用 @LooseController
注释查看 classes,但是带有您要拦截的注释方法的父 class 没有该注释。因此,@within()
不是适合您的切入点类型。您想表达的是实例,即调用该方法的当前 target
对象属于带注释的 class。因此,你需要一个 @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()
是那里支持的切入点类型。
我希望能够跟踪使用@RequestMapping 进行注释的方法,这些方法使用特定注释(例如@LooseController)进行注释。
我有两个切入点:requestMappings() 和 looseController()
如果使用@RequestMapping 注释的方法位于具有@LooseController 的class 中,但如果@LooseController 位于子class
中,则此方法效果很好例如,当在 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>
正如我在评论中所说,我不得不推测:
- 它以您的确切切入点(您没有显示)开始
- 并继续询问您是使用 Spring AOP 还是通过 LTW(加载时织入)的完整 AspectJ。
- 在前一种情况下,您不解释您的目标 class 是否是实际的 Spring bean,因为 Spring AOP 只能代理 Spring beans/components .
- 在后一种情况下,您有更多选择,但必须以不同的方式配置您的应用程序。
- 您也不会显示您自己的注释的实现,尤其是如果它具有所需的运行时保留。
我现在的假设是
- 您使用基于代理的 Spring AOP 和
- 所有 class 元素和方面都是
@Component
或以其他方式在您的配置中声明为 Spring bean。
但是为了向您展示发生了什么,我将使用 AspectJ 的独立 Java 示例,而不是 Spring 应用程序。我只将 spring-web.jar
和 sprint-context.jar
放在我的 class 路径上,以便解析 Spring 注释。
译注:
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface LooseController {}
抽象基础class:
package de.scrum_master.app;
import org.springframework.web.bind.annotation.RequestMapping;
public abstract class PutController {
@RequestMapping("/{id}")
public void update(String id) {}
}
Subclass + 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 可以拦截给定切入点的几个连接点,但是根据 [=33],Spring AOP 不支持 call
和 staticinitialization
=].
所以要么你需要切换到 AspectJ with LTW 要么设计另一个切入点策略。
未完待续,因为我有预约,我不得不在这里打断一下回答,但稍后会添加更多信息。
更新: 好的,这是您的问题和解决方案:@within(de.scrum_master.app.LooseController)
使用 @LooseController
注释查看 classes,但是带有您要拦截的注释方法的父 class 没有该注释。因此,@within()
不是适合您的切入点类型。您想表达的是实例,即调用该方法的当前 target
对象属于带注释的 class。因此,你需要一个 @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()
是那里支持的切入点类型。