我正在使用jdk1.6。我在运行时成功加载了一个jar。代码如下:
vm = VirtualMachine.attach(vid);
vm.loadAgent(agentPath);
现在我想在运行时卸载这个代理。没有API DOC可以做到这一点。谁能给我一些建议?感谢。
修改
更多代码
GlobalVariables.vm = VirtualMachine.attach(vid);
// Check to see if transformer agent is installed
if(!GlobalVariables.vm.getSystemProperties().contains("demo.agent.installed")) {
System.out.println("Load agent");
GlobalVariables.vm.loadAgent(agentPath);
}
GlobalVariables.connectorAddress = GlobalVariables.vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress", null);
if(null == GlobalVariables.connectorAddress) {
// It's not, so install the management agent
String javaHome = GlobalVariables.vm.getSystemProperties().getProperty("java.home");
File managementAgentJarFile = new File(javaHome + File.separator + "lib" + File.separator + "management-agent.jar");
GlobalVariables.vm.loadAgent(managementAgentJarFile.getAbsolutePath());
System.out.println("Load Management agent");
GlobalVariables.connectorAddress = GlobalVariables.vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress", null);
// Now it's installed
}
// Now connect and transform the classnames provided in the remaining args.
//JMXConnector connector = null;
try {
// This is the ObjectName of the MBean registered when loaded.jar was installed.
//ObjectName on = new ObjectName("transformer:service=DemoTransformer");
GlobalVariables.on = new ObjectName("transformer:service=DemoTransformer");
// Here we're connecting to the target JVM through the management agent
GlobalVariables.connector = JMXConnectorFactory.connect(new JMXServiceURL(GlobalVariables.connectorAddress));
GlobalVariables.server = GlobalVariables.connector.getMBeanServerConnection();
System.out.println("MBean Server connection...");
// Call transformClass on the transformer MBean
GlobalVariables.server.invoke(GlobalVariables.on, "transformClass", new Object[]{className, args}, new String[]{String.class.getName(), String.class.getName()});
} catch (Exception ex) {
ex.printStackTrace(System.err);
} finally {
if(GlobalVariables.connector!=null) try { GlobalVariables.connector.close(); } catch (Exception e) {}
GlobalVariables.vm.detach();
System.out.println("Has disconnected");
}
我接下来做了什么
我再次运行上面的代码再次加载这两个代理。但是我遇到了错误。
错误
当前vm 中的 错误
错误 目标 做同样的工作,没有错误。每当我完成工作时,我想我需要卸载代理。但是我没能卸下这些代理商。 编辑GlobleVariables
目标虚拟机中的com.sun.tools.attach.AgentInitializationException: Agent JAR loaded but agent failed to initialize
at sun.tools.attach.HotSpotVirtualMachine.loadAgent(HotSpotVirtualMachine.java:103)
at com.sun.tools.attach.VirtualMachine.loadAgent(VirtualMachine.java:508)
at faultinjectionaction.AttachClass.attachAgent(AttachClass.java:111)
at org.apache.jsp.fjstep3_jsp._jspService(fjstep3_jsp.java:350)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
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)
Exception in thread "Attach Listener" java.lang.reflect.InvocationTargetException
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.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:323)
at sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:348)
Caused by: javax.management.InstanceAlreadyExistsException: transformer:service= DemoTransformer
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:453)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.internal_addObject(DefaultMBeanServerInterceptor.java:1484)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:963)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:917)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:312)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:482)
at faultinjectionagent.AgentMain.agentmain(AgentMain.java:28)
... 6 more
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import com.sun.tools.attach.VirtualMachine;
public class GlobalVariables{
public static MBeanServerConnection server;
public static ObjectName on;
public static JMXConnector connector = null;
public static String connectorAddress = null;
public static VirtualMachine vm;
}
答案 0 :(得分:2)
卸载代理是什么意思?您无法卸载类,因为它在文档中隐含地说:
将指定的JAR文件添加到系统类路径中 目标虚拟机)
这可能是一些自定义类加载器魔法的唯一方法,但我不建议这样做。
更新:在查看扩展问题后,我认为您的问题实际上是其他问题。在某些时候你正在调用
JMXConnectorFactory.connect(new JMXServiceURL(GlobalVariables.connectorAddress))
以创建JMXConnector
。我想在你的GlobalVariables.server.invoke
电话中,你正在new ObjectName("transformer:service=DemoTransformer")
注册一个MBean。此名称必须是唯一的,当您第二次运行代码时,此名称已按照javax.management.InstanceAlreadyExistsException: transformer:service= DemoTransformer
的建议采用。你需要做的是:
MBeanServerConnection.close(new ObjectName("transformer:service=DemoTransformer"))
以使名称再次可用。您可能认为通过分离,远程计算机上的所有状态都已重置。然而,事实并非如此。您添加了一个带有名称的MBean,而不是您尝试再次执行此操作。可以将此错误理解为将两个具有相同键的值添加到地图中。除了地图之外,您不会覆盖值,但会导致您在上面观察到的异常。
顺便说一下:当不再需要与远程服务器的连接时,应该明确地调用JMXConnector.close
。
PS:你可能会发现this article很有趣。
更新2 :在聊天讨论之后以及在获得MBean命名冲突之后,我认为这是导致问题的原因:
第二次加载Java代理时,代理附带的类(在managementAgentJarFile
中表示)已经加载到目标JVM中。这意味着,将不会再次运行类初始值设定项,并且仍将表示由static
变量表示的状态更改。此外,无法加载具有相同名称但已更改实现的类。这将导致LinkageError
并且代理加载将失败。解决方案是避免static
状态,以便代理不会对自身造成影响并为不同的代理创建单独的名称空间。否则,可以使用自定义类加载器卸载代理类。关于这个问题的更多信息可以在很多地方找到,并在这里: