举一个应用实例:在一个系统中常常会有一些配置信息,比如服务的IP地址,端口号什么的,那么如何来写这些代码呢?
- 程序初哥一般是写死在程序里,到要改变时就去改程序,然后再编译发布;
- 程序熟手则一般把这些信息写在一个配置文件里(JAVA一般都是*.properties文件),到要改变时只要改配置文件,但还是重新启动系统,以便读取配置文件里的新值;
- 程序好手则会写一个段代码,把配置值缓存起来,系统在读值的时候,先看看配置文件有没有更动。如有更改则重读一遍,否则从缓存里读取值
- 程序高手则懂得取物为我所用,用JMX!把配置属性集中在一个类,然后写一个叫MBean的东东,再配置一下就轻松搞定了。而且JMX自动提供了一个WEB页面来给你来改变这些配置信息。
- RMI(Remote Method Invocation)
RMI是不同JVM之间的对象通信的协议
- JMX RMI访问的基本步骤:
| 1 | 启动MBeanServer | 
| 2 | 建立并启动 NamingService MBean,实际就是rmiregistry | 
| 3 | 为MBeanServer建立160 JMX RMIConnector,此RMI连接器提供:  service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxconnector | 
| 4 | 客户端连接 | 
| 4.1 | 通用客户端(如jconsole) | 
| 4.2 | 自定义客户端  生成 JMXConnector ,与JMI server建立 RMI连接  建立与MBean server的连接  MBeanServerInvocationHandler.newProxyInstance()获取代理MBean | 
- JMX RMI例子
1. RMI Server
|  | 
|  执行此RmiServer:  Server up and running  可以看到TCP 1099端口被listen  D:Documents and Settingsmac>netstat -an  Active Connections    Proto  Local Address          Foreign Address        State    TCP    0.0.0.0:135            0.0.0.0:0              LISTENING    TCP    0.0.0.0:445            0.0.0.0:0              LISTENING    TCP    0.0.0.0:1025           0.0.0.0:0              LISTENING  TCP    0.0.0.0:1099           0.0.0.0:0                 TCP    0.0.0.0:2737           0.0.0.0:0              LISTENING    TCP    0.0.0.0:3306           0.0.0.0:0              LISTENING    TCP    0.0.0.0:6059           0.0.0.0:0              LISTENING    TCP    0.0.0.0:6648           0.0.0.0:0              LISTENING | 
 2.通用客户端(典型的比如jconsole) 
| 这里用的是jdk 1.6 jconsole  远程进程:  service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxconnector  用户名:  口令:  用户名和口令都可以空着,不必输入 | 
| 点"连接",可以进入jconsole界面  可以在mbean下看到hello对象 | 
 3. 自定义client 端通过RMI连接 Server 
执行:
 Server up and running
 Hello, mac
 Hello, haha
package com.machome.jmx.appTest;
 import javax.management.JMX;
 import javax.management.MBeanServerConnection;
 import javax.management.MBeanServerDelegateMBean;
 import javax.management.MBeanServerInvocationHandler;
 import javax.management.ObjectName;
 import javax.management.remote.JMXConnector;
 import javax.management.remote.JMXConnectorFactory;
 import javax.management.remote.JMXServiceURL;
 import com.machome.bean.Hello;
 import com.machome.bean.HelloMBean;
 public class RmiClient
 {
     private JMXServiceURL jmxUrl;
     private JMXConnector connector;
     private MBeanServerConnection mBeanServerconnection;
    
    
     public RmiClient()throws Exception{
         createJMXRmiConnector();
         createMBeanServerConnection();
     }
    
    public static void main(String[] args) throws Exception
    {
        new RmiClient().test();
       
    }
   
   
    private void createJMXRmiConnector() throws Exception{
           // 1.The JMXConnectorServer protocol
           String serverProtocol = "rmi";
           // 2.The RMI server's host
           // this is actually ignored by JSR 160
           String serverHost = "localhost";
           // 3.The host, port and path where the rmiregistry runs.
           String namingHost = "localhost";
           int namingPort = 1099;
           String jndiPath = "/jmxconnector";
           // 4. connector server url
           jmxUrl = new JMXServiceURL("service:jmx:" +
                   serverProtocol + "://" + serverHost +
                   "/jndi/rmi://" + namingHost + ":" +
                   namingPort + jndiPath);
          
           // 5. 生成 JMXConnector,连接到url一端
           // Connect a JSR 160 JMXConnector to the server side
           connector = JMXConnectorFactory.connect(jmxUrl);
    }
   
   
    private void createMBeanServerConnection() throws Exception{
        mBeanServerconnection = ();
    }   
    public void test()throws Exception{
  
        ObjectName  oName = new ObjectName("mbean", "name", "hello");
        // 获取代理对象
        Object proxy = MBeanServerInvocationHandler
         .newProxyInstance(mBeanServerconnection,oName, HelloMBean.class, true);
                 
        
         // 获取测试MBean,并执行它的(暴露出来被管理监控的)方法      
        HelloMBean helloMBean = (HelloMBean)proxy;
       
        helloMBean.setName("mac");
        helloMBean.printHello();
        helloMBean.printHello("haha");
    
    }
   
 }
   
    public void test()throws Exception{
  
        ObjectName  oName = new ObjectName("mbean", "name", "hello");
        // 获取代理对象
        Object proxy = MBeanServerInvocationHandler
         .newProxyInstance(mBeanServerconnection,oName, HelloMBean.class, true);
                 
        
         // 获取测试MBean,并执行它的(暴露出来被管理监控的)方法      
        HelloMBean helloMBean = (HelloMBean)proxy;
       
        helloMBean.setName("mac");
        helloMBean.printHello();
        helloMBean.printHello("haha");
    
    }
   
 }
执行:
 Server up and running
 Hello, mac
 Hello, haha
   
    public void test()throws Exception{
  
        ObjectName  oName = new ObjectName("mbean", "name", "hello");
        // 获取代理对象
        Object proxy = MBeanServerInvocationHandler
         .newProxyInstance(mBeanServerconnection,oName, HelloMBean.class, true);
                 
        
         // 获取测试MBean,并执行它的(暴露出来被管理监控的)方法      
        HelloMBean helloMBean = (HelloMBean)proxy;
       
        helloMBean.setName("mac");
        helloMBean.printHello();
        helloMBean.printHello("haha");
    
    }
   
 }- 上面例子中RMI中的rmiregistry MBean,我们采用的mc4j-tools.jar中的 NamingService,代码如下,代码并不复杂,其实我们也可以自定义一个代替它:
|  | 
| MBean接口: 
  | 
- spring 下的 RMI connector
1.spring 配置如下:
| 
                            
  | 
 2. web.xml装载spring 配置 
| 
  | 
 3.将项目部署入Tomcat 
| 启动Tomcat | 
| 不需要执行任何servlet,action,只要spring随Tomcat启动,就会看到TCP 1099端口被listen  D:Documents and Settingsmac>netstat -an  Active Connections    Proto  Local Address          Foreign Address        State    TCP    0.0.0.0:135            0.0.0.0:0              LISTENING    TCP    0.0.0.0:445            0.0.0.0:0              LISTENING    TCP    0.0.0.0:1025           0.0.0.0:0              LISTENING  TCP    0.0.0.0:1099       0.0.0.0:0              TCP    0.0.0.0:2737           0.0.0.0:0              LISTENING    | 
 4. 执行通用客户端(典型的比如jconsole) 
| 这里用的是jdk 1.6 jconsole  远程进程:  service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxconnector  用户名:  口令:  用户名和口令都可以空着,不必输入    | 
| 点"连接",可以进入jconsole界面  与前面application RMI的例子不同,这里的不仅可以看到hello MBean对象,还能看到很多MBean对象,如Catalina目录下的很多MBean,因为spring没有定义新的MBeanServer,而是用 tomcat容器自己的MBeanServer,所以能看到很多Tomcat容器自己的service MBean | 
 5.执行前面application RMI的例子的RmiClient 
| Hello, mac  Hello, haha | 
(我在spring rmi 例子和application rmi 例子 
用的相同的serviceUrl 
,都是 
service:jmx:rmi://localhost/jndi/rmi: //localhost:1099/jmxconnector 
因此客户端可以访问这两种例子的Server) 
- 简化后的spring RMI
其实spring 例子里的spring 配置的no.2,no.3.no.4都可以不用
 MBeanServer可以不用建立,spring会自动搜索容器自己的MBeanServer,
 MBeanInfoAssembler和AnnotationJmxAttributeSource 则只是提供注释MBean功能,以代替implement MBean接口,完全可以不用这种注释,而用传统的implement MBean接口
| 
  | 










