AspectJ AOP LTW 不适用于 javaagent 的动态加载
AspectJ AOP LTW not working with dynamic loading of javaagent
Here is my sample non-working project.
它包含 2 个模块:
- aop-lib - 用作库的方面。它包含以下 classes
- Wrap.java - 这是用来附加建议的注解
- WrapDef.java - 就是上面提到的
Wrap
注解的定义。
- aop-app - 使用上面的 aspect 库
- DynamicLoad.java - class动态加载javaagent
- Main.java - 使用
Wrap
注释的主要 class。
目录结构如下:
.
├── 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
中使用方面库 aop-lib
(一个 AOP 建议库),方法是动态加载 [=33] 中提到的 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 line 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
official docs 确实说 any classes loaded before attachment will not be woven
。但是,相反,正如您在上面的输出中看到的,WrapDef
class 根本没有加载。
此外,请注意,我在我的 aop-lib/pom.xml 中使用 aspectj-maven-plugin
,具有以下选项:
<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
因此,它在 aop-lib-1.0.jar
中创建了 META-INF/aop-ajc.xml
,内容如下:
<aspectj>
<aspects>
<aspect name="com.aop.app.lib.WrapDef"/>
</aspects>
</aspectj>
但 showWeaveInfo
和 verbose
对应的其他标签未在 META-INF/aop-ajc.xml
中创建。这是另一个在这里不起作用的东西。
如果您需要任何其他信息 - 我会提供。
感谢任何帮助。
解释很简单:您直接在 class Main
中测试编织代理,它已经加载 before 您从中附加那个代理class。所以你要避免 class 你喜欢编织的东西过早加载。我建议您将方法 myFunc()
(顺便说一句,这个名字很糟糕)放到另一个 class 中。怎么样?
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 的功能。 ;-)
Here is my sample non-working project.
它包含 2 个模块:
- aop-lib - 用作库的方面。它包含以下 classes
- Wrap.java - 这是用来附加建议的注解
- WrapDef.java - 就是上面提到的
Wrap
注解的定义。
- aop-app - 使用上面的 aspect 库
- DynamicLoad.java - class动态加载javaagent
- Main.java - 使用
Wrap
注释的主要 class。
目录结构如下:
.
├── 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
中使用方面库 aop-lib
(一个 AOP 建议库),方法是动态加载 [=33] 中提到的 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 line 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
official docs 确实说 any classes loaded before attachment will not be woven
。但是,相反,正如您在上面的输出中看到的,WrapDef
class 根本没有加载。
此外,请注意,我在我的 aop-lib/pom.xml 中使用 aspectj-maven-plugin
,具有以下选项:
<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
因此,它在 aop-lib-1.0.jar
中创建了 META-INF/aop-ajc.xml
,内容如下:
<aspectj>
<aspects>
<aspect name="com.aop.app.lib.WrapDef"/>
</aspects>
</aspectj>
但 showWeaveInfo
和 verbose
对应的其他标签未在 META-INF/aop-ajc.xml
中创建。这是另一个在这里不起作用的东西。
如果您需要任何其他信息 - 我会提供。
感谢任何帮助。
解释很简单:您直接在 class Main
中测试编织代理,它已经加载 before 您从中附加那个代理class。所以你要避免 class 你喜欢编织的东西过早加载。我建议您将方法 myFunc()
(顺便说一句,这个名字很糟糕)放到另一个 class 中。怎么样?
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 的功能。 ;-)