Javaagent使用介绍 Java动态代理
- 2021-12-25 23:33:00
- admin
- 原创 1938
一、Javaagent使用介绍
1、javaagent通过premain或angentmain方法注入java应用,从而影响应用执行,用于热部署或监控;
2、java应用可以加载多个代理,premain代理必须位于命令行参数的主类或-jar参数前面;
3、premain(String,Instrumentation)优先级高于premain(String),两个方法同时存在时执行前者;
4、agentmain(String,Instrumentation)优先级高于agentmain(String),两个方法同时存在时执行前者;
5、代理包的MANIFEST文件必须包含Premain-Class或Agent-Class;
程序启动前注入:
程序启动前代理类:AgentStatic.java
程序启动前代理清单:agent-static.mf
测试程序:AgentTest.java
打包以及执行:
jar cvfm myagent1.jar agent-static.mf -C target\classes javaagent\AgentStatic.class
java -javaagent:myagent1.jar=myagent -classpath target\classes javaagent.AgentTest
执行输出:
AgentStatic::premain(String,Instrumentation)
myagent
main
程序启动后注入:
程序启动后代理类:AgentDynamic.java
程序启动后代理清单:agent-dynamic.mf
注入程序:AttachApp.java
打包以及执行:
jar cvfm myagent2.jar agent-dynamic.mf -C target\classes javaagent\AgentDynamic.class
java -classpath "target\classes;%JAVA_HOME%\lib\tools.jar" javaagent.AttachApp pid myagent2.jar myagent
执行输出:
AgentDynamic::agentmain(String,Instrumentation)
myagent
二、Java动态代理
1、如果需要对接口进行代理,则使用JDK动态代理;
2、如果需要对类进行代理,则使用CGLib动态代理;
3、如果希望直接修改字节码,则使用Javassist动态代理;
JDK动态代理:
1、Proxy.newProxyInstance(loader,interfaces,h)生成代理对象,实现了被代理对象的接口;
2、代理对象所有方法实际调用InvocationHandler.invoke(proxy,method,args);
3、proxy是虚拟机生成的代理对象,method是被代理的方法,args是方法的参数;
4、InvocationHandler.invoke实际调用method.invoke(obj,args),obj是被代理对象;
5、sun.misc.ProxyGenerator.saveGeneratedFiles=true,代理类写入文件系统;
6、动态代理代码示例:ProxyDemo.java
CGLib动态代理:
1、Enhancer.setSuperclass(cls)设置需要代理的类;
2、Enhancer.setCallback(callback)设置代理处理逻辑;
3、Enhancer.create()生成代理对象,继承了被代理的类;
4、代理对象所有非static非final方法被重载,实际调用MethodInterceptor.intercept(proxy,method,args,methodProxy);
5、代理对象所有非static非final方法会新增方法methodname$0(),实际调用super.methodname();
6、CGLib同时会生成两个FastClass,一个调用methodname$0(),另外一个调用methodname();
7、MethodProxy.invokeSuper调用第一个FastClass,MethodProxy.invoke调用第二个FastClass;
8、动态代理代码示例:CGLibDemo.java
Javassist动态代理:
1、Javassist可以直接使用源代码来修改字节码,使用起来非常方便;
2、帮助指南:https://www.javassist.org/tutorial/tutorial.html
3、修改字节码示例:JavassistDemo.java