gpt4 book ai didi

java - 注释为的类或子类的方面

转载 作者:行者123 更新时间:2023-12-02 13:34:11 25 4
gpt4 key购买 nike

我希望能够跟踪使用 @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>

最佳答案

正如我在评论中所说,我必须推测:

  • 它从您的确切切入点(您没有显示)开始
  • 然后继续问您是使用 Spring AOP 还是通过 LTW(加载时编织)使用完整的 AspectJ。
    • 在前一种情况下,您无需解释您的目标类是否是实际的 Spring beans,因为 Spring AOP 只能代理 Spring beans/组件。
    • 在后一种情况下,您有更多选择,但必须以不同的方式配置您的应用程序。
  • 您也不会显示自己的注释的实现,尤其是当它具有所需的运行时保留时。

我现在的假设是

  • 您使用基于代理的 Spring AOP 并且
  • 所有类和方面都是 @Component 或在您的配置中声明为 Spring bean。

但是为了向您展示会发生什么,我将使用带有 AspectJ 的独立 Java 示例,而不是 Spring 应用程序。我只将 spring-web.jarsprint-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 可以拦截给定切入点的一些连接点,但根据 documentation Spring AOP 都不支持 callstaticinitialization。 .

所以要么你需要切换到 AspectJ with LTW或者设计另一个切入点策略。

要继续,我必须在这里中断回答一段时间,因为我有一个约会,但稍后会添加更多信息。

<小时/>

更新: 好的,这是您的问题和解决方案:@within(de.scrum_master.app.LooseController) 使用 @LooseController 查看类内部 注解,但您尝试拦截的带注解方法的父类没有该注解。因此,@within() 不是适合您的切入点类型。您想要表达的是实例,即调用该方法的当前目标对象,属于带注释的类。因此,您需要一个 @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() 是那里受支持的切入点类型。

关于java - 注释为的类或子类的方面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43092745/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com