首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否可以排除AspectJ中的字段集?

是否可以排除AspectJ中的字段集?
EN

Stack Overflow用户
提问于 2020-10-30 16:04:34
回答 1查看 407关注 0票数 1

是否有可能排除AspectJ切入点中的fiel集,从而使Java11中的最终字段不会出现故障?

在编织以下方面时(完整的示例如下:https://github.com/DaGeRe/aspect-final-example):

代码语言:javascript
复制
@Pointcut("!within(de.aspectjtest..*)")
public void notWithinAspect() {
}

@Pointcut("!set(private * *)")
public void noSet() {
    
}

@Around("notWithinAspect() && noSet()")
public Object aroundStuff(final ProceedingJoinPoint thisJoinPoint, final EnclosingStaticPart thisEnclosingJoinPoint)
        throws Throwable {
    System.out.println("=== Call: " + thisJoinPoint.getSignature() + " " + thisJoinPoint.getKind());
    System.out.println(thisJoinPoint.getSourceLocation() + " " + thisJoinPoint.getStaticPart());
    System.out.println(thisJoinPoint.toLongString());
    return thisJoinPoint.proceed();
}

转到

代码语言:javascript
复制
class FinalFieldConstructorExample {
    private final Integer parameters = 5;
    public Integer getParameters() {
        return parameters;
    }
}

public class MainWithError {
    public static void main(String[] args) {
        FinalFieldConstructorExample example = new FinalFieldConstructorExample();
        System.out.println(example.getParameters());
    }
}

通过java -cp target/test-0.1-SNAPSHOT.jar -javaagent:../aspect/target/aspectjtest-0.1-SNAPSHOT.jar de.test.MainWithError我得到

代码语言:javascript
复制
Exception in thread "main" java.lang.IllegalAccessError: Update to non-static final field de.test.FinalFieldConstructorExample.parameters attempted from a different method (init$_aroundBody2) than the initialize
r method <init>                                                                                                                                                                                                    
        at de.test.FinalFieldConstructorExample.init$_aroundBody2(MainWithError.java:5)                                                                                                                            
        at de.test.FinalFieldConstructorExample$AjcClosure3.run(MainWithError.java:1)                                                                                                                              
        at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:167)                                                                                                                               
        at de.aspectjtest.ExampleAspect.aroundStuff(ExampleAspect.java:27)                                                                                                                                         
        at de.test.FinalFieldConstructorExample.<init>(MainWithError.java:3)                                                                                                                                       
        at de.test.MainWithError.init$_aroundBody2(MainWithError.java:15)                                                                                                                                          
        at de.test.MainWithError$AjcClosure3.run(MainWithError.java:1)                                                                                                                                             
        at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:167)                     
        at de.aspectjtest.ExampleAspect.aroundStuff(ExampleAspect.java:27)                                                                                                                                         
        at de.test.MainWithError.main_aroundBody10(MainWithError.java)        
        at de.test.MainWithError$AjcClosure11.run(MainWithError.java:1)                                                                                                                                            
        at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:167)                     
        at de.aspectjtest.ExampleAspect.aroundStuff(ExampleAspect.java:27)     
        at de.test.MainWithError.main(MainWithError.java:15)

当我使用OpenJDK 11执行它时(当将一切设置为Java 8时,它工作得很好)。从FinalFieldConstructorExample中删除最终修饰符和从切入点中移除&& noSet()时,效果很好,输出包含

代码语言:javascript
复制
=== Call: Integer java.lang.Integer.valueOf(int) method-call
MainWithoutError.java:5 call(Integer java.lang.Integer.valueOf(int))
call(public static java.lang.Integer java.lang.Integer.valueOf(int))
=== Call: Integer de.test.NonFinalFieldConstructorExample.parameters field-set
MainWithoutError.java:5 set(Integer de.test.NonFinalFieldConstructorExample.parameters)
set(private java.lang.Integer de.test.NonFinalFieldConstructorExample.parameters)

因此,我认为对静态字段的设置调用(具有getKind of field-set (似乎不在OpenJDK 8中)是问题的原因。是否有任何方法将其排除在AspectJ工具之外(或解决问题)?文档(https://www.eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html#primitive-pointcuts)声明get可以在切入点中使用,但是我没有找到一种指定final的方法,即使我添加了noSet,它似乎也被触摸了,并且出现了错误。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-10-31 07:06:25

我想你在打AspectJ问题#563709。错误消息是相同的,它在Java8上工作也是一样的,但不是11 (可能是9+)。

因此,作为目前的解决办法,您希望避免向构造函数提供建议。要么你把他们排除在外

代码语言:javascript
复制
@Around("notWithinAspect() && noSet() && !(execution(*.new(..)))")

或者,考虑到您的建议只在proceed()之前做一些事情,只需更改通知类型:

代码语言:javascript
复制
@Before("notWithinAspect() && noSet()")
public void beforeStuff(final JoinPoint thisJoinPoint, final EnclosingStaticPart thisEnclosingJoinPoint) {
  System.out.println("=== Call: " + thisJoinPoint.getSignature() + " " + thisJoinPoint.getKind());
  System.out.println(thisJoinPoint.getSourceLocation() + " " + thisJoinPoint.getStaticPart());
  System.out.println(thisJoinPoint.toLongString());
}

如果出于任何原因,您需要@Around,并且通常不能将其重构为@Before + @After对,则可以保留它而不执行构造函数,只为构造函数添加一个单独的@Before + @After通知对。

更新:

排除构造函数或只使用@Before工作,但不能用于我的用例(方法执行持续时间监视)

那么这个解决方案如何呢?全球范围内用@Around + @Before + @After代替?您甚至可能会注意到,您的日志现在还显示了额外的preinitializationinitialization切入点,因为对于这些切入点类型,不支持它。这是我的MCVE

代码语言:javascript
复制
package de.scrum_master.app;

public class FinalFieldConstructorExample {
  private final Integer parameters = 5;

  public Integer getParameters() {
    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {}
    return parameters;
  }
}
代码语言:javascript
复制
package de.scrum_master.app;

public class MainWithError {
  public static void main(String[] args) {
    FinalFieldConstructorExample example = new FinalFieldConstructorExample();
    System.out.println(example.getParameters());
  }
}
代码语言:javascript
复制
package de.scrum_master.aspect;

import java.util.Stack;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MyAspect {
  private ThreadLocal<Stack<Long>> startTimeTL = ThreadLocal.withInitial(() -> new Stack<>());

  @Pointcut("within(de.scrum_master.aspect..*)")
  public void withinAspect() {}

  @Before("!withinAspect()")
  public void beforeStuff(final JoinPoint thisJoinPoint) {
    startTimeTL.get().push(System.currentTimeMillis());
  }

  @After("!withinAspect()")
  public void afterStuff(final JoinPoint thisJoinPoint) {
    System.out.println(thisJoinPoint + " -> " + (System.currentTimeMillis() - startTimeTL.get().pop()));
  }
}

控制台日志如下所示:

代码语言:javascript
复制
staticinitialization(de.scrum_master.app.MainWithError.<clinit>) -> 1
staticinitialization(de.scrum_master.app.FinalFieldConstructorExample.<clinit>) -> 0
preinitialization(de.scrum_master.app.FinalFieldConstructorExample()) -> 0
call(Integer java.lang.Integer.valueOf(int)) -> 0
set(Integer de.scrum_master.app.FinalFieldConstructorExample.parameters) -> 0
execution(de.scrum_master.app.FinalFieldConstructorExample()) -> 1
initialization(de.scrum_master.app.FinalFieldConstructorExample()) -> 1
call(de.scrum_master.app.FinalFieldConstructorExample()) -> 2
get(PrintStream java.lang.System.out) -> 0
call(void java.lang.Thread.sleep(long)) -> 100
get(Integer de.scrum_master.app.FinalFieldConstructorExample.parameters) -> 0
execution(Integer de.scrum_master.app.FinalFieldConstructorExample.getParameters()) -> 100
call(Integer de.scrum_master.app.FinalFieldConstructorExample.getParameters()) -> 100
5
call(void java.io.PrintStream.println(Object)) -> 1
execution(void de.scrum_master.app.MainWithError.main(String[])) -> 103

P.S.:您是否知道,对于编织方法和构造函数,您同时记录相同方法/构造函数的callexecution

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64611859

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档