AspectJ加载时间编织 - 命令行项目

时间:2017-05-09 15:07:38

标签: java command-line jar aspectj load-time-weaving

我在一个简单的项目上挣扎,因为我无法运行。

我的目标是扩展.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

非常感谢你的想法!

0 个答案:

没有答案