带有 jar 类加载器的 AspectJ

AspectJ with jar classloader

我正在尝试检测基于 Jetty 构建的 Oracle Rest Data Service (ORDS)。该方面应跟踪 JDBC 调用。我没有看到编织发生。

我已经在另一个使用 JDBC 的独立应用程序中尝试了 AspectJ,并且还在独立 Jetty 中的应用程序 运行 中分析了 Servlet 调用,所有这些都对我有用。但在这种情况下有一个例外,看起来并没有发生编织。应用程序本身在应用所有 AspectJ 配置的情况下按预期工作。

已尝试两种方案:

   ├── WEB-INF
   │   ├── beans.xml
   │   ├── classes
   │   │   ├── META-INF
   │   │   │   ├── MANIFEST.MF
   │   │   │   └── aop-ajc.xml
   │   │   └── WhereTheStatementTimeGo.class 

两种情况都出现如下异常。

这是命令行和异常:

$JAVA_HOME/bin/java -javaagent:/DATA/PROJECTS/ASPECTJ19/lib/aspectjweaver.jar -Dorg.aspectj.tracing.enabled=true -Dorg.aspectj.tracing.factory=defaug.aspectj.tracing.messages=true   -jar ords.war standalone

[JarClassLoader@17f052a3] warning parse definitions failed -- (IllegalStateException) sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
java.lang.IllegalStateException: sun.misc.Launcher$AppClassLoader@18b4aac2
    at oracle.dbtools.jarcl.NestedResourceHandler.jarClassLoader(NestedResourceHandler.java:36)
    at oracle.dbtools.jarcl.NestedResourceHandler.openConnection(NestedResourceHandler.java:23)
    at java.net.URL.openConnection(URL.java:979)
    at java.net.URL.openStream(URL.java:1045)
    at org.aspectj.weaver.loadtime.definition.DocumentParser.saxParsing(DocumentParser.java:157)
    at org.aspectj.weaver.loadtime.definition.DocumentParser.parse(DocumentParser.java:123)
    at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.parseDefinitions(ClassLoaderWeavingAdaptor.java:290)
    at org.aspectj.weaver.loadtime.DefaultWeavingContext.getDefinitions(DefaultWeavingContext.java:130)
    at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.initialize(ClassLoaderWeavingAdaptor.java:174)
    at org.aspectj.weaver.loadtime.Aj$ExplicitlyInitializedClassLoaderWeavingAdaptor.initialize(Aj.java:337)
    at org.aspectj.weaver.loadtime.Aj$ExplicitlyInitializedClassLoaderWeavingAdaptor.getWeavingAdaptor(Aj.java:342)
    at org.aspectj.weaver.loadtime.Aj$WeaverContainer.getWeaver(Aj.java:316)
    at org.aspectj.weaver.loadtime.Aj.preProcess(Aj.java:108)
    at org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:51)
    at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
    at oracle.dbtools.jarcl.JarClassLoader.findClass(JarClassLoader.java:77)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at oracle.dbtools.jarcl.Entrypoint.invoke(Entrypoint.java:50)
    at oracle.dbtools.jarcl.Entrypoint.main(Entrypoint.java:77)

2019-07-02 16:47:29.822:INFO::main: Logging initialized @3375ms to org.eclipse.jetty.util.log.StdErrLog
Jul 02, 2019 4:47:29 PM  
INFO: HTTP and HTTP/2 cleartext listening on port: 8080
Jul 02, 2019 4:47:29 PM  
INFO: Disabling document root because the specified folder does not exist: /Users/slinetsk/Downloads/ORDS/ords/standalone/doc_root
2019-07-02 16:47:30.632:INFO:oejs.Server:main: jetty-9.4.z-SNAPSHOT; built: 2019-02-20T15:50:58.683Z; git: 3285c4dd4bb00caddcded77f8e44e72c61b9ab72; jvm 1.8.0_211-b12
2019-07-02 16:47:30.693:INFO:oejs.session:main: DefaultSessionIdManager workerName=node0
2019-07-02 16:47:30.693:INFO:oejs.session:main: No SessionScavenger set, using defaults
2019-07-02 16:47:30.694:INFO:oejs.session:main: node0 Scavenging every 600000ms

输出中没有任何 AspectJ 跟踪相关信息

我找到了一个解决方法,它让我 运行 服务器没有问题,并且还在各种 classes 上使用不同类型的方面切入点,例如内部 Jetty classes:

将 AspectJ 编织器和方面库(包含方面和 META-INF/aop.xml 的 JAR 复制到子目录 lib 您开始 ords.war 的地方。然后将方面库附加到 JVM 引导 class 路径。您需要使用像 Java 8 这样的 JRE/JDK 版本,它实际上仍然支持引导 class 路径。 (其实我刚刚查了一下,JDK 11 仍然支持它。) 我不知道如何使用模块化的 JRE 来做到这一点。然后像这样开始你的WAR:

java -Xbootclasspath/a:lib/aspect.jar -javaagent:lib/aspectjweaver.jar -jar ords.war standalone

再来一次,插入换行符:

java
  -Xbootclasspath/a:lib/aspect.jar
  -javaagent:lib/aspectjweaver.jar
  -jar ords.war standalone

这种方法确保在 Oracle JAR classloader 执行其入口点魔术之前找到 weaver 及其方面 classes。

请注意,您根本不需要在此处修改 WAR 文件。


更新: 作为替代方案,您可以动态附加 AspectJ 编织代理,而不是通过 -javaagent,请参阅

我很快测试了它,它有效。不过有点棘手:

  • 您必须将您自己的主 class 与 AspectJ read-me 中的那个类似,作为主 class 放入 WAR 中。 class 将附加编织器,然后启动 JAR classloader。现在编织器已经到位,一切都按预期工作。
  • 需要注意的是,您需要在 class 路径上使用 tools.jarmyaspect.jaraspectjweaver.jar 启动 JVM,
    • 如果您想使用 java -jar my.war
    • 启动应用程序,则在启动 classpath 上
    • 或在正常的 class 路径上 您是否可以使用 -cp ...;my.war my.own.MainClass.
    • 启动应用程序
  • 此外,自 Java 9 以来,不再有 tools.jar,但您需要根据模块 jdk.attach 创建自己的入口点 class,并确保您实际上 运行 带有 JDK 的应用程序,而不是 JRE。否则您不能使用 API 动态附加代理。

总而言之我还是喜欢原来的方案,实现起来简单多了。