为什么我的Javassist类在运行时没有被执行?

时间:2017-02-27 10:33:46

标签: java maven jar javassist

我一直在编写一个修改已加载类的字节码的java代理。 我的代码由4个类组成:

  1. StackTraceAgent.java - 带有方法的java代理类 的premain。
  2. StackTraceClassTransformer.java - 实现 java.lang.instrument.ClassFileTransformer。
  3. Student.java - 只是用于测试的自定义类。
  4. AgentTest - 使用方法main的简单类。
  5. 利用库:

    1. 了Javassist-3.20.0-GA.jar
    2. StackTraceAgent.java,ClassFileTransformer.java和javassist-3.20.0-GA.jar打包在一个jar文件中。它通过" -javaagent:MyJar.jar AgentTest"调用。我的问题是,在runtume中没有调用使用javassist类编写的代码。它只是由运行时传递而没有任何错误,并且在最后程序继续执行非javassist代码直到结束。

      我是如何尝试解决这个问题的:

      1. 我查看了编译类。所有类都包含确切的代码。
      2. 我觉得包装成罐子有点不对劲,但经过数小时的网上冲浪后,我找不到任何有趣的东西。
      3. MANIFEST.MF:

        Manifest-Version: 1.0
        Premain-Class: agent.StackTraceAgent
        

        我的pom.xml文件:

            <?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
            <modelVersion>4.0.0</modelVersion>
        
            <groupId>com.belenov</groupId>
            <artifactId>TraceAgent</artifactId>
            <version>1.0-SNAPSHOT</version>
        
            <dependencies>
                <!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
                <dependency>
                    <groupId>org.javassist</groupId>
                    <artifactId>javassist</artifactId>
                    <version>3.20.0-GA</version>
                </dependency>
        
            </dependencies>
        
            <build>
                <plugins>
        
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-dependency-plugin</artifactId>
                        <executions>
                            <execution>
                                <id>copy-dependencies</id>
                                <phase>prepare-package</phase>
                                <goals>
                                    <goal>copy-dependencies</goal>
                                </goals>
                                <configuration>
                                    <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                                    <overWriteReleases>false</overWriteReleases>
                                    <overWriteSnapshots>false</overWriteSnapshots>
                                    <overWriteIfNewer>true</overWriteIfNewer>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
        
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-jar-plugin</artifactId>
                        <configuration>
                            <archive>
                                <manifestFile>
                                    src/main/resources/META-INF/MANIFEST.MF
                                </manifestFile>
                                <manifest>
                                    <addClasspath>false</addClasspath>
                                </manifest>
                            </archive>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        

        StackTraceAgent.java:

        import java.lang.instrument.Instrumentation;
        public class StackTraceAgent  {
        
            public static void premain(String args, Instrumentation instrumentation) {
                System.out.println("instrument agent");
                StackTraceClassTransformer transformer = new StackTraceClassTransformer();
                instrumentation.addTransformer(transformer);
            }
        }
        

        StackTraceClassTransformer.java:

        import javassist.ClassPool;
        import javassist.CtClass;
        import javassist.CtMethod;
        
        import java.lang.instrument.ClassFileTransformer;
        import java.lang.instrument.IllegalClassFormatException;
        import java.security.ProtectionDomain;
        
        public class StackTraceClassTransformer implements ClassFileTransformer {
        
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                                    ProtectionDomain protectionDomain,
                                    byte[] classfileBuffer) throws IllegalClassFormatException {
        
                try {
                    //the code below is passed up
                    ClassPool classPool = ClassPool.getDefault();
                    CtClass ctClass = classPool.get(className);
                    CtMethod[] methods = ctClass.getMethods();
        
                    for (CtMethod method : methods) {
                        method.insertAfter("System.out.println(\"Method name: \"+" + method.getName() + "+\" \"+" + method.getSignature() + ");");
                        method.insertAfter("System.out.println(\"Object: \" + this.toString());");
                    }
        
                    byte[] byteCode = ctClass.toBytecode();
                    ctClass.detach();
                    return byteCode;
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                return null;
            }
        }
        

        AgentTest.java

        public class AgentTest {
            public static void main(String[] args) {
                System.out.println("Agent Tester");
                Student student = new Student("vasia", "poopkin");
                student.toString();
            }
        }
        

        Student.java

        public class Student {
            private String name;
            private String surname;
        
            public Student(String name, String surname) {
                this.name = name;
                this.surname = surname;
            }
        
            @Override
            public String toString() {
                return "Student{" +
                        "name='" + name + '\'' +
                        ", surname='" + surname + '\'' +
                        '}';
            }
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public String getSurname() {
                return surname;
            }
        
            public void setSurname(String surname) {
                this.surname = surname;
            }
        }
        

1 个答案:

答案 0 :(得分:1)

基本上在您的清单文件中,您需要包含程序使用的每个库和资源的类路径,您可以在MANIFEST.MF中添加如下所示的行:

Class-Path: path/to/my/libraries

这样做的一种方法就是更新你的pom.xml,maven jar插件的manifest部分:

<addClasspath>true</addClasspath>
<classpathPrefix>${project.build.directory}/classes/lib</classpathPrefix>