AspectJ AOP LTW не работает с динамической загрузкой javaagent
Вот мой пример нерабочего проекта .
Он содержит 2 модуля:
-
aop-lib - аспекты, используемые в качестве lib. Он содержит следующие классы
- обернуть.java - это аннотация, используемая для прикрепления советов
-
WrapDef.java - это определение вышеупомянутой аннотации
Wrap
.
-
aop-app - использует вышеупомянутый аспект lib
- динамическая нагрузка.java - класс для динамической загрузки javaagent
-
Главная.java - основной класс, использующий аннотацию
Wrap
.
Структура 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
Я пытаюсь использовать аспект lib aop-lib
(AOP advice lib) внутри aop-app
через load Time Weaving (LTW) путем динамической загрузки javaagent, как указано в официальных документах. Но это не работает.
Ниже приводится содержание обернуть.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
Но, при динамической нагрузке 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
не загружается на все.
Также обратите внимание, что я использую 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 ответ:
Объяснение довольно простое: вы тестируете ткацкий агент непосредственно в классе
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);
Это даст следующий вывод:
P.S.: Вы действительно думаете, что пользователям вашей библиотеки аспектов проще указать два свойства в командной строке JVM вместо того, чтобы просто использовать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
-javaagent:/path/to/aspectweaver.jar
? В любом случае, у вас, вероятно, есть свои причины использовать динамическую привязанность Ткача. В каком-то смысле я даже рад, что кто-то использует функциональность, которую я сам недавно добавил в AspectJ.;-)