代码之家  ›  专栏  ›  技术社区  ›  Pankaj Singhal

AspectJ AOP LTW不处理javaagent的动态加载

  •  3
  • Pankaj Singhal  · 技术社区  · 6 年前

    Here is my sample non-working project .

    它包含两个模块:

    • aop库 -用作lib的方面。它包含以下类
      1. 包装.java -这是用来附加建议的注释
      2. WrapDef.java -这是上面提到的定义 Wrap 注解。
    • aop应用程序 -使用上面的方面库
      1. 动态加载.java -类动态加载javaagent
      2. 主类 -使用的主要类 包裹 注解。

    Dir结构如下:

    .
    ├── 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
    

    我试图使用aspect库 aop-lib (AOP通知库)内部 aop-app 通过动态加载javaagent实现负载时间编织(LTW),如 official docs . 但没用。

    以下是 Wrap.java

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

    以下是 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);
        }
    }
    

    以下是 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);
        }
    
    }
    

    javaagent 作为命令行arg,它工作得非常好:

    $ 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
    

    但是,随着 Java代理 ,它提供以下输出:

    $ 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
    

    这个 正式文件 是不是说 any classes loaded before attachment will not be woven . 但是,正如您在上面的输出中所看到的,在 WrapDef 类根本没有加载。

    另外,请注意我正在使用 aspectj-maven-plugin 在我的 aop-lib/pom.xml ,具有以下选项:

    <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
    

    所以,它创造了 META-INF/aop-ajc.xml 里面 aop-lib-1.0.jar 内容如下:

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

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

    如果你需要其他信息-我会提供的。

    如有任何帮助,我们将不胜感激。

    1 回复  |  直到 6 年前
        1
  •  2
  •   kriegaex    6 年前

    解释很简单:您正在类中直接测试编织代理 Main 已经加载了 之前 你把那个班里的那个探员接上了。所以你必须避免你喜欢的课程被编织得太早。我建议你把方法 myFunc() (顺便说一句,糟糕的名字)进入另一个类。那怎么样?

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

    然后在最后一行 Main.main(..) 启动要编织的实际应用程序:

    Application.main(null);
    

    这将产生以下输出:

    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.:您真的认为方面库的用户在JVM命令行上指定两个属性比仅仅使用 -javaagent:/path/to/aspectweaver.jar ? 不管怎样,您可能有理由使用动态编织器附件。在某种程度上,我很高兴有人使用了我刚才自己添加到AspectJ中的功能。 ;-)

    推荐文章