gpt4 book ai didi

spring - 使用 AspectJ LTW 在非公共(public)方法的自调用和相关注意事项上允许 spring 代理功能

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

我见过许多与 @Cacheable 相关的 Spring 功能示例。 , @Transactional , @Async等,每次都重复相同的选项:

  • 通过 ApplicationContext.getBean(MyService.class) 获得的代理对象进行的自我调用或自动接线MyService.class @Scope(proxyMode=ScopedProxyMode.TARGET_CLASS) 之外的代理对象,
  • 将目标方法重定位到单独的 @Service类(class),
  • 使用 AspectJ 加载时编织。

  • 虽然前两种方法通常很好,但有时我们需要将上述三个(和其他)注释的功能附加到私有(private)方法,无论是出于代码清晰、设计还是其他原因。

    前两种方法的例子很多,但最后一种方法很少。据我了解,由于 AspectJ LTW 的性质,默认情况下它与启用 @Cacheable 的常见 Spring AOP 行为互斥。等行为没有太多麻烦。我的问题如下:
  • 是否有任何关于启用上述行为的体面示例,通常使用 AspectJ LTW 使用前两个选项来完成?
  • 有没有办法选择性地启用 AspectJ LTW,例如不适用于 @Async@Transactional但只是 @Cacheable ?这种情况的一个示例用例可能是:由于团队的设计,所有可缓存的方法(其中一些可能是私有(private)的)都应该位于一个外观类中,该类调用执行大量计算的私有(private)方法,但可能会更新某些状态(即'last-queried-at: #' ) 在返回到外部调用之前。

  • 这个问题是从一个 spring-boot 的角度来看的。用户,但我相信它通常适用于 Spring AOP 和 AspectJ LTW。如果在这种情况下需要特殊考虑,请纠正我。

    最佳答案

    1. Are there any decent examples on enabling the above behavior usually done with the first two options using AspectJ LTW?


    我的 GitHub 帐户上有几个 AspectJ 示例。这两个示例都显示了如何拦截 内的调用。相同的目标对象 (自调用)并拦截 私有(private)方法 .
  • Spring Boot Source Weaving Example with AspectJ
  • Spring Boot Load-Time Weaving Example with AspectJ

  • 这两个示例都相似,只是将方面编织到目标类中的方式不同。

    请阅读示例的自述文件以了解有关每种编织类型以及如何使用每个示例的更多信息。

    1. Is there a way to enable AspectJ LTW selectively, e.g. not for @Async and @Transactional but just @Cacheable?


    是的,您可以根据以下任一条件进行过滤:
  • 通过调用者方法的注解类型。
    @Before("call(* com.basaki.service.UselessService.sayHello(..))" +
    " && cflow(@annotation(trx))")
    public void inspectMethod(JoinPoint jp,
    JoinPoint.EnclosingStaticPart esjp, Transactional trx) {
    log.info(
    "Entering FilterCallerAnnotationAspect.inspectMethod() in class "
    + jp.getSignature().getDeclaringTypeName()
    + " - method: " + jp.getSignature().getName());
    }
  • 通过调用方方法的名称。
    @Before("call(* com.basaki.service.UselessService.sayHello(..))" +
    " && cflow(execution(* com.basaki.service.BookService.read(..)))")
    public void inspectMethod(JoinPoint jp,
    JoinPoint.EnclosingStaticPart esjp) {
    log.info(
    "Entering FilterCallerMethodAspect.inspectMethod() in class "
    + jp.getSignature().getDeclaringTypeName()
    + " - method: " + jp.getSignature().getName());
    }

  • 您可以找到工作示例 here .

    更新

    Q. Do I understand correctly then, that if I wanted to enable compile-time weaving for transactionality, I would: 1. No longer use a TransactionAwareDataSourceProxy anywhere in my DataSource configuration; 2. Add the following to my application: @EnableTransactionManagement(mode=AdviceMode.ASPECTJ).



    Spring AOP 和 CTW/LTW AspectJ 编织是完全正交的,即它们彼此独立。
  • 编译 LTW 修改实际的字节码,即将代码行插入到目标对象的方法体中。
  • AOP 是基于代理的,即目标对象周围有一个包装器。对目标对象的任何调用都会被 Spring 包装器对象拦截。如果需要,您还可以将 Spring AOP 与 CTW/LTW 一起使用。在这种情况下,Spring AOP 将对修改后的目标进行代理。

  • 您将需要 @EnableTransactionManagement如果要启用 Spring 的注解驱动事务管理功能。

    Q. In your examples, I see that you do not start the application in any special way for CTW. Would this suffice, or have I missed anything?



    是的,在 CTW 中,您在启动期间不需要任何特殊的东西,因为额外的字节码已经在编译期间由 AspectJ 编译器 ( ajc) 注入(inject)到原始代码中。例如,这里是原始源代码:
    @CustomAnnotation(description = "Validates book request.")
    private Book validateRequest(BookRequest request) {
    log.info("Validating book request!");

    Assert.notNull(request, "Book request cannot be empty!");
    Assert.notNull(request.getTitle(), "Book title cannot be missing!");
    Assert.notNull(request.getAuthor(), "Book author cannot be missing!");

    Book entity = new Book();
    entity.setTitle(request.getTitle());
    entity.setAuthor(request.getAuthor());

    return entity;
    }

    这是 AspectJ 编译器编译后的同一段代码, ajc :
    private Book validateRequest(BookRequest request) {
    JoinPoint var3 = Factory.makeJP(ajc$tjp_0, this, this, request);
    CustomAnnotationAspect var10000 = CustomAnnotationAspect.aspectOf();
    Annotation var10002 = ajc$anno$0;
    if (ajc$anno$0 == null) {
    var10002 = ajc$anno$0 = BookService.class.getDeclaredMethod("validateRequest", BookRequest.class).getAnnotation(CustomAnnotation.class);
    }

    var10000.inspectMethod(var3, (CustomAnnotation)var10002);

    log.info("Validating book request!");
    Assert.notNull(request, "Book request cannot be empty!");
    Assert.notNull(request.getTitle(), "Book title cannot be missing!");
    Assert.notNull(request.getAuthor(), "Book author cannot be missing!");

    Book entity = new Book();
    entity.setTitle(request.getTitle());
    entity.setAuthor(request.getAuthor());
    return entity;
    }

    在 LTW 中,您需要 Java 代理,因为代码在加载时被修改,即当 Java 类加载器加载类时。

    关于spring - 使用 AspectJ LTW 在非公共(public)方法的自调用和相关注意事项上允许 spring 代理功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48492162/

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