`
zhengxuezhou
  • 浏览: 148133 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JMX RMI 访问

    博客分类:
  • j2se
阅读更多

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
package com.machome.jmx.appTest;

import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

import com.machome.bean.Hello;

import mx4j.tools.naming.NamingService;


public class RmiServer
{
    private MBeanServer mBeanServer;
    private JMXConnectorServer connectorServer;
    private JMXServiceURL jmxUrl;
  
    public RmiServer() throws Exception{
          mBeanServer = MBeanServerFactory.createMBeanServer();
          createRmiregistry();
          CreateJMXConnector();
    }
   public static void main(String[] args) throws Exception
   {
    
       RmiServer rmiServer = new RmiServer();
       // 加一个测试MBean Hello对象
       rmiServer.addMbean(new Hello(), "mbean", "name", "hello");
       rmiServer.startJMXConnector();
     
       System.out.println("Server up and running");
   }
 
   public ObjectName addMbean(Object o,String domain,String key,String value) throws Exception{
          ObjectName oName = new ObjectName(domain, key, value);
          mBeanServer.registerMBean(o, oName);
          return oName;
}
 
 
   public void createRmiregistry() throws Exception{
        
          // 1.注册NamingService MBean
          ObjectName namingName = ObjectName
                      .getInstance("naming:type=rmiregistry");
          // 这里采用MC4J的mx4j.tools.naming.NamingService
          NamingService ns = new NamingService();
        
          mBeanServer.registerMBean(ns, namingName);
          // 2.启动NamingService MBean
          mBeanServer.invoke(namingName, "start", null, null);
   }
 
 
   public void CreateJMXConnector() throws Exception{

          // 1.nammingPort,从NamingService获得Port,缺省是1099
          ObjectName namingName = ObjectName.getInstance("naming:type=rmiregistry");
     int namingPort = ((Integer)mBeanServer.getAttribute(namingName, "Port")).intValue();
       
          // 2. jndiPath
          String jndiPath = "/jmxconnector";
          // 3. JMXServiceURL ,为:
          // service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxconnector
          jmxUrl = new JMXServiceURL("service:jmx:rmi://localhost/jndi/rmi://localhost:"
                                              + namingPort + jndiPath);
        
          // 4.Create and start the RMIConnectorServer
          // 中间设为null的参数,是针对认证的,我们这里没打开,设为null
             connectorServer = JMXConnectorServerFactory
                                  .newJMXConnectorServer(jmxUrl, null, mBeanServer);
   }
 
   public void startJMXConnector() throws Exception{
       connectorServer.start();
   }
 
   public void stopJMXConnector() throws Exception{
       connectorServer.stop();
   }
 
}
 

执行此RmiServer:
Server up and running


可以看到TCP 1099端口被listen
D:\Documents and Settings\mac>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              LISTENING
  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
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 = connector.getMBeanServerConnection();
   }
 
 
   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
 

 

上面例子中RMI中的rmiregistry MBean,我们采用的mc4j-tools.jar中的 NamingService,代码如下,代码并不复杂,其实我们也可以自定义一个代替它:
public class NamingService  implements NamingServiceMBean
{
    public NamingService()
    {
        this(1099);
    }

    public NamingService(int port)
    {
        setPort(port);
    }

    public void setPort(int port)
    {
        if(isRunning())
        {
            throw new IllegalStateException("NamingService is running, cannot change the port");
        } else
        {
            m_port = port;
            return;
        }
    }

    public int getPort()
    {
        return m_port;
    }

    public boolean isRunning()
    {
        return m_running;
    }

    public void start()
        throws RemoteException
    {
        if(!isRunning())
        {
            m_registry = LocateRegistry.createRegistry(getPort());
            m_running = true;
        }
    }

    public void stop()
        throws NoSuchObjectException
    {
        if(isRunning())
            m_running = !UnicastRemoteObject.unexportObject(m_registry, true);
    }

    public String[] list()
        throws RemoteException
    {
        if(!isRunning())
            throw new IllegalStateException("NamingService is not running");
        else
            return m_registry.list();
    }

    public void unbind(String name)
        throws RemoteException, NotBoundException
    {
        if(!isRunning())
        {
            throw new IllegalStateException("NamingService is not running");
        } else
        {
            m_registry.unbind(name);
            return;
        }
    }

    private int m_port;
    private Registry m_registry;
    private boolean m_running;
}
 
MBean接口:
public interface NamingServiceMBean
{

    public abstract void setPort(int i);

    public abstract int getPort();

    public abstract boolean isRunning();

    public abstract void start()
        throws RemoteException;

    public abstract void stop()
        throws NoSuchObjectException;

    public abstract String[] list()
        throws RemoteException;

    public abstract void unbind(String s)
        throws RemoteException, NotBoundException;
}
 

 

spring 下的 RMI connector
1.spring 配置如下:
   <!-- 1.定义自己的bean -->
    <bean id="hello" class="com.machome.bean.Hello" /> 
  
    <!-- JMX configuration -->

    <!-- 2.创建一个mbeanServer bean-->
    <!--  如果你的spring是应用在容器中,则不需要此步骤,此步骤用于单独建立独立的MBeanServer中
    <bean id="mbeanServer"
          class="org.springframework.jmx.support.MBeanServerFactoryBean">
    </bean>  
    -->
      
    <!-- 3.定义assembler bean ,装配bean
        MetadataMBeanInfoAssembler是AutodetectCapableMBeanInfoAssembler 唯一实现
        spring文档中有专门介绍AutodetectCapableMBeanInfoAssembler的章节
     -->
    <bean id="assembler"
          class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
        <!-- 注入下面定义的jmxAttributeSource-->
        <property name="attributeSource" ref="jmxAttributeSource"/>
    </bean>
      
    <!-- 4.定义解释mbean中Annotation的bean-->
    <bean id="jmxAttributeSource"
          class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>


    <!-- 5.定义 RMI连接器,注意需要先定义一个naming 注册 bean-->
    <bean id="registry"    
         class="org.springframework.remoting.rmi.RmiRegistryFactoryBean"
         destroy-method="destroy">
      <property name="port" value="1099" />
    </bean>
          
    <bean id="serverConnector"
       class="org.springframework.jmx.support.ConnectorServerFactoryBean"
       depends-on="registry">
        <property name="objectName" value="connector:name=rmi"/>
        <property name="serviceUrl"
        value="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxconnector"/>
      
        <!--  如果上面步骤2.你单独定义一个mbeanServer,这里需要指定,否则rmi connector缺省是去寻找runtime环境内的MBeanserver(通常是容器的MBeanServer)
        <property name="server" ref="mbeanServer"/>
        -->
      
        <!-- 多线程启动connector,一个线程一个connector -->
        <property name="threaded" value="true" />
        <!-- 多线程启动connector,thread daemon -->
        <property name="daemon" value="true" />
    </bean>
 
  
    <!-- 6.定义MBeanExporter bean, 这是spring jmx最核心的类 -->
    <bean id="mBeanExporter" class="org.springframework.jmx.export.MBeanExporter"
    lazy-init="false">
        <!-- 注入上面定义的assembler 两个bean注入-->
        <property name="assembler" ref="assembler"/>
      
        <!--  如果上面步骤2.你单独定义一个mbeanServer,这里需要指定,否则export bean缺省是去寻找runtime环境内的MBeanserver(通常是容器的MBeanServer)
        <property name="server" ref="mbeanServer"/>
        -->
      
        <!-- 将1.里面定义的mbean注册到mBeanExporter bean中 -->
        <property name="beans">
            <map>
                <entry key="mbean:name=hello" value-ref="hello"/>
            </map>
        </property>
      
    </bean>
 
2. web.xml装载spring 配置
    <!-- ##################### 初始化spring容器  ###########-->  
    <context-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>
               classpath:ssh-mysql.xml
        </param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
 
3.将项目部署入Tomcat
启动Tomcat
 
不需要执行任何servlet,action,只要spring随Tomcat启动,就会看到TCP 1099端口被listen
D:\Documents and Settings\mac>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           LISTENING
  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接口

   <!-- 1.定义自己的bean -->
    <bean id="hello" class="com.machome.bean.Hello" />
  
    <!-- 5.定义 RMI连接器,注意需要先定义一个naming 注册 bean-->
    <bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean" destroy-method="destroy">
      <property name="port" value="1099" />
    </bean>
          
    <bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" depends-on="registry">
        <property name="objectName" value="connector:name=rmi"/>
        <property name="serviceUrl" value="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxconnector"/>

      
        <!-- 多线程启动connector,一个线程一个connector -->
        <property name="threaded" value="true" />
        <!-- 多线程启动connector,thread daemon -->
        <property name="daemon" value="true" />
    </bean>
  
  
    <!-- 6.定义MBeanExporter bean, 这是spring jmx最核心的类 -->
    <bean id="mBeanExporter" class="org.springframework.jmx.export.MBeanExporter"
    lazy-init="false">
      
        <!-- 将1.里面定义的mbean注册到mBeanExporter bean中 -->
        <property name="beans">
            <map>
                <entry key="mbean:name=hello" value-ref="hello"/>
            </map>
        </property>
      
    </bean>
 

 

分享到:
评论

相关推荐

    JMX以RMI方式连接的场景示例

    JMX以RMI方式连接的场景示例,从“服务器A远程获取服务器B的历史IP访问记录”这一场景出发,将JMX框架的各层简单的串了一遍。其中包括了MBean、Agent、Client每个层的详细代码和说明

    jmx三种访问方式

    Jmx简单应用,http页面方式,vm参数方式,rmi方式

    实现JMX的spring支持,拓展了RMI远程接口。

    JMX集成到spring中,并提供了一个rmi远程连接的配置文件

    jolokia:辣椒素上的JMX

    Jolokia是一种远程访问JMX MBean的新方法。 它与JSR-160连接器的不同之处在于它是一种基于代理的方法,该方法使用REST风格的HTTP上的JSON进行通信。 为不同的环境提供了多个代理: 用于在Java EE Server中作为Web...

    Monitoring-kafka-using-Nagios-plugin:使用Nagios插件监控Kafka

    下载插件: 解压缩并cd到check_jmx / nagios / plugin 运行命令: ./check_jmx -U服务:jmx:rmi:/// jndi / rmi:// $ hostname:$ port / jmxrmi -O java.lang:type = Memory -A HeapMemoryUsage -K used -I ...

    embedded-jmxtrans:进行中的JMX指标导出器

    正在进行中的JMX Exporter将解决在Java的IP地址未知且RMI-IIOP被禁用(例如Amazon Elastic Beanstalk,Cloudbees等)的云风格和弹性环境中进行远程JMX访问的问题。 如果您有什么要讨论的 入门 启用了Spring ...

    JAVA_API1.6文档(中文)

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax...

    [Java参考文档].JDK_API 1.6

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax....

    serjs:JavaScript中的Java序列化程序

    这样就可以利用原本无法访问的RMI端点。免责声明所有信息和代码仅出于教育目的和/或针对这些漏洞测试您自己的系统而提供。笔记某些浏览器/浏览器插件可能实施进一步的限制,试图禁止对本地网络的请求。 JMX / RMI ...

    java jdk-api-1.6 中文 chmd

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax...

    JDK_1_6 API

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax....

    java api最新7.0

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax....

    JavaAPI1.6中文chm文档 part1

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax...

    [Java参考文档]

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax...

    JavaAPI中文chm文档 part2

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax...

    Java 1.6 API 中文 New

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax....

    基于J2EE的介绍

    •RMI/ IIOP(远程过程调用/因特网ORB间协议):友情链接本地Java的RPC机制,CORBA,并允许非Java系统访问EJB。 •XML技术(JAXP,SAAJ,JAX-RPC等):一个完整的技术套件操纵XML和构建基于标准的XML Web服务。 •...

Global site tag (gtag.js) - Google Analytics