gpt4 book ai didi

java - 停止使用aspectj捕获Jparepository方法

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

如果程序员返回 Arraylist 而不是列表,我会尝试生成警告。我使用Spring Boot、Spring Data JPA。

Pojo 示例

@Entity
public class Box {

@Id
@GeneratedValue
private long id;

private long prio;


public long getPrio() {
return prio;
}

public void setPrio(long prio) {
this.prio = prio;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

}

我的存储库:

@Repository
public interface BoxRepository extends JpaRepository<Box, Long>{

public List findByPrio(long prio);
}

现在我的方面:

@Aspect
@Component
public class ReturnList {

@AfterReturning(value = "within(de.fhb.*) && !within(org.springframework.*) && call(* de.fhb..*(..))", returning = "returnValue")
public void logServiceAccess(JoinPoint joinPoint, Object returnValue) {

if (returnValue != null) {
if (returnValue.getClass() != null) {

Class<?> clazz = returnValue.getClass();

if (java.util.List.class.isAssignableFrom(clazz)) {
System.out
.println("Please use List instead of a concrete implementation ( "+ returnValue.getClass() + " ) for method: "
+ joinPoint.getSignature().getName() + ".");
}

}
}

}

}

我的问题

看起来 spring data(jpa 存储库)正在返回一个 Arraylist。我不想从 jpa 存储库捕获方法,我排除了 org.springframework,但如果我运行类似以下行的内容,仍然会触发该方面:

System.out.println(boxRepository.findByPrio(1));

任何会停止触发方面调用 spring jparepository 方法的提示吗?

完整代码:https://github.com/svenhornberg/MDSD

最佳答案

首先,List.class.isAssignableFrom(clazz) 对于 ListArrayList 都是正确的,即你无法区分两人之间就这样。顺便说一句,returnValue.getClass()永远计算为List,因为这是一个接口(interface)类型。它将总是计算为实际的实现类,例如ArrayList。所以你试图通过反射(reflection)找出你想知道的东西的人为方式无论如何都是注定要失败的。

好消息是:AspectJ 使您能够做您想做的事情。您似乎通过加载或编译时编织使用真正的 AspectJ,否则您无法使用 call() 切入点,因为它在 Spring AOP 中不可用。 编辑:是的,您的 Gradle 构建显示您正在使用编译时编织。但是,嘿,为什么您要使用当前版本 1.8.4 中的编译器,而使用严重过时的 1.5.4 版本中的 AspectJ 运行时呢?您应该协调两者,并在版本 1.8.4 中使用 aspectjrt

现在让我们解构你的切入点:

within(de.fhb.*) &&
!within(org.springframework.*) &&
call(* de.fhb..*(..))

这意味着:拦截对 de.fhb 或其​​子包(..* 表示法)中定义的任何方法的调用,但前提是这些调用也是从类中进行的在 de.fhb 中定义,但不在子包中定义(.* 表示法)。 !within(org.springframework.*) 部分是多余的,因为 de.fhb.* 中定义的代码永远不可能来自 org.springframework.* 同时。这没有任何意义。

您可能真正想要的是找出在您自己的包中是否有方法返回具体类型,例如ArrayList,而不是接口(interface)类型List。正确的?我认为切入点应该是这样的:

within(de.fhb..*) &&
execution(java.util.List+ *(..)) &&
!execution(java.util.List *(..))

这意味着:对于 de.fhb 或其​​子包中的所有类,拦截所有返回 List+ 的方法(+ 的意思是: List 或其子类型)根据其方法签名。因为这也将匹配返回父类型 List 的方法,并且您只需要子类型,所以您必须通过 !execution(java.util.List * (..)).

我匹配方法执行而不是调用,因为这样更有效。如果从包中的 100 个位置调用一个方法,call() 会将方面代码编织到 100 个调用连接点中,而 execution() 实际上只是编织该方法实际所在的位置已定义。

这里是一些示例代码:

驱动程序应用程序:

您会看到,有一种方法正确声明(根据您的意愿)List 返回类型,而其他方法则声明“禁止”返回类型,例如 ArrayListLinkedListVector

package de.fhb.app;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

public class Application {
public static List<String> methodReturningList() {
return new ArrayList<String>();
}

public static ArrayList<String> methodReturningArrayList() {
return new ArrayList<String>();
}

public static LinkedList<String> methodReturningLinkedList() {
return new LinkedList<String>();
}

public static Vector<String> methodReturningVector() {
return new Vector<String>();
}

public static void main(String[] args) {
methodReturningList();
methodReturningArrayList();
methodReturningLinkedList();
methodReturningVector();
}
}

类型检查方面,变体 A(运行时检查):

package de.fhb.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class ReturnTypeChecker {
@AfterReturning("within(de.fhb..*) && execution(java.util.List+ *(..)) && !execution(java.util.List *(..))")
public void logServiceAccess(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}

控制台输出:

execution(ArrayList de.fhb.app.Application.methodReturningArrayList())
execution(LinkedList de.fhb.app.Application.methodReturningLinkedList())
execution(Vector de.fhb.app.Application.methodReturningVector())

正如您所看到的,您准确地截获了那些根据您的定义有问题的方法。

类型检查方面,变体 B(编译时检查):

但是 AspectJ 可以做得更多。为什么不在编译期间(即在软件打包和部署之前)抛出警告甚至错误?您的开发团队可以在错误进入生产代码之前修复它们。为此,请使用 @DeclareWarning@DeclareError:

package de.fhb.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareError;

@Aspect
public class ReturnTypeChecker {
@DeclareError("within(de.fhb..*) && execution(java.util.List+ *(..)) && !execution(java.util.List *(..))")
private static final String typeWarning = "Please do not declare methods returning concrete subclasses of List";
}

现在您将在控制台上看到编译错误。在 Eclipse 中它看起来像这样:

Eclipse compilation errors

关于java - 停止使用aspectj捕获Jparepository方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27250261/

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