网站的用途,宝塔和WordPress一样吗,淘宝客可以自己做网站推广吗,网站代理被抓Arthas#xff08;阿尔萨斯#xff09;是一款开源的Java诊断和监控工具#xff0c;可以在生产环境中进行实时的应用程序分析和故障排查。Arthas的实现原理主要基于Java Instrumentation API和Java Agent技术。
Java Agent 是 Java 编程语言提供的一种特殊机制#xff0c;允…Arthas阿尔萨斯是一款开源的Java诊断和监控工具可以在生产环境中进行实时的应用程序分析和故障排查。Arthas的实现原理主要基于Java Instrumentation API和Java Agent技术。
Java Agent 是 Java 编程语言提供的一种特殊机制允许你在程序运行过程中对字节码进行转换和增强。它是通过 Java 的 Instrumentation API 来实现的可以用于在应用程序加载类时进行监测、修改和增强。Java Agent 通常被用于实现性能监测、代码分析、方法耗时统计、字节码增强等功能。
Java Agent 的主要特点 动态性 Java Agent 允许你在程序运行时加载代理类对类进行转换和增强从而实现动态修改已编译类的功能。 无侵入性 使用 Java Agent 不需要修改源代码也不需要重新编译。这使得你可以在不改变程序结构的情况下实现一些横切关注点的逻辑。 全局性 Java Agent 可以在整个 JVM 中生效对加载的所有类都可以进行转换和增强。这使得你可以监测、分析和增强全局的应用行为。
Java Agent 的使用步骤
开发 Java Agent 的涉及的要点如下图所示 image.png
要使用 Java Agent通常需要遵循以下步骤 创建代理类 创建一个代理类实现 java.lang.instrument.Instrumentation 接口的 premain 方法。 注册代理类 在代理类的 premain 方法中注册代理类。这将使代理类在 JVM 启动时加载并执行。 定义转换规则 在代理类中你可以使用 Instrumentation API 来定义转换规则即如何对类的字节码进行转换。
示例方法计时器 Java Agent
以下是一个简单的 Java Agent 示例实现对所有方法的计时统计
import java.lang.instrument.Instrumentation;public class MethodTimerAgent {public static void premain(String agentArgs, Instrumentation instrumentation) {System.out.println(Agent premain called);instrumentation.addTransformer(new MethodTimerTransformer());}
}增加创建一个 ClassFileTransformer 接口的实现类 MethodTimerTransformer
public class MethodTimerTransformer implements ClassFileTransformer { private final static String prefix \nlong startTime System.currentTimeMillis();\n; private final static String postfix \nlong endTime System.currentTimeMillis();\n; // 被处理的方法列表 final static MapString, ListString methodMap new HashMapString, ListString(); public MethodTimerTransformer() { add(com.example.TimeTest.sayHello); } private void add(String methodString) { String className methodString.substring(0, methodString.lastIndexOf(.)); String methodName methodString.substring(methodString.lastIndexOf(.) 1); ListString list methodMap.get(className); if (list null) { list new ArrayListString(); methodMap.put(className, list); } list.add(methodName); } Override public byte[] transform( ClassLoader loader, String className, Class? classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (className.startsWith(com/example/)) { className className.replace(/, .); System.out.println(Transforming class: className); // 在方法前后添加计时逻辑 CtClass ctclass null; try { ctclass ClassPool.getDefault().get(className);// 使用全称,用于取得字节码类使用javassist System.out.println(ctclass.getName()); for (String methodName : methodMap.get(className)) { System.out.println(methodName); String outputStr \nSystem.out.println(\this method methodName cost:\ (endTime - startTime) \ms.\);; CtMethod ctmethod ctclass.getDeclaredMethod(methodName);// 得到这方法实例 String newMethodName methodName $old;// 新定义一个方法叫做比如sayHello$old ctmethod.setName(newMethodName);// 将原来的方法名字修改 // 创建新的方法复制原来的方法名字为原来的名字 CtMethod newMethod CtNewMethod.copy(ctmethod, methodName, ctclass, null); // 构建新的方法体 StringBuilder bodyStr new StringBuilder(); bodyStr.append({); bodyStr.append(prefix); bodyStr.append(newMethodName ($$);\n);// 调用原有代码类似于method();($$)表示所有的参数 bodyStr.append(postfix); bodyStr.append(outputStr); bodyStr.append(}); newMethod.setBody(bodyStr.toString());// 替换新方法 ctclass.addMethod(newMethod);// 增加新方法 } return ctclass.toBytecode(); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } return classfileBuffer; }
}在上述示例中MethodTimerAgent 是 Java Agent 的代理类通过 premain 方法注册了 MethodTimerTransformer 类。MethodTimerTransformer 是转换器类实现了 ClassFileTransformer 接口允许你在 transform 方法中修改目标类的字节码。
这里的对字节码的修改用到了javassistjavassist介绍可以参考字节码增强技术-Javassist
想要其他项目使用我们还需完成以下几步
创建文件resources/META-INF/MANIFEST.MF,内容如下
Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: com.example.MethodTimerAgent
Boot-Class-Path: javassist-3.28.0-GA.jarpom文件增加下面配置
build plugins plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-jar-plugin/artifactId version2.4/version configuration archive !-- 就是把前面的配置的MANIFEST.MF打入jar中以指定premain的位置否则会报 Failed to find Premain-Class manifest attribute in -- manifestFile${maven.configuration.manifestFile}/manifestFile /archive /configuration /plugin /plugins
/build使用 Java Agent
我们新建一个项目增加一个测试类
public class TimeTest { public static void main(String[] args) { sayHello(); } public static void sayHello() { try { Thread.sleep(2000); System.out.println(hello world!!); } catch (InterruptedException e) { e.printStackTrace(); } }
}要使用 Java Agent你需要将代理类打包成 JAR 文件并在启动 JVM 时使用 -javaagent 参数指定该 JAR 文件的路径。例如
java -javaagent:path/to/agent.jar -jar your-application.jar我们这里直接在idea上测试
增加VM Options参数 由于我们使用到了javassist,需要将javassist的jar与java-agent的jar放在一起 最后我们运行我们的测试类TimeTest结果如下 可以看到方法执行耗时被打印出来了。