JVM本身提供了一组管理的API,通过该API,我们可以获取得到JVM内部主要运行信息,包括内存各代的数据、JVM当前所有线程及其栈相关信 息等等。各种JDK自带的剖析工具,包括jps、jstack、jinfo、jstat、jmap、jconsole等,都是基于此API开发的。本篇对 这部分内容进行一个详细的说明。
参考:http://java.sun.com/javase/6/docs/api/java/lang/management/package-summary.html
一、Management API
我们先看一下从Sun JVM我们可以获取到哪些信息,如下图(来自于JConsole的MBean部分的截图):
1.HotSpotDiagnostic:非标准的监控JMX,这块是Sun JVM自带的,主要提供了两个功能
- 修改JVM的启动参数(譬如在不需要重启的情况下设置-XX:+HeapDumpOnOutOfMemoryError参数使得JVM内存不足的时候自动dump出堆空间到文件提供后续分析)
- Dump堆信息到文件,可以猜测jmap工具是基于此功能来完成的
我们通过com.sun.management.HotSpotDiagnosticMXBean定义了解其主要功能
- public interface HotSpotDiagnosticMXBean
- {
- void dumpHeap(String s, boolean flag) throws IOException;
- List getDiagnosticOptions();
- VMOption getVMOption(String s);
- void setVMOption(String s, String s1);
- }
[java] view plain copy
- public interface HotSpotDiagnosticMXBean
- {
- void dumpHeap(String s, boolean flag) throws IOException;
- List getDiagnosticOptions();
- VMOption getVMOption(String s);
- void setVMOption(String s, String s1);
- }
2.ClassLoading:加载的类的总体信息,我们可以通过此MBean获取到JVM加载的类定义的总体信息,可以猜测JConsole的类功能就
是通过此MBean来提供的。我们可以通过java.lang.management.ClassLoadingMXBean定义了解其提供的主要功能
- public interface ClassLoadingMXBean {
- public long getTotalLoadedClassCount();
- public int getLoadedClassCount();
- public long getUnloadedClassCount();
- public boolean isVerbose();
- public void setVerbose(boolean value);
- }
[java] view plain copy
- public interface ClassLoadingMXBean {
- public long getTotalLoadedClassCount();
- public int getLoadedClassCount();
- public long getUnloadedClassCount();
- public boolean isVerbose();
- public void setVerbose(boolean value);
- }
3.Compilation:提供JVM的JIT(Just In Time)编译器(将bytecode编译成native
code)的信息,我们可以通过java.lang.management.CompilationMXBean定义了解其提供的主要功能
- public interface CompilationMXBean {
- public java.lang.String getName();
- public boolean isCompilationTimeMonitoringSupported();
- public long getTotalCompilationTime();
- }
[java] view plain copy
- public interface CompilationMXBean {
- public java.lang.String getName();
- public boolean isCompilationTimeMonitoringSupported();
- public long getTotalCompilationTime();
- }
4.GarbageCollector:垃圾回收器信息,譬如在如上图中,我们启动的JVM会包含一个Copy垃圾回收器(用于Young
Gen垃圾回收)和一个MarkAndSweep垃圾回收器(用于Tenured
Gen垃圾回收)。我们可以通过java.lang.management.GarbageCollectorMXBean定义了解其提供的主要功能
- public interface GarbageCollectorMXBean extends MemoryManagerMXBean {
- public long getCollectionCount();
- public long getCollectionTime();
- }
[java] view plain copy
- public interface GarbageCollectorMXBean extends MemoryManagerMXBean {
- public long getCollectionCount();
- public long getCollectionTime();
- }
java.lang.management.MemoryManagerMXBean定义是
- public interface MemoryManagerMXBean {
- public String getName();
- public boolean isValid();
- public String[] getMemoryPoolNames();
- }
[java] view plain copy
- public interface MemoryManagerMXBean {
- public String getName();
- public boolean isValid();
- public String[] getMemoryPoolNames();
- }
除了如上信息,Sun JVM在实现上还提供了一个额外的信息LastGCInfo,见com.sun.management.GarbageCollectorMXBean定义
- public interface GarbageCollectorMXBean
- extends java.lang.management.GarbageCollectorMXBean
- {
- GcInfo getLastGcInfo();
- }
[java] view plain copy
- public interface GarbageCollectorMXBean
- extends java.lang.management.GarbageCollectorMXBean
- {
- GcInfo getLastGcInfo();
- }
我们可以通过下面的截图了解GcInfo包含的主要信息
其中java.lang.management.MemoryUsage后续可以看说明
5.内存相关
可以猜测,JConsole的内存部分的功能都是通过此部分的相关Bean来完成的。
1)Memory/MemoryManager:内存块相关信息,通过这MBean我们可以获取到内存的总体信息,并可以通过提供的gc操作进行强制gc
的功能(System.gc())。我们可以通过java.lang.management.MemoryMXBean和
java.lang.management.MemoryManagerMXBean了解其主要提供的功能
- public interface MemoryMXBean {
- public int getObjectPendingFinalizationCount();
- public MemoryUsage getHeapMemoryUsage();
- public MemoryUsage getNonHeapMemoryUsage();
- public boolean isVerbose();
- public void setVerbose(boolean value);
- public void gc();
- }
[java] view plain copy
- public interface MemoryMXBean {
- public int getObjectPendingFinalizationCount();
- public MemoryUsage getHeapMemoryUsage();
- public MemoryUsage getNonHeapMemoryUsage();
- public boolean isVerbose();
- public void setVerbose(boolean value);
- public void gc();
- }
其中java.lang.management.MemoryUsage我们可以通过下图来了解其提供的主要信息
- public interface MemoryManagerMXBean {
- public String getName();
- public boolean isValid();
- public String[] getMemoryPoolNames();
- }
[java] view plain copy
- public interface MemoryManagerMXBean {
- public String getName();
- public boolean isValid();
- public String[] getMemoryPoolNames();
- }
2)MemoryPool:通过该MBean可以了解JVM各内存块的信息,譬如对于Sun JVM,目前包括Eden
Space、Suvivor Space、Tenured Gen、CodeCache、Perm
Gen,可以猜测JConsole的内存监控功能就是通过此MBean来做到的。我们可以通过
java.lang.management.MemoryPoolMXBean了解其主要提供的功能
- public interface MemoryPoolMXBean {
- public String getName();
- public MemoryType getType();
- public MemoryUsage getUsage();
- public MemoryUsage getPeakUsage();
- public void resetPeakUsage();
- public boolean isValid();
- public String[] getMemoryManagerNames();
- public long getUsageThreshold();
- public void setUsageThreshold(long threshold);
- public boolean isUsageThresholdExceeded();
- public long getUsageThresholdCount();
- public boolean isUsageThresholdSupported();
- public long getCollectionUsageThreshold();
- public void setCollectionUsageThreshold(long threhsold);
- public boolean isCollectionUsageThresholdExceeded();
- public long getCollectionUsageThresholdCount();
- public MemoryUsage getCollectionUsage();
- public boolean isCollectionUsageThresholdSupported();
- }
[java] view plain copy
- public interface MemoryPoolMXBean {
- public String getName();
- public MemoryType getType();
- public MemoryUsage getUsage();
- public MemoryUsage getPeakUsage();
- public void resetPeakUsage();
- public boolean isValid();
- public String[] getMemoryManagerNames();
- public long getUsageThreshold();
- public void setUsageThreshold(long threshold);
- public boolean isUsageThresholdExceeded();
- public long getUsageThresholdCount();
- public boolean isUsageThresholdSupported();
- public long getCollectionUsageThreshold();
- public void setCollectionUsageThreshold(long threhsold);
- public boolean isCollectionUsageThresholdExceeded();
- public long getCollectionUsageThresholdCount();
- public MemoryUsage getCollectionUsage();
- public boolean isCollectionUsageThresholdSupported();
- }
6.系统运行信息
1)OperatingSystem:通过该MBean我们可以了解到JVM所运行在的操作系统上的一些相关信息,通过java.lang.management.OperatingSystemMXBean定义我们可以了解到其主要提供的功能
- public interface OperatingSystemMXBean {
- public String getName();
- public String getArch();
- public String getVersion();
- public int getAvailableProcessors();
- public double getSystemLoadAverage();
- }
[java] view plain copy
- public interface OperatingSystemMXBean {
- public String getName();
- public String getArch();
- public String getVersion();
- public int getAvailableProcessors();
- public double getSystemLoadAverage();
- }
SunJVM在此基础上提供更多的一些信息,可以通过com.sun.management.OperatingSystemMXBean了解一些额外可以获取到的信息
- public interface OperatingSystemMXBean
- extends java.lang.management.OperatingSystemMXBean
- {
- long getCommittedVirtualMemorySize();
- long getTotalSwapSpaceSize();
- long getFreeSwapSpaceSize();
- long getProcessCpuTime();
- long getFreePhysicalMemorySize();
- long getTotalPhysicalMemorySize();
- }
[java] view plain copy
- public interface OperatingSystemMXBean
- extends java.lang.management.OperatingSystemMXBean
- {
- long getCommittedVirtualMemorySize();
- long getTotalSwapSpaceSize();
- long getFreeSwapSpaceSize();
- long getProcessCpuTime();
- long getFreePhysicalMemorySize();
- long getTotalPhysicalMemorySize();
- }
2)Runtime:通过该MBean获取获取到JVM一些相关的信息,通过java.lang.management.RuntimeMXBean可以了解其主要提供的功能
- public interface RuntimeMXBean {
- public String getName();
- public String getVmName();
- public String getVmVendor();
- public String getVmVersion();
- public String getSpecName();
- public String getSpecVendor();
- public String getSpecVersion();
- public String getManagementSpecVersion();
- public String getClassPath();
- public String getLibraryPath();
- public boolean isBootClassPathSupported();
- public String getBootClassPath();
- public java.util.List<String> getInputArguments();
- public long getUptime();
- public long getStartTime();
- public java.util.Map<String, String> getSystemProperties();
- }
[java] view plain copy
- public interface RuntimeMXBean {
- public String getName();
- public String getVmName();
- public String getVmVendor();
- public String getVmVersion();
- public String getSpecName();
- public String getSpecVendor();
- public String getSpecVersion();
- public String getManagementSpecVersion();
- public String getClassPath();
- public String getLibraryPath();
- public boolean isBootClassPathSupported();
- public String getBootClassPath();
- public java.util.List<String> getInputArguments();
- public long getUptime();
- public long getStartTime();
- public java.util.Map<String, String> getSystemProperties();
- }
可以通过RuntimeMXBean.getUptime()和OperatingSystemMXBean. getProcessCpuTime()来计算JVM占用的系统CPU比例的情况,JConsole的CPU视图就是通过这种方式计算的。
7.Threading:可以通过该MBean获取线程信息,包括线程状态、执行栈等。可以通过java.lang.management.ThreadMXBean了解其提供的主要功能
- public interface ThreadMXBean {
- public int getThreadCount();
- public int getPeakThreadCount();
- public long getTotalStartedThreadCount();
- public int getDaemonThreadCount();
- public long[] getAllThreadIds();
- public ThreadInfo getThreadInfo(long id);
- public ThreadInfo[] getThreadInfo(long[] ids);
- public ThreadInfo getThreadInfo(long id, int maxDepth);
- public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth);
- public boolean isThreadContentionMonitoringSupported();
- public boolean isThreadContentionMonitoringEnabled();
- public void setThreadContentionMonitoringEnabled(boolean enable);
- public long getCurrentThreadCpuTime();
- public long getCurrentThreadUserTime();
- public long getThreadCpuTime(long id);
- public long getThreadUserTime(long id);
- public boolean isThreadCpuTimeSupported();
- public boolean isCurrentThreadCpuTimeSupported();
- public boolean isThreadCpuTimeEnabled();
- public void setThreadCpuTimeEnabled(boolean enable);
- public long[] findMonitorDeadlockedThreads();
- public void resetPeakThreadCount();
- public long[] findDeadlockedThreads();
- public boolean isObjectMonitorUsageSupported();
- public boolean isSynchronizerUsageSupported();
- public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers);
- public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers);
- }
[java] view plain copy
- public interface ThreadMXBean {
- public int getThreadCount();
- public int getPeakThreadCount();
- public long getTotalStartedThreadCount();
- public int getDaemonThreadCount();
- public long[] getAllThreadIds();
- public ThreadInfo getThreadInfo(long id);
- public ThreadInfo[] getThreadInfo(long[] ids);
- public ThreadInfo getThreadInfo(long id, int maxDepth);
- public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth);
- public boolean isThreadContentionMonitoringSupported();
- public boolean isThreadContentionMonitoringEnabled();
- public void setThreadContentionMonitoringEnabled(boolean enable);
- public long getCurrentThreadCpuTime();
- public long getCurrentThreadUserTime();
- public long getThreadCpuTime(long id);
- public long getThreadUserTime(long id);
- public boolean isThreadCpuTimeSupported();
- public boolean isCurrentThreadCpuTimeSupported();
- public boolean isThreadCpuTimeEnabled();
- public void setThreadCpuTimeEnabled(boolean enable);
- public long[] findMonitorDeadlockedThreads();
- public void resetPeakThreadCount();
- public long[] findDeadlockedThreads();
- public boolean isObjectMonitorUsageSupported();
- public boolean isSynchronizerUsageSupported();
- public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers);
- public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers);
- }
二、编程获取到JVM Manage信息
我们可以通过JMX的方式读取到JVM Manage定义的MBean,如下是3种获取方法
1.监控应用与被监控应用位于同一JVM
- MBeanServer server = ManagementFactory.getPlatformMBeanServer();
- RuntimeMXBean rmxb = ManagementFactory.newPlatformMXBeanProxy(server,
- "java.lang:type=Runtime", RuntimeMXBean.class);
[java] view plain copy
- MBeanServer server = <span style="BACKGROUND-COLOR: #00ff40; COLOR: black; " id="casearchresult"><strong>ManagementFactory</strong></span>.getPlatformMBeanServer();
- RuntimeMXBean rmxb = <span style="BACKGROUND-COLOR: #00ff40; COLOR: black; " id="casearchresult"><strong>ManagementFactory</strong></span>.newPlatformMXBeanProxy(server,
- "java.lang:type=Runtime", RuntimeMXBean.class);
2.监控应用与被监控应用不位于同一JVM
1)首先在被监控的JVM的启动参数中加入如下的启动参数以启JVM代理
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=127.0.0.1:8000
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
2)连接到代理上
- JMXServiceURL url = new JMXServiceURL(
- "service:jmx:rmi:///jndi/rmi://127.0.0.1:8000/jmxrmi");
- JMXConnector connector = JMXConnectorFactory.connect(url);
- RuntimeMXBean rmxb = ManagementFactory.newPlatformMXBeanProxy(connector
- .getMBeanServerConnection(),"java.lang:type=Runtime",
- RuntimeMXBean.class);
[java] view plain copy
- JMXServiceURL url = new JMXServiceURL(
- "service:jmx:rmi:///jndi/rmi://127.0.0.1:8000/jmxrmi");
- JMXConnector connector = JMXConnectorFactory.connect(url);
- RuntimeMXBean rmxb = <span style="BACKGROUND-COLOR: #00ff40; COLOR: black; " id="casearchresult"><strong>ManagementFactory</strong></span>.newPlatformMXBeanProxy(connector
- .getMBeanServerConnection(),"java.lang:type=Runtime",
- RuntimeMXBean.class);
3.监控应用与被监控应用不位于同一JVM但在同一物理主机上(2的特化情况,通过进程Attach)
我们使用JDK工具,如jmap、jstack等的时候,工具所在的JVM当然与被监控的JVM不是同一个,所以不能使用方式1,被监控的JVM一般也不
会在启动参数中增加JMX的支持,所以方式2也没有办法。还好Sun
JVM给我们提供了第3种非标准的方式,就是通过Attach到被监控的JVM进程,并在被监控的JVM中启动一个JMX代理,然后使用该代理通过2的方
式连接到被监控的JVM的JMX上。下面是一个使用范例,由于里面使用到的知识涉及到Java
Instrutment(JVMTI的一个技术的Java实现)和Attach
API,因此此处不做详细解析,在后续看完Java Instrutment和Attach
API自然就会明白。(注意,仅在JDK6+中支持,另外,运行需要jdk的tools.jar包)
- //Attach 到5656的JVM进程上,后续Attach API再讲解
- VirtualMachine virtualmachine = VirtualMachine.attach("5656");
- //让JVM加载jmx Agent,后续讲到Java Instrutment再讲解
- String javaHome = virtualmachine.getSystemProperties().getProperty("java.home");
- String jmxAgent = javaHome + File.separator + "lib" + File.separator + "management-agent.jar";
- virtualmachine.loadAgent(jmxAgent, "com.sun.management.jmxremote");
- //获得连接地址
- Properties properties = virtualmachine.getAgentProperties();
- String address = (String)properties.get("com.sun.management.jmxremote.localConnectorAddress");
- //Detach
- virtualmachine.detach();
- JMXServiceURL url = new JMXServiceURL(address);
- JMXConnector connector = JMXConnectorFactory.connect(url);
- RuntimeMXBean rmxb = ManagementFactory.newPlatformMXBeanProxy(connector
- .getMBeanServerConnection(), "java.lang:type=Runtime",RuntimeMXBean.class);
[java] view plain copy
- //Attach 到5656的JVM进程上,后续Attach API再讲解
- VirtualMachine virtualmachine = VirtualMachine.attach("5656");
- //让JVM加载jmx Agent,后续讲到Java Instrutment再讲解
- String javaHome = virtualmachine.getSystemProperties().getProperty("java.home");
- String jmxAgent = javaHome + File.separator + "lib" + File.separator + "management-agent.jar";
- virtualmachine.loadAgent(jmxAgent, "com.sun.management.jmxremote");
- //获得连接地址
- Properties properties = virtualmachine.getAgentProperties();
- String address = (String)properties.get("com.sun.management.jmxremote.localConnectorAddress");
- //Detach
- virtualmachine.detach();
- JMXServiceURL url = new JMXServiceURL(address);
- JMXConnector connector = JMXConnectorFactory.connect(url);
- RuntimeMXBean rmxb = <span style="BACKGROUND-COLOR: #00ff40; COLOR: black; " id="casearchresult"><strong>ManagementFactory</strong></span>.newPlatformMXBeanProxy(connector
- .getMBeanServerConnection(), "java.lang:type=Runtime",RuntimeMXBean.class);
三、结束语
可以看到,通过标准的接口,我们已经可以获得运行的JVM很详细的信息,从运行JVM、操作系统,到内存、GC和线程,通过这些标准的接口我们已经可以对
JVM进行功能完善的监控。但是仅此是不够的,这部分接口描述的主要是JVM的总体性的信息,而无法提供更多的细节。在下一部分,我们将使用JPDA来更
深入地了解JVM内部信息更细节的信息,并了解我们如何通过JVM TI实现自动的性能监控
软件包 java.lang.management 提供管理接口,用于监视和管理 Java 虚拟机以及 Java 虚拟机在其上运行的操作系统。
它同时允许从本地和远程对正在运行的 Java 虚拟机进行监视和管理。
管理接口
ClassLoadingMXBean Java 虚拟机的类加载系统。
CompilationMXBean Java 虚拟机的编译系统。
MemoryMXBean Java 虚拟机的内存系统。
ThreadMXBean Java 虚拟机的线程系统。
RuntimeMXBean Java 虚拟机的运行时系统。
OperatingSystemMXBean Java 虚拟机在其上运行的操作系统。
GarbageCollectorMXBean Java 虚拟机中的垃圾回收器。
MemoryManagerMXBean Java 虚拟机中的内存管理器。
MemoryPoolMXBean Java 虚拟机中的内存池。
示例如下:
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.CompilationMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.ThreadMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.util.List;
public class JVM {
public static void main(String[] args) {
//Java 虚拟机线程系统的管理接口 ThreadMXBean
ThreadMXBean th=(ThreadMXBean)ManagementFactory.getThreadMXBean() ;
System.out.println("活动线程的当前数目"+th.getThreadCount());
System.out.println("返回活动守护线程的当前数目"+th.getDaemonThreadCount());
System.out.println("Java 虚拟机启动或峰值重置以来峰值活动线程计数"+th.getPeakThreadCount());
System.out.println("返回当前线程的总 CPU 时间"+th.getCurrentThreadUserTime());
System.out.println("当前线程在用户模式中执行的 CPU 时间"+th.getCurrentThreadUserTime());
//Java 虚拟机的运行时系统的管理接口。 RuntimeMXBean
RuntimeMXBean run=(RuntimeMXBean)ManagementFactory.getRuntimeMXBean();
System.out.println("正在运行的 Java 虚拟机的名称"+run.getName());
System.out.println("Java 虚拟机规范名称"+run.getSpecName());
System.out.println("返回 Java 库路径"+run.getLibraryPath());
System.out.println("系统类加载器用于搜索类文件的 Java 类路径"+run.getClassPath());
//用于操作系统的管理接口,Java 虚拟机在此操作系统上运行 OperatingSystemMXBean
OperatingSystemMXBean op=(OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
System.out.println("返回操作系统的架构"+op.getArch());
System.out.println("返回操作系统名称"+op.getName());
System.out.println("返回操作系统的版本"+op.getVersion());
System.out.println("Java 虚拟机可以使用的处理器数目"+op.getAvailableProcessors());
//内存池的管理接口。内存池表示由 Java 虚拟机管理的内存资源,
//由一个或多个内存管理器对内存池进行管理 MemoryPoolMXBean
List<MemoryPoolMXBean> list=ManagementFactory.getMemoryPoolMXBeans();
for(MemoryPoolMXBean mem:list){
System.out.println("Java 虚拟机启动以来或自峰值重置以来此内存池的峰值内存使用量"+mem.getPeakUsage());
System.out.println("返回此内存池的类型"+mem.getType());
System.out.println("内存使用量超过其阈值的次数"+ mem.getUsage());
}
//Java 虚拟机内存系统的管理接口。 MemoryMXBean
MemoryMXBean mem=(MemoryMXBean)ManagementFactory.getMemoryMXBean();
System.out.println(" 返回用于对象分配的堆的当前内存使用量"+mem.getHeapMemoryUsage());
System.out.println("Java 虚拟机使用的非堆内存的当前内存使用量"+mem.getNonHeapMemoryUsage());
// Java 虚拟机的编译系统的管理接口 CompilationMXBean
CompilationMXBean com=(CompilationMXBean)ManagementFactory.getCompilationMXBean();
System.out.println("即时 (JIT) 编译器的名称"+com.getName());
System.out.println("在编译上花费的累积耗费时间的近似值(毫秒)"+com.getTotalCompilationTime());
//Java 虚拟机的类加载系统的管理接口 ClassLoadingMXBean
ClassLoadingMXBean cl=(ClassLoadingMXBean)ManagementFactory.getClassLoadingMXBean();
System.out.println("当前加载到 Java 虚拟机中的类的数量"+cl.getLoadedClassCount());
System.out.println("Java 虚拟机开始执行到目前已经加载的类的总数"+cl.getTotalLoadedClassCount());
System.out.println("Java 虚拟机开始执行到目前已经卸载的类的总数"+cl.getUnloadedClassCount());
}
}
[java] view plain copy
- public class TestExcho {
- /**
- * @param args
- */
- public static void main(String[] args) throws Exception{
- MBeanServer server = ManagementFactory.getPlatformMBeanServer();
- ObjectName name = new ObjectName("com.demo.mbean:type=Excho");
- Echo ei =new Echo();
- server.registerMBean(ei,name);
- server.invoke(name, "setName", new Object[] { "jack"}, new String[] {"java.lang.String"});
- server.invoke(name, "showName", null, null);
- String yourName = (String)server.invoke(name, "fetchName", new Object[] { "mimi",10}, new String[] {"java.lang.String","int"});
- System.out.println("~~~"+yourName);
- CompositeData d = (CompositeData) server.invoke(name, "fetchConfig", null, null);
- String fn = (String)d.get("firstName");
- String ln = (String)d.get("lastName");
- System.out.println("[email protected]@@~~"+fn+"@@"+ln);
- int num = (Integer)server.getAttribute(name, "Num");
- System.out.println("~OOOOO~~"+num);
- Thread.currentThread().sleep(Integer.MAX_VALUE);
- }
- }