当前位置: 首页 > 知识库问答 >
问题:

停止用aspectj捕获Jparepository方法

有凯泽
2023-03-14

如果程序员返回的是Arraylist而不是List,我会尝试生成一个警告。我使用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() + ".");
                }

            }
        }

    }

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

共有1个答案

班承恩
2023-03-14

首先,list.class.isAssignableFrom(clazz)对于ListArrayList都是真的,也就是说,您不能像这样区分这两者。顺便说一句,returnvalue.getclass()永远不会计算为list,因为这是一种接口类型。它将始终根据实际的实现类进行计算,例如ArrayList。因此,你试图通过反思找出你想知道的东西的人为方式注定要失败。

好消息是: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..*(..))

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

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

它意味着:对于de.fhb或其子包中的所有类,根据其方法签名拦截返回列表+的所有方法(+意味着:列表或其子类型)。因为这也会匹配返回父类型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();
    }
}
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可以做得更多。为什么不在编译过程中抛出警告甚至错误,即在软件打包和部署之前?您的开发团队可以在bug进入生产代码之前修复它们。为此,请使用@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中,它如下所示:

 类似资料:
  • 我在一个名为seedrecord的对象和一个名为FielliateLink的对象之间有一个manytomany关系。为了删除FielliateLink,我需要首先从每个SeedRecord的FielliateList中删除对它的引用。之后,我使用spring JParepository的delete方法删除对象。因为我的服务(FiniliateLinkService)中有不同的删除方法,所以我决定

  • 我想在try块中捕获PyCharm的stop信号(当stop被按下时),但是我不知道这个信号是什么或者如何在代码中捕获它。JetBrains在他们的文档中没有提供这方面的见解。 我尝试将其捕获为,但它似乎根本不是异常。 这在编程上是完全可以捕获的吗?

  • 问题内容: 我有一个文件需要读取,打印出整数,捕获异常并继续显示下一个整数,依此类推,直到不再有整数。 该文件包含:12 5 sd 67 4 cy 我希望它显示: 12 5 输入错误 67 4 输入错误 但是,它只给我12、5,后面是输入错误,然后停止。我尝试将所有内容放入while循环中,并且由于输入异常而无休止地循环。 我缺少什么,以便循环继续读取下一个int,依此类推? 问题答案: try

  • 为了在生产环境中启动我的Spring Boot应用程序,我的公司有一个执行“java-jar”的系统,我试图在我的Intellij思想中模拟它,并且jar可以正确启动,我也可以用proyect源代码进行调试。 在运行和调试模式下,当我单击stop按钮时,jar突然停止,并显示消息: 并且我无法捕获关闭事件来关闭我的DB连接。我尝试了其他stackoverflow解决方案,如在Main中运行的Spr

  • 我正在寻找一种方法来停止/杀死线程,我看到Thread.stop()已被弃用。所以我开始寻找另一个解决方案,并看到多个帖子建议这样做: 但这不会阻止我的线程,我的线程看起来像这样: 有人得到我可以用来停止/杀死我的线程的解决方案吗?非常感谢任何帮助。

  • 当我从测试类调用functions方法时,我希望executeSol方法不要运行,因为它会导致错误。