美文网首页
skywalking之javassist

skywalking之javassist

作者: david161 | 来源:发表于2022-04-03 19:51 被阅读0次

目的

使用javaagent和javassist实现了把特定包下面的class的所有类的所有有body的非native的方法前面添加一句 System.out.println("hello im agent :" + ctMethod.getName());

javassist简介

Java 字节码以二进制的形式存储在 .class 文件中,每一个 .class 文件包含一个 Java 类或接口。Javassist 就是一个用来 处理 Java 字节码的类库。它可以在一个已经编译好的类中添加新的方法,或者是修改已有的方法,并且不需要对字节码方面有深入的了解。同时也可以去生成一个新的类对象,通过完全手动的方式。

增加依赖

agentdemo1项目的pom文件增加javassist依赖包

<dependencies> 
    <dependency> 
        <groupId>org.javassist</groupId> 
        <artifactId>javassist</artifactId> 
        <version>3.27.0-GA</version> 
    </dependency> 
</dependencies>

FirstAgent类

FirstAgent类实现ClassFileTransformer接口。重写transform方法。实现 ClassFileTransformer 这个接口的目的就是在class被装载到JVM之前将class字节码转换掉,从而达到动态注入代码的目的。其中代码的修改使用到了javassist。
FirstAgent类实现了把特定包下面的class的所有类的所有有body的非native的方法前面添加一句System.out.println("hello im agent :" + ctMethod.getName());

package com.david.instrumentationimpl; 

import javassist.ClassPool; 
import javassist.CtClass; 
import javassist.CtMethod; 
import javassist.bytecode.CodeAttribute; 
import java.lang.instrument.ClassFileTransformer; 
import java.lang.instrument.IllegalClassFormatException; 
import java.security.ProtectionDomain; 

public class FirstAgent implements ClassFileTransformer { 
    
    //对特定包下的类修改字节码 
    public final String injectedClassName = "com.lagou.test"; 
    
    @Override 
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, 
                            ProtectionDomain protectionDomain,byte[] classfileBuffer) throws IllegalClassFormatException { 

        className = className.replace("/", "."); 
        if (className.startsWith(injectedClassName)) { 
            CtClass ctclass = null; 
            try {
                // 使用全称,用于取得字节码类,使用javassist技术实现 
                ctclass = ClassPool.getDefault().get(className); 
                CtMethod[] ctmethods = ctclass.getMethods(); 
                for (CtMethod ctMethod : ctmethods) { 
                    CodeAttribute ca = ctMethod.getMethodInfo2().getCodeAttribute(); 
                    if (ca == null) { 
                        continue; 
                    }
                    if (!ctMethod.isEmpty()) { 
                        ctMethod.insertBefore("System.out.println(\"hello Im agent : " + ctMethod.getName() + "\");"); 
                    } 
                }
                return ctclass.toBytecode(); 
            } 
            catch (Exception e) { 
                System.out.println(e.getMessage()); e.printStackTrace(); 
            } 
        }
           
        return null; 
    } 
}

PremainTest1类

package com.lagou.agent; 

import com.lagou.instrumentationimpl.FirstAgent; 
import java.lang.instrument.ClassFileTransformer; 
import java.lang.instrument.IllegalClassFormatException; 
import java.lang.instrument.Instrumentation; 
import java.security.ProtectionDomain; 

public class PremainTest1 { 
    public static void premain(String agentArgs, Instrumentation inst) { 
        System.out.println("hello agent demo1"); 
        System.out.println("agentArgs =====> " + agentArgs); 
        inst.addTransformer(new FirstAgent()); 
    }
    
    public static void premain(String agentArgs) {
        System.out.println("hello agent demo2"); 
        System.out.println("agentArgs =====> " + agentArgs); 
    } 
}

更新打包插件

使用maven-jar-plugin插件进行打包。无法将第三方依赖的javassist包进行打包。如果需要将依赖包打入jar中。需要额外引入maven-dependency-plugin插件。为了简单,使用maven-shade-plugin进行打包。
修改agentdemo1的pom文件。将打包插件更换为maven-shade-plugin。

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-shade-plugin</artifactId> 
    <version>3.2.4</version> 
    <executions> 
        <execution> 
            <phase>package</phase> 
            <goals> 
                <goal>shade</goal> 
            </goals> 
            <configuration> 
                <transformers> 
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTr ansformer"> 
                        <manifestEntries> 
                            <Premain- Class>com.lagou.agent.PremainTest1</Premain-Class> 
                        </manifestEntries> 
                    </transformer> 
                </transformers> 
            </configuration> 
        </execution> 
    </executions> 
</plugin>
打包
mvn clean package
agenttest1项目

修改AgentTest1类

package com.lagou.test1;

public class AgentTest1 { 
    public static void main(String[] args) { 
        System.out.println("这里是agent第一个main方法测试。"); testAgent(); t
        estAgent1("one", "two"); 
    }
    
    public static void testAgent() { 
        System.out.println("test agent say hello"); 
    }
    
    public static void testAgent1(String one, String two) { 
        System.out.println("test agent say hello" + one + two); 
    } 
}
测试
测试结果如下: 

hello agent demo1 
agentArgs =====> lagou 
hello Im agent : main 
这里是agent第一个main方法测试。 
hello Im agent : testAgent 
test agent say hello 
hello Im agent : testAgent1 
test agent say helloonetwo 

Process finished with exit code 0
独立测试

脱离idea开发工具,独立使用java -javaagent命令测试。
通过 -javaagent 参数来指定我们的Java代理包,值得一说的是 -javaagent 这个参数的个数是不限的,如果指定了多个,则会按指定的先后执行,执行完各个 agent 后,才会执行主程序的 main 方法。
特别提醒:如果你把 -javaagent 放在 -jar 后面,则不会生效。也就是说,放在主程序后面的 agent 是无效的。
class方式
agentdemo1项目打jar包
agenttest1项目没有打包。进入 ..\agenttest1\target\classes目录中,执行如下命令
java -javaagent:e:\javaagent\agentdemo1.jar com.lagou.test1.AgentTest1
jar包方式
agentdemo1和agenttest1两个项目全部打jar包。

<build> 
    <finalName>agenttest1</finalName> 
    <plugins> 
        <plugin> 
            <groupId>org.apache.maven.plugins</groupId> 
            <artifactId>maven-jar-plugin</artifactId> 
            <version>3.2.0</version> 
            <configuration> 
                <archive> 
                <!--自动添加META-INF/MANIFEST.MF --> 
                    <manifest> 
                        <addClasspath>true</addClasspath> 
                    <mainClass>com.lagou.test1.AgentTest1</mainClass> 
                    </manifest> 
                    </archive> 
            </configuration> 
        </plugin> 
    </plugins> 
</build>
agentdemo1项目打包:将agentdemo1.jar复制到d:\javaagent目录中 
mvn clean package 

agenttest1项目打包:将agenttest1.jar复制到d:\javaagent目录中 

使用java -javaagent命令,不带参数 
java -javaagent:d:\javaagent\agentdemo1.jar -jar agenttest1.jar 

使用java -javaagent命令,带参数 
java -javaagent:d:\javaagent\agentdemo1.jar -jar agenttest1.jar

相关文章

网友评论

      本文标题:skywalking之javassist

      本文链接:https://www.haomeiwen.com/subject/pbmrjrtx.html