AspectJ AOP LTW无法动态加载javaagent

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

它包含2个模块:

  • aop-lib – 用作lib的方面。 它包含以下类
    1. Wrap.java – 它是用于附加建议的注释
    2. WrapDef.java – 它是上面提到的Wrap注释的定义。
  • aop-app – 使用上面的方面lib
    1. DynamicLoad.java – 动态加载javaagent的类
    2. Main.java – 使用Wrap注释的主类。

目录结构如下:

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

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

以下是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作为cmd行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 

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

 $ 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类根本没有加载。

另外,请注意我在aop-lib / pom.xml中使用了aspectj-maven-plugin ,其中包含以下选项:

 true //creates META-INF/aop-ajc.xml true //supposed to create  BUT DOES NOT WORK true //supposed to create  BUT DOES NOT WORK 

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

      

但是对应于showWeaveInfoverbose的其他标签不是在META-INF/aop-ajc.xml 。 这是另一件在这里不起作用的事情。

如果您需要任何其他信息 – 我将提供。

任何帮助表示赞赏。

解释非常简单:您正在直接在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 

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