AspectJ AOP LTW 不适用于 javaagent 的动态加载 [英] AspectJ AOP LTW not working with dynamic loading of javaagent

查看:30
本文介绍了AspectJ AOP LTW 不适用于 javaagent 的动态加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的示例非工作项目.

它包含2个模块:

  • aop-lib - 用作 lib 的方面.它包含以下类

    1. Wrap.java - 这是用于附加建议的注释
    2. WrapDef.java - 上面提到的Wrap注解的定义.

  • aop-app - 使用上述方面库

    1. DynamicLoad.java - 动态加载 javaagent 的类
    2. Main.java - 使用 Wrap 注释的主类.

目录结构如下:

<预><代码>.├── README.md├── aop-app│ ├── pom.xml│ └── src│ └── 主要│ └── java│ └── com│ └── aop│ └── 应用│ ├── DynamicLoad.java│ └── Main.java└── aop-lib├── pom.xml└── src└── 主要└── 爪哇└── com└── aop└── 应用程序└── 库├── Wrap.java└── WrapDef.java

我正在尝试通过加载时间编织 (LTW) 动态加载 aop-app 中的方面库 aop-lib(AOP 建议库)官方文档 中提到的 javaagent.但它不起作用.

以下是Wrap.java

@Target({ElementType.METHOD, ElementType.TYPE})@Retention(value = RetentionPolicy.RUNTIME)公共@interface 包装{}

以下是WrapDef.java

@Aspect公共类 WrapDef {私有静态最终记录器记录器 = LoggerFactory.getLogger(WrapDef.class);公共静态布尔加载 = 假;@Around("@annotation( wrapAnnotation ) && execution(* *(..))")公共对象 processSystemRequest(final ProceedingJoinPoint pjp, Wrap wrapAnnotation)抛出 Throwable {logger.debug("包装前");对象 o = pjp.proceed();logger.debug("包装后");返回o;}静止的 {System.out.println("加载中");WrapDef.loaded = true;}公共静态无效报告加载(){System.out.println("加载:" + 加载);}}

以下是Main.java:

public class Main {私有静态最终记录器记录器 = LoggerFactory.getLogger(Main.class);@裹公共无效 myFunc(){logger.debug("在 myFunc 里面");}public static void main(String[] args) 抛出 NoSuchMethodException、IllegalAccessException、InvocationTargetException {boolean dynamicLoad = Boolean.getBoolean("dynamicLoad");如果(动态负载){Main.isAdviceClassLoaded();//查看WrapDef.java是否加载.if(!DynamicLoad.isAspectJAgentLoaded()) {logger.error("AspectJ 未加载.现有.");System.exit(0);}Main.isAdviceClassLoaded();//查看WrapDef.java是否加载.}new Main().myFunc();}private static void isAdviceClassLoaded() 抛出 NoSuchMethodException、InvocationTargetException、IllegalAccessException {java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);m.setAccessible(true);ClassLoader cl = ClassLoader.getSystemClassLoader();对象 test1 = m.invoke(cl, "com.aop.app.lib.WrapDef");布尔加载 = test1 != null;System.out.println("com.aop.app.lib.WrapDef 已加载:" + 已加载);}}

使用 javaagent 作为 cmd 行 arg,它工作得很好:

$ java -javaagent:deploy/lib/aspectjweaver-1.9.1.jar -classpath aop-app-1.0.jar:deploy/lib/* com.aop.app.Main14:02:45.384 [main] 调试 com.aop.app.lib.WrapDef - 换行前14:02:45.391 [main] 调试 com.aop.app.Main - 在 myFunc 中14:02:45.391 [main] 调试 com.aop.app.lib.WrapDef - 包装后

但是,通过 javaagent 的动态加载,它提供以下输出:

$ java -DdynamicLoad=true -DAGENT_PATH=deploy/lib/aspectjweaver-1.9.1.jar -classpath aop-app-1.0.jar:deploy/lib/* com.aop.app.Maincom.aop.app.lib.WrapDef Loaded : false//WrapDef 在 JAVAAGENT 加载之前未加载 - 这是正确的java.lang.UnsupportedOperationException:AspectJ 编织代理既不是通过-javaagent"(preMain)启动,也不是通过VirtualMachine.loadAgent"(agentMain)连接加载 javaAgent deploy/lib/aspectjweaver-1.9.1.jar加载 javaAgent deploy/lib/aspectjweaver-1.9.1.jar//JAVAAGENT 是动态加载的 - 这是正确的com.aop.app.lib.WrapDef Loaded : false//即使在加载 JAVAAGENT 之后 WrapDef 仍未加载 - 这是问题15:53:08.543 [main] 调试 com.aop.app.Main - 在 myFunc 中

官方文档确实说在附件之前加载的任何类都不会被编织.但是,正如您在上面的输出中看到的相反,WrapDef 类根本没有加载.

另外,请注意我在我的 aop-lib/pom.xml,有以下选项:

true//创建 META-INF/aop-ajc.xml<showWeaveInfo>true</showWeaveInfo>//应该创建<weaver options="-showWeaveInfo"/>但不起作用<详细>真</详细>//应该创建<weaver options="-verbose"/>但不起作用

因此,它在 aop-lib-1.0.jar 中创建了 META-INF/aop-ajc.xml,内容如下:

<方面><aspect name="com.aop.app.lib.WrapDef"/></方面></aspectj>

但其他标签对应于showWeaveInfo &verbose 不是在 META-INF/aop-ajc.xml 中创建的.这是另一件在这里不起作用的事情.

如果您需要任何其他信息 - 我会提供.

感谢任何帮助.

解决方案

解释很简单:你是在之前加载的类Main中直接测试编织代理强> 你附上了那个班级的特工.因此,您必须避免过早加载您喜欢编织的类.我建议你把方法 myFunc()(顺便说一句,可怕的名字)放到另一个类中.怎么样?

package com.aop.app;导入 com.aop.app.lib.Wrap;导入 org.slf4j.Logger;导入 org.slf4j.LoggerFactory;公共类应用{私有静态最终记录器记录器 = LoggerFactory.getLogger(Application.class);@裹公共无效 myFunc(){logger.debug("在 myFunc 里面");}公共静态无效主(字符串 [] args){新应用程序().myFunc();}}

然后在 Main.main(..) 的最后一行开始你想要编织的实际应用程序:

Application.main(null);

这将产生以下输出:

com.aop.app.lib.WrapDef Loaded : falsejava.lang.UnsupportedOperationException:AspectJ 编织代理既不是通过-javaagent"(preMain)启动,也不是通过VirtualMachine.loadAgent"(agentMain)连接加载 javaAgent aop-app/target/deploy/lib/aspectjweaver-1.9.1.jar已加载 javaAgent aop-app/target/deploy/lib/aspectjweaver-1.9.1.jarcom.aop.app.lib.WrapDef 加载:假加载中07:56:21.703 [main] 调试 com.aop.app.lib.WrapDef - 换行前07:56:21.716 [main] 调试 com.aop.app.Application - 在 myFunc 中07:56:21.716 [main] DEBUG com.aop.app.lib.WrapDef - 包装后

P.S.:您真的认为您的方面库的用户在 JVM 命令行上指定两个属性比仅使用 -javaagent:/path/to/aspectweaver.jar 更容易吗?无论如何,您可能有理由使用动态编织器附件.在某种程度上,我很高兴有人使用我不久前自己添加到 AspectJ 的功能.;-)

Here is my sample non-working project.

It contains 2 modules:

  • aop-lib - Aspects used as lib. It contains the following classes

    1. Wrap.java - It's the annotation used to attach advice
    2. WrapDef.java - It is the definition of the above mentioned Wrap annotation.

  • aop-app - Uses the above aspect lib

    1. DynamicLoad.java - class to load javaagent dynamically
    2. Main.java - Main class which uses Wrap annotation.

Dir structure is as follows:

.
├── README.md
├── aop-app
│   ├── pom.xml
│   └── src
│       └── main
│           └── java
│               └── com
│                   └── aop
│                       └── app
│                           ├── DynamicLoad.java
│                           └── Main.java
└── aop-lib
    ├── pom.xml
    └── src
        └── main
            └── java
                └── com
                    └── aop
                        └── app
                            └── lib
                                ├── Wrap.java
                                └── WrapDef.java

I'm trying to use the aspect lib aop-lib (an AOP advice lib) inside aop-app through Load Time Weaving (LTW) by dynamically loading the javaagent as mentioned in the official docs. But it's not working.

Following are the contents of Wrap.java

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Wrap { }

Following are the contents of WrapDef.java

@Aspect
public class WrapDef {
    private static final Logger logger = LoggerFactory.getLogger(WrapDef.class);

    public static boolean loaded = false;

    @Around("@annotation( wrapAnnotation ) && execution(* *(..))")
    public Object processSystemRequest(final ProceedingJoinPoint pjp, Wrap wrapAnnotation)
            throws Throwable {
        logger.debug("before wrap");
        Object o = pjp.proceed();
        logger.debug("after wrap");
        return o;
    }

    static {
        System.out.println("Loading");
        WrapDef.loaded = true;
    }
    public static void reportLoaded() {
        System.out.println("loaded : " + loaded);
    }
}

Following are the contents of Main.java:

public class Main {

    private static final Logger logger = LoggerFactory.getLogger(Main.class);

    @Wrap
    public void myFunc(){
        logger.debug("inside myFunc");
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        boolean dynamicLoad = Boolean.getBoolean("dynamicLoad");
        if(dynamicLoad){
            Main.isAdviceClassLoaded();           //To see if WrapDef.java is loaded or not.
            if(!DynamicLoad.isAspectJAgentLoaded()) {
                logger.error("AspectJ Not Loaded. Existing.");
                System.exit(0);
            }
            Main.isAdviceClassLoaded();           //To see if WrapDef.java is loaded or not.
        }

        new Main().myFunc();
    }

    private static void isAdviceClassLoaded() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
        m.setAccessible(true);
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Object test1 = m.invoke(cl, "com.aop.app.lib.WrapDef");
        boolean loaded = test1 != null;
        System.out.println("com.aop.app.lib.WrapDef Loaded : " + loaded);
    }

}

With javaagent as cmd line arg, it works perfectly fine:

$ java -javaagent:deploy/lib/aspectjweaver-1.9.1.jar -classpath aop-app-1.0.jar:deploy/lib/* com.aop.app.Main
14:02:45.384 [main] DEBUG com.aop.app.lib.WrapDef - before wrap
14:02:45.391 [main] DEBUG com.aop.app.Main - inside myFunc
14:02:45.391 [main] DEBUG com.aop.app.lib.WrapDef - after wrap

But, with Dynamic loading of javaagent, it gives the following output:

$ java -DdynamicLoad=true -DAGENT_PATH=deploy/lib/aspectjweaver-1.9.1.jar -classpath aop-app-1.0.jar:deploy/lib/* com.aop.app.Main
com.aop.app.lib.WrapDef Loaded : false                   //The WrapDef is NOT loaded before JAVAAGENT is Loaded - which is correct
java.lang.UnsupportedOperationException: AspectJ weaving agent was neither started via '-javaagent' (preMain) nor attached via 'VirtualMachine.loadAgent' (agentMain)
loading javaAgent deploy/lib/aspectjweaver-1.9.1.jar
loaded javaAgent deploy/lib/aspectjweaver-1.9.1.jar      //The JAVAAGENT is Dynamically Loaded - which is correct
com.aop.app.lib.WrapDef Loaded : false                   //The WrapDef is STILL NOT loaded even AFTER JAVAAGENT is Loaded - THIS IS THE ISSUE
15:53:08.543 [main] DEBUG com.aop.app.Main - inside myFunc

The official docs does say that any classes loaded before attachment will not be woven. But, on the contrary as you can see in the above output, the WrapDef class is not loaded at all.

Also, note that I'm using aspectj-maven-plugin in my aop-lib/pom.xml, with the following options:

<outxml>true</outxml>                           //creates META-INF/aop-ajc.xml
<showWeaveInfo>true</showWeaveInfo>             //supposed to create <weaver options="-showWeaveInfo"/> BUT DOES NOT WORK
<verbose>true</verbose>                         //supposed to create <weaver options="-verbose"/> BUT DOES NOT WORK

So, it creates META-INF/aop-ajc.xml inside aop-lib-1.0.jar with the following content:

<aspectj>
<aspects>
<aspect name="com.aop.app.lib.WrapDef"/>
</aspects>
</aspectj>

but the other tags corresponding to showWeaveInfo & verbose are not created in META-INF/aop-ajc.xml. This is another thing that is not working here.

If you require any other info - I shall provide it.

Any help is appreciated.

解决方案

The explanation is quite simple: You are testing the weaving agent directly in class Main which is already loaded before you attach that very agent from that class. So you have to avoid classes which you like to be woven to be loaded too early. I suggest you put method myFunc() (horrible name, by the way) into another class. How about that?

package com.aop.app;

import com.aop.app.lib.Wrap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Application {
  private static final Logger logger = LoggerFactory.getLogger(Application.class);

  @Wrap
  public void myFunc(){
    logger.debug("inside myFunc");
  }

  public static void main(String[] args) {
    new Application().myFunc();
  }
}

Then in the last line of Main.main(..) you start the actual application you want woven:

Application.main(null);

This will yield the following output:

com.aop.app.lib.WrapDef Loaded : false
java.lang.UnsupportedOperationException: AspectJ weaving agent was neither started via '-javaagent' (preMain) nor attached via 'VirtualMachine.loadAgent' (agentMain)
loading javaAgent aop-app/target/deploy/lib/aspectjweaver-1.9.1.jar
loaded javaAgent aop-app/target/deploy/lib/aspectjweaver-1.9.1.jar
com.aop.app.lib.WrapDef Loaded : false
Loading
07:56:21.703 [main] DEBUG com.aop.app.lib.WrapDef - before wrap
07:56:21.716 [main] DEBUG com.aop.app.Application - inside myFunc
07:56:21.716 [main] DEBUG com.aop.app.lib.WrapDef - after wrap

P.S.: Do you really think it is easier for users of your aspect library to specify two properties on the JVM command line instead of just using -javaagent:/path/to/aspectweaver.jar? Anyway, you probably have your reasons to use dynamic weaver attachment. In a way I am kind of happy that someone uses the functionality I added to AspectJ myself a while ago. ;-)

这篇关于AspectJ AOP LTW 不适用于 javaagent 的动态加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆