欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 人文社科 > 生活经验 >内容正文

生活经验

Java字节码instrument研究

发布时间:2023/11/27 生活经验 63 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Java字节码instrument研究 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

MyAgent项目

<?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.book.MyAgent</groupId><artifactId>MyAgent</artifactId><version>1.0</version><dependencies><dependency><groupId>javassist</groupId><artifactId>javassist</artifactId><version>3.12.1.GA</version></dependency><dependency><groupId>org.ow2.asm</groupId><artifactId>asm-all</artifactId><version>5.1</version></dependency><dependency><groupId>net.bytebuddy</groupId><artifactId>byte-buddy</artifactId><version>1.5.7</version></dependency><dependency><groupId>net.bytebuddy</groupId><artifactId>byte-buddy-agent</artifactId><version>1.5.7</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-source-plugin</artifactId><version>3.0.1</version><executions><execution><id>attach-sources</id><phase>verify</phase><goals><goal>jar-no-fork</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>2.6</version><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><archive><manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile></archive></configuration><executions><execution><id>assemble-all</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><executions><execution><phase>package</phase><goals><goal>shade</goal></goals></execution></executions><configuration><artifactSet><includes><include>javassist:javassist:jar:</include><include>net.bytebuddy:byte-buddy:jar:</include><include>net.bytebuddy:byte-buddy-agent:jar:</include></includes></artifactSet></configuration></plugin></plugins><resources><resource><directory>${basedir}/src/main/resources</directory></resource><resource><directory>${basedir}/src/main/java</directory></resource></resources></build>
</project>

 

AgentTime类

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;public class AgentTime {public static void premain(String agentArgs, Instrumentation inst) {System.out.println("监控耗时 >>>");// 添加 TransformerClassFileTransformer transformer = new PerformMonitorTransformer();inst.addTransformer(transformer);System.out.println("监控耗时 <<<");}
}

PerformMonitorTransformer类

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;public class PerformMonitorTransformer implements ClassFileTransformer {private static final Set<String> classNameSet = new HashSet<>();static {classNameSet.add("com.book.test.TestTime");}@Overridepublic byte[] transform(ClassLoader loader,String className,Class<?> classBeingRedefined,ProtectionDomain protectionDomain,byte[] classfileBuffer) throws IllegalClassFormatException {//System.out.println("监控耗时 >>>1");try {String currentClassName = className.replaceAll("/", ".");if (!classNameSet.contains(currentClassName)) { // 仅仅提升Set中含有的类return null;}System.out.println("transform: [" + currentClassName + "]");CtClass ctClass = ClassPool.getDefault().get(currentClassName);CtBehavior[] methods = ctClass.getDeclaredBehaviors();for (CtBehavior method : methods) {System.out.println("method: [" + method + "]");enhanceMethod(method);}CtMethod m = ctClass.getDeclaredMethod("fun1");m.insertBefore("{ System.out.println($1); System.out.println($2); }");           return ctClass.toBytecode();} catch (Exception e) {e.printStackTrace();}return null;}private void enhanceMethod(CtBehavior method) throws Exception {if (method.isEmpty()) {return;}String methodName = method.getName();if (methodName.equalsIgnoreCase("main")) { // 不提升main方法return;}CtClass[] prams = method.getParameterTypes();if (prams.length > 0) {method.insertBefore("{ System.out.println($1);System.out.println($2); }");}final StringBuilder source = new StringBuilder();if (methodName.equalsIgnoreCase("fun3")) { // 修改fun3方法source.append("{").append("System.out.println(\"方法三真的被替换了\");").append("\n").append("}");} else {source.append("{").append("long start = System.nanoTime();\n") // 前置增强: 打入时间戳.append("$_ = $proceed($$);\n") // 保留原有的代码处理逻辑                  .append("System.out.print(\"method:[" + methodName + ">>>]\");").append("\n").append("System.out.println(\" cost:[\" +(System.nanoTime() -start)+ \"ns]\");") // 后置增强.append("}");}ExprEditor editor = new ExprEditor() {@Overridepublic void edit(MethodCall methodCall) throws CannotCompileException {methodCall.replace(source.toString());}};method.instrument(editor);}
}

被增强的项目:

TestAgent

<?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.book</groupId><artifactId>TestAgent</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><build><plugins><plugin>    <artifactId>maven-assembly-plugin</artifactId>    <configuration>    <appendAssemblyId>false</appendAssemblyId>    <descriptorRefs>    <descriptorRef>jar-with-dependencies</descriptorRef>    </descriptorRefs>    <archive>    <manifest>    <mainClass>com.book.test.TestTime</mainClass>    </manifest>    </archive></configuration>    <executions>    <execution>    <id>make-assembly</id>    <phase>package</phase>    <goals>    <goal>assembly</goal>    </goals>    </execution>    </executions>    </plugin>            </plugins></build>
</project>

 TestTime类

public class TestTime {private int fun1(int a,int b) {System.out.println("\n方法一开始>>>");return a+b;}private void fun2() {System.out.println("\n方法二开始>>>");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace(); }System.out.println("方法二结束<<<");}private void fun3() {System.out.println("方法三会被干掉么?");        }public static void main(String[] args) {TestTime test = new TestTime();test.fun1(2,3);test.fun2();test.fun3();}
}

运行:

java  -javaagent:E:\worktest\MyAgent\target\MyAgent-1.0-jar-with-dependencies.jar -jar E:\worktest\TestAgent\target\TestAgent-1.0-SNAPSHOT.jar com.book.test.TestTime

 

参考:https://blog.csdn.net/f59130/article/details/78481594

Javassist 使用指南(三)

总结

以上是生活随笔为你收集整理的Java字节码instrument研究的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。