我在一个简单的项目上挣扎,因为我无法运行。
我的目标是扩展.jar-File的功能,以获取有关该jar内部工作方式的更多信息。 .jar不是开源的。 我遇到了许多不同的概念,将我自己的代码“注入”jvm,如“ASM” - 图书馆,BECL,Javassist,最后是AspectJ。
AspectJ引起了我的注意,因为它似乎更容易使用和更高级别。为了尝试AspectJ在使用封闭源.jar之前的工作方式,我设置了测试项目:
PROJECT1:
为了测试它,我想创建一个包含一个Class的简单项目,该类应该被编译并打包到.jar-File。稍后应使用Aspect监视此类。我从互联网上的一个例子中获取了这个类的源代码:https://github.com/Nosfert/AspectJ-Tutorial-jayway 该类的文件内容如下所示: YourClass.java:
package com.test.java.instrumentation;
public class YourClass {
public static void main(String[] args) {
YourClass yourClass = new YourClass();
yourClass.yourMethodBefore();
yourClass.yourMethodAfter();
yourClass.yourMethodAround(1);
yourClass.yourMethodAround(1,"Test");
}
public void yourMethodBefore() {
System.out.println("Executing TestTarget.yourMethodBefore()");
}
public void yourMethodAfter(){
System.out.println("Executing TestTarget.yourMethodAfter()");
}
public void yourMethodAround(Integer i){
System.out.println("Executing TestTarget.yourMethodAround()");
System.out.println("i : "+i);
}
public void yourMethodAround(Integer i,String x){
System.out.println("Executing TestTarget.yourMethodAround()");
System.out.println("i : "+i);
System.out.println("x : "+x);
}
}
我使用以下命令编译代码:
javac -d bin -cp ./src/ ./src/com/test/java/instrumentation/YourClass.java
该命令运行没有错误。 在下一步中,我创建了一个Manifest文件,其中包含在.jar-File中运行Class的必要信息: MANIFEST.MF:
Manifest-Version: 1.0
Main-Class: com.test.java.instrumentation.YourClass
Built-By: Me
Build-Jdk: 1.8.0_131
在下一步中,我创建一个.jar:
cd bin\
jar cvfm program.jar ..\meta-inf\manifest.mf .
.jar可以通过以下方式成功执行:
java -jar program.jar
输出如下:
Executing TestTarget.yourMethodBefore()
Executing TestTarget.yourMethodAfter()
Executing TestTarget.yourMethodAround()
i : 1
Executing TestTarget.yourMethodAround()
i : 1
x : Test
到目前为止一切顺利。第1步完成。这是示例应用程序,稍后应使用AspectJ的加载时间编织扩展其他功能。
Project2的: 在下一步中,我想创建包含我的代码的AspectJ .jar-File以扩展Project1的功能: Priject2(YourAspect.java)的内容如下:
package com.test.java.instrumentation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.JoinPoint;
@Aspect
public class YourAspect {
//Patterns
//blank = modifier (public/private/protected or default(blank) should be looked for
//* = return type to look for. Void/Object/Primitive type
//com.jayway.YourClass.yourMethodBefore(..) = PackageName . ClassName . methodName (parameters)
@Before("execution (* com.test.java.instrumentation.YourClass.yourMethodBefore(..))")
//JointPoint = the reference of the call to the method
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("YourAspect's BeforeAdvice's body is now executed Before yourMethodBefore is called.");
}
//Patterns
//public = look for the specific modifier named public
//!Object = Basically we are looking for void or primitives. But if we specified Object we could get a good pattern
//com.jayway.YourClass.yourMethodBefore(..) = PackageName . ClassName . methodName (parameters)
@After("execution (public !Object com.test.java.instrumentation.YourClass.yourMethodAfter(..))")
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("YourAspect's afterAdvice's body is now executed After yourMethodAfter is called.");
}
//Patterns
//!private = look for any modifier that's not private
//void = looking for method with void
//com.jayway.YourClass.yourMethodBefore(..) = PackageName . ClassName . methodName (parameters)
@Around("execution (!private void com.test.java.instrumentation.YourClass.yourMethodAround(Integer,..))")
//ProceedingJointPoint = the reference of the call to the method.
//The difference between ProceedingJointPoint and JointPoint is that a JointPoint can't be continued (proceeded)
//A ProceedingJointPoint can be continued (proceeded) and is needed for an Around advice
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
//Default Object that we can use to return to the consumer
Object returnObject = null;
try {
System.out.println("YourAspect's aroundAdvice's body is now executed Before yourMethodAround is called.");
//We choose to continue the call to the method in question
returnObject = joinPoint.proceed();
//If no exception is thrown we should land here and we can modify the returnObject, if we want to.
} catch (Throwable throwable) {
//Here we can catch and modify any exceptions that are called
//We could potentially not throw the exception to the caller and instead return "null" or a default object.
throw throwable;
}
finally {
//If we want to be sure that some of our code is executed even if we get an exception
System.out.println("YourAspect's aroundAdvice's body is now executed After yourMethodAround is called.");
}
return returnObject;
}
//Patterns
//blank = modifier (public/private/protected or default(blank) should be looked for
//* = return type to look for. Void/Object/Primitive type
//com.jayway.YourClass.yourMethod*(..) = PackageName . ClassName . * (parameters)
//Where the "*" will catch any method name
@After("execution ( * com.test.java.instrumentation.YourClass.*(..))")
//JointPoint = the reference of the call to the method
public void printNewLine(JoinPoint pointcut){
//Just prints new lines after each method that's executed in
System.out.print("\n\r");
}
}
我还创建了一个MANIFEST.FM:
Manifest-Version: 1.0
Main-Class: com.test.java.instrumentation.YourAspect
Built-By: Me
Build-Jdk: 1.8.0_131
和aop.xml:
<aspectj>
<aspects>
<aspect name="com.test.java.instrumentation.YourAspect"/>
</aspects>
<weaver options="-XlazyTjp">
<include within="com.test.java.instrumentation..*"/>
</weaver>
</aspectj>
我可以使用以下命令成功编译该类:
javac -cp ./lib/aspectjrt.jar;.lib/aspejctjweaver.jar;./src;. -d ./bin/ ./src/com/test/java/instrumentation/YourAspect.java
生成的类文件与Manifest和aop.xml一起打包成.jar:
cd bin\
jar cvfm aspect.jar ..\meta-inf\manifest.mf ..\meta-inf\aop.xml .
当我尝试运行示例程序(Project1)并尝试编织方面(Project2)时,我使用以下命令:
java -Daj.weaving.verbose=true -Dorg.aspectj.weaver.showWeaveInfo=true -javaagent:./Aspect/lib/aspectjweaver.jar -cp ./Aspect/lib/aspectjrt.jar;./Aspect/lib/aspejctjtools.jar;. -jar ./JavaProgram/bin/program.jar
加载失败,产生的错误如下:
[AppClassLoader@18b4aac2] info AspectJ Weaver Version 1.8.10 built on Monday Dec 12, 2016 at 19:07:48 GMT
[AppClassLoader@18b4aac2] info register classloader sun.misc.Launcher$AppClassLoader@18b4aac2
[AppClassLoader@18b4aac2] info no configuration found. Disabling weaver for class loader sun.misc.Launcher$AppClassLoader@18b4aac2
Executing TestTarget.yourMethodBefore()
Executing TestTarget.yourMethodAfter()
Executing TestTarget.yourMethodAround()
i : 1
Executing TestTarget.yourMethodAround()
i : 1
x : Test
如何将我的方面(Project2)注入正在运行的program.jar(Project1)? 你有什么想法吗?
我将包含我创建的源代码和清单(两个项目)的所有文件作为.zip文件附加到以下链接中,这样您也可以尝试我到目前为止所做的事情。这可以帮助您更轻松地发现我的错误。该项目旨在在Windows命令行上运行。
链接:Downloadlink of my Projects
非常感谢你的想法!