是否可以排除AspectJ

如何解决是否可以排除AspectJ

是否可以在AspectJ切入点中排除字段集,从而使检测不会偶然发现Java 11中的最终字段?

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

@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();
}

进入

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得到

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()中删除最终修饰符时,它工作正常并且输出包含

=== 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的{​​{1}},似乎在OpenJDK 8中不存在)是问题的原因。有什么方法可以将它从AspectJ工具中排除(或解决问题)?文档(https://www.eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html#primitive-pointcuts)指出可以在切入点中使用get,但是我没有找到指定field-set的方法,即使我添加了final,它也似乎是某种方式触摸并显示错误。

解决方法

我认为您正在击中AspectJ issue #563709。错误消息是相同的,因此它可以在Java 8上运行,但不能在11(可能是9+)上运行。

因此,作为一种变通办法,您现在要避免建议周围的构造函数。您可以通过

排除它们
@Around("notWithinAspect() && noSet() && !(execution(*.new(..)))")

或者,考虑到您的建议仅在proceed()之前执行某项操作,只需更改建议类型:

@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对,则可以在上面排除构造函数执行的情况下保留它,并添加一个单独的{ {1}} + @Before咨询对,仅适用于构造函数。


更新

排除构造函数或仅使用@After可以工作,但是不适用于我的用例(方法执行持续时间监视)

那么,如何解决这个问题,以@Before + @Around对全局替换@Before呢?您甚至可能会注意到,您的日志现在还显示了其他@Afterpreinitialization切入点,这些切入点以前没有被around通知捕获,因为不支持这些切入点类型。这是我的MCVE

initialization
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;
  }
}
package de.scrum_master.app;

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

控制台日志如下:

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()));
  }
}

P.S .:您是否知道以下事实:对于编织方法和构造函数,您要为同一方法/构造函数同时记录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 call

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-