如何在运行时重新转换类
我正在修改已经加载到jvm中的类。我发现的解决方案是:
- 1st 将代理附加到 pid 指定的 jvm。(例如 8191)(代码:附加测试)
- 2nd 从 jvm 中已经加载的类(例如 8191)中查找要修改的类。
- 第三使用仪器添加变压器(代码:代理主)
- 第四修改方法中的类(例如人)(代码:DemoTransformer)
transform
- 第 5 次 使用重新转换类重新转换类
从第1步到第5步,它工作正常,但是在.它再次调用,其中包含修改类的代码。它修改了我永远不想修改的其他类。我认为问题可能发生在 或 期间。但我仍然感到困惑。那么,如何重新转换一个类?有什么想法吗?感谢retransformClasses
transform
addTransformer
retransformClasses
public class AttachTest {
public static void main(String[] args) throws AttachNotSupportedException,
IOException, AgentLoadException, AgentInitializationException {
String agentPath = "D:\\work\\workspace\\myjar\\loaded.jar";
String vid = args[0];
VirtualMachine vm = VirtualMachine.attach(vid);
vm.loadAgent(agentPath);
}
}
代理
public class AgentMain {
public static void agentmain (String agentArgs, Instrumentation inst)
throws ClassNotFoundException, UnmodifiableClassException,
InterruptedException {
Class<?> [] allLoadedClasses = inst.getAllLoadedClasses();
String tmpString = null;
for (int i = 0; i<allLoadedClasses.length; i++) {
tmpString = allLoadedClasses[i].getName();
if (0 != tmpString.length()) {
if (-1 != tmpString.lastIndexOf(".")) {
tmpString = tmpString.substring(tmpString.lastIndexOf(".")+1,tmpString.length());
}
if (tmpString.equals("Person")) {
inst.addTransformer(new DemoTransformer(), true);
inst.retransformClasses(allLoadedClasses[i]);
}
}
}
}
}
|
public class DemoTransformer implements ClassFileTransformer {
@Override
public byte[] transform (ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
ModifyMethodTest tm = new ModifyMethodTest(classfileBuffer);
byte[] byteArray = null;
try {
byteArray = tm.modiySleepMethod();
} catch (Exception e) {
e.printStackTrace();
}
return byteArray;
}
}
输出:附加程序
javax.management.RuntimeMBeanException: java.lang.RuntimeException: Failed to transform [Person]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.rethrow(DefaultMBeanServerInterceptor.java:856)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.rethrowMaybeMBeanException(DefaultMBeanServerInterceptor.java:869)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:838)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:761)
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1427)
at javax.management.remote.rmi.RMIConnectionImpl.access$200(RMIConnectionImpl.java:72)
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1265)
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1360)
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:788)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305)
at sun.rmi.transport.Transport$1.run(Transport.java:159)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142)
at com.sun.jmx.remote.internal.PRef.invoke(Unknown Source)
at javax.management.remote.rmi.RMIConnectionImpl_Stub.invoke(Unknown Source)
at javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.invoke(RMIConnector.java:993)
at AttachStackOverflow.main(AttachStackOverflow.java:57)
Caused by: java.lang.RuntimeException: Failed to transform [Person]
at loaded3.TransformerService.transform(TransformerService.java:75)
at loaded3.TransformerService.transformClass(TransformerService.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:93)
at com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:27)
at com.sun.jmx.mbeanserver.MBeanIntrospector.invokeM(MBeanIntrospector.java:208)
at com.sun.jmx.mbeanserver.PerInterface.invoke(PerInterface.java:120)
at com.sun.jmx.mbeanserver.MBeanSupport.invoke(MBeanSupport.java:262)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:836)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:761)
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1427)
at javax.management.remote.rmi.RMIConnectionImpl.access$200(RMIConnectionImpl.java:72)
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1265)
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1360)
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:788)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305)
at sun.rmi.transport.Transport$1.run(Transport.java:159)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)
at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:124)
at loaded3.TransformerService.transform(TransformerService.java:72)
... 31 more
产出:目标节目
print Call sayHello()
print Hello World!
Supported Redefine
Supported Retransform
Call transform() in TransformerService
Add transformer
support redefine. return TRUE
support retransforme. return TRUE
IsModifiable class "class Person". return TRUE
Retransform classes
Number of times to Call transform() in DemoTransformer:1
####ASM CODE####
consturct ModifyMethodTest
Call modifySleepMethod
new classreader
new classwriter
construct ModifyClassAdapter
sayHello
consturct Modifymethod
[arg1] = java/io/PrintStream [arg2] = println #5
[arg1] = java/io/PrintStream [arg2] = println #13
[arg1] = java/util/concurrent/TimeUnit [arg2] = sleep #22
[arg1] = java/io/PrintStream [arg2] = println #30
sayHello2
consturct Modifymethod
[arg1] = java/io/PrintStream [arg2] = println #5
[arg1] = java/io/PrintStream [arg2] = println #13
<init>
consturct Modifymethod
[arg1] = java/lang/Object [arg2] = <init> #1
main
consturct Modifymethod
[arg1] = Person [arg2] = <init> #4
[arg1] = Person [arg2] = sayHello #9
[arg1] = Person [arg2] = sayHello2 #13
[arg1] = java/lang/InterruptedException [arg2] = printStackTrace #21
getName
consturct Modifymethod
setName
consturct Modifymethod
Call visitend
Finished to call modifymethodtest
####End of ASM CODE
Remove transformer
Call transform() in TransformerService
Add transformer
support redefine. return TRUE
support retransforme. return TRUE
IsModifiable class "class Person". return TRUE
Retransform classes
Number of times to Call transform() in DemoTransformer:2
####ASM CODE####
consturct ModifyMethodTest
Call modifySleepMethod
new classreader
new classwriter
construct ModifyClassAdapter
sayHello
consturct Modifymethod
[arg1] = java/io/PrintStream [arg2] = println #5
[arg1] = java/io/PrintStream [arg2] = println #13
[arg1] = java/util/concurrent/TimeUnit [arg2] = sleep #22
[arg1] = java/io/PrintStream [arg2] = println #30
sayHello2
consturct Modifymethod
[arg1] = java/io/PrintStream [arg2] = println #5
[arg1] = java/io/PrintStream [arg2] = println #13
<init>
consturct Modifymethod
[arg1] = java/lang/Object [arg2] = <init> #1
main
consturct Modifymethod
[arg1] = Person [arg2] = <init> #4
[arg1] = Person [arg2] = sayHello #9
[arg1] = Person [arg2] = sayHello2 #13
[arg1] = java/lang/InterruptedException [arg2] = printStackTrace #21
getName
consturct Modifymethod
setName
consturct Modifymethod
Call visitend
Finished to call modifymethodtest
####End of ASM CODE
Remove transformer
print in sayHello()
print Call sayHello2()
print Hello World!2