Spring JMX之二:远程访问MBean
虽然最初的JMX规范提及了通过MBean进行应用的远程管理,但是它并没有定义实际的远程 访问协议或API。因此,会由JMX供应商定义自己的JMX远程访问解决方案,但这通常又是专 有的。
为了满足以标准方式进行远程访问JMX的需求,JCP(Java Community Process)制订了JSR-160: Java管理扩展远程访问API规范(Java Management Extensions Remote API Specification)。该规范 定义了JMX远程访问的标准,该标准至少需要绑定RMI和可选的JMX消息协议(JMX Messaging Protocol ,JMXMP)。
在本小节中,我们将看到Spring如何远程访问MBean。我们首先从配置Spring把 SpittleController导出为远程MBean开始,然后我们再了解如何使用Spring远程操纵 MBean。
spring通过annotation暴露MBean
在javaconfig类中开启注解
@EnableMBeanExport
涉及到三个重要的annotation:@ManagedResource @ManagedAttribute 和 @ManagedOperation。
说明:
- @ManagedResource @ManagedAttribute 和 @ManagedOperation 还有许多参数,具体使用请参考spring官方手册。( spring手册[2.5.3] ---- 20.3.4. 源代码级的元数据类型)
- @ManagedOperationParameters 是对@ManagedOperation的补充。具体看代码样例中的add1方法上的注解,然后再看图2(查看已暴露MBean的方法)的add1方法和add2的区别。添加参数说明的add1方法会显示出参数名,而add2方法则是默认的参数名p1/p2。
- 没有添加@ManagedOperation和@ManagedAttribute的方法,在图2中就没有看到,说明添加了注解的方法暴露MBean是可用的。
- @ManagedOperation和@ManagedAttribute的区别,请查看2.1的详解。
1、暴露远程MBean
使MBean成为远程对象的最简单方式是配置Spring的ConnectorServerFactoryBean:
@Bean
public ConnectorServerFactoryBean connectorServerFactoryBean() {
return new ConnectorServerFactoryBean();
}
ConnectorServerFactoryBean会创建和启动JSR-160 JMXConnectorServer。默认 情况下,服务器使用JMXMP协议并监听端口9875——因此,它将绑 定“service:jmx:jmxmp://localhost:9875”。但是我们导出MBean的可选方案并不局限于JMXMP。
根据不同JMX的实现,我们有多种远程访问协议可供选择,包括远程方法调用(Remote Method Invocation,RMI)、SOAP、Hessian/Burlap和IIOP(Internet InterORB Protocol)。为MBean绑定不同 的远程访问协议,我们仅需要设置ConnectorServerFactoryBean的serviceUrl属性。 例如,如果我们想使用RMI远程访问MBean,我们可以像下面示例这样配置:
@Bean
public ConnectorServerFactoryBean connectorServerFactoryBean() {
ConnectorServerFactoryBean csfb = new ConnectorServerFactoryBean();
csfb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter");
return csfb;
}
在这里,我们将ConnectorServerFactoryBean绑定到了一个RMI注册表,该注册表监听 本机的1099端口。这意味着我们需要一个RMI注册表运行时,并监听该端口。我们可以回顾下第15章,RmiServiceExporter可以为我们自动启动一个RMI注册表。但是,我们在本示例 中不使用RmiServiceExporter,而是通过在Spring中声明RmiRegistryFactoryBean 来启动一个RMI注册表,如下面的@Bean方法所示:
@Bean
public RmiRegistryFactoryBean rmiRegistryFB() {
RmiRegistryFactoryBean rmiRegistryFB = new RmiRegistryFactoryBean();
rmiRegistryFB.setPort(1099);
return rmiRegistryFB;
}
没错!现在我们的MBean可以通过RMI进行远程访问了。
完整代码如下:
package com.dxz.mvcdemo1.web.jmx4; import static org.springframework.web.bind.annotation.RequestMethod.GET; import org.springframework.context.annotation.Bean;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.support.ConnectorServerFactoryBean;
import org.springframework.remoting.rmi.RmiRegistryFactoryBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; @Controller
@RequestMapping("/biz4")
@ManagedResource(objectName="spitter:name=SpittleController4") //将SpittleController导出为MBean
public class SpittleCntroller4 { // 默认每个页面的大小
public static final int DEFAULT_SPITTLES_PER_PAGE = 25; // 每页的大小
private int spittlesPerPage = DEFAULT_SPITTLES_PER_PAGE; //@ManagedOperation@ManagedOperation注解替换@ManagedAttribute注解来标注存取器方法
@ManagedAttribute //将spittlesPerPage暴露为托管属性
public int getSpittlesPerPage() {
return spittlesPerPage;
} //@ManagedOperation@ManagedOperation注解替换@ManagedAttribute注解来标注存取器方法
@ManagedAttribute //将spittlesPerPage暴露为托管属性
public void setSpittlesPerPage(int spittlesPerPage) {
this.spittlesPerPage = spittlesPerPage;
} @RequestMapping(value = "/test4", method = GET)
public String test() {
String result = spittlesPerPage + " - test()";
System.out.println(result);
return "home";
} //启动一个RMI注册表,并监听1099端口
@Bean
public RmiRegistryFactoryBean rmiRegistryFB() {
RmiRegistryFactoryBean rmiRegistryFB = new RmiRegistryFactoryBean();
rmiRegistryFB.setPort(1099);
return rmiRegistryFB;
} //将ConnectorServerFactoryBean绑定到了上面的RMI注册表,该注册表监听本机的1099端口
@Bean
public ConnectorServerFactoryBean connectorServerFactoryBean() {
ConnectorServerFactoryBean csfb = new ConnectorServerFactoryBean();
csfb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter");
return csfb;
} }
启动测试:
注意:日志中RMI注册表运行了,并监听1099端口
下面先通过java自带的工具连接及测试如下,选择“远程进程”并将代码中的url=“service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter”填入输入框中,进行连接:
连接成功后的结果如下:
但是如果没有人通过RMI访问MBean 的话,那就不值得这么做。所以现在让我们把关注点转向JMX远程访问的客户端,看看如何在 Spring中装配一个远程MBean到JMX客户端中。
2 访问远程MBean
要想访问远程MBean服务器,我们需要在Spring上下文中配置MbeanServerConnectionFactoryBean。下面的bean声明装配了一个MbeanServerConnectionFactoryBean,该bean用于访问我们在上一节中所创建的基于RMI的远程服务器。
@Bean
public MBeanServerConnectionFactoryBean connectionFactoryBean() throws MalformedURLException {
MBeanServerConnectionFactoryBean mbscfb = new MBeanServerConnectionFactoryBean();
mbscfb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter");
return mbscfb;
}
顾名思义,MBeanServerConnectionFactoryBean是一个可用于创建MbeanServerConnection的工厂bean。由MBeanServerConnectionFactoryBean所生成的 MBeanServerConnection实际上是作为远程MBean服务器的本地代理。它能够以 MBeanServerConnection的形式注入到其他bean的属性中:
@Bean
public JmxClient jmxClient(MBeanServerConnection connection) {
JmxClient jmxClient = new JmxClient();
jmxClient.setMbeanServerConnection(connection);
return jmxClient;
}
JmxClient.java
package com.dxz.mvcdemo2.web; import javax.management.MBeanServerConnection; import org.springframework.stereotype.Component; @Component
public class JmxClient { MBeanServerConnection mbeanServerConnection; public JmxClient() { } public MBeanServerConnection getMbeanServerConnection() {
return mbeanServerConnection;
}
public void setMbeanServerConnection(MBeanServerConnection mbeanServerConnection) {
this.mbeanServerConnection = mbeanServerConnection;
}
测试类:
package com.dxz.mvcdemo2.web; import static org.springframework.web.bind.annotation.RequestMethod.GET; import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Set; import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.jmx.support.MBeanServerConnectionFactoryBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; @Controller
@RequestMapping("/biz4")
public class ClientController { @Autowired
JmxClient jmxClient; @RequestMapping(value = "/client4", method = GET)
public String test() throws IOException, MalformedObjectNameException, AttributeNotFoundException,
InstanceNotFoundException, MBeanException, ReflectionException {
MBeanServerConnection connection = jmxClient.mbeanServerConnection;
int mbenaCount = connection.getMBeanCount();
System.out.println("There are " + mbenaCount + " MBeans"); ObjectName managerObjName = new ObjectName("spitter:name=SpittleController4");
Set<ObjectName> s = connection.queryNames(managerObjName, null);
for (ObjectName obj : s) {
System.out.println(obj);
} Object cronExpression = connection.getAttribute(new ObjectName("spitter:name=SpittleController4"),
"SpittlesPerPage");
System.out.println(cronExpression);
return "home";
}
@Bean
public MBeanServerConnectionFactoryBean connectionFactoryBean() throws MalformedURLException {
MBeanServerConnectionFactoryBean mbscfb = new MBeanServerConnectionFactoryBean();
mbscfb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter");
return mbscfb;
} @Bean
public JmxClient jmxClient(MBeanServerConnection connection) {
JmxClient jmxClient = new JmxClient();
jmxClient.setMbeanServerConnection(connection);
return jmxClient;
}
}
结果:
3、代理MBean
Spring JMX之二:远程访问MBean的更多相关文章
- spring源码分析之spring jmx
JMX架构定义: https://docs.oracle.com/javase/8/docs/technotes/guides/jmx/overview/architecture.html Archi ...
- 开源框架是如何通过JMX来做监控的(一) - JMX简介和Standard MBean
相关文章目录: 开源框架是如何通过JMX来做监控的(一) - JMX简介和Standard MBean 开源框架是如何通过JMX来做监控的(二) - Druid连接池的监控 相信很多做Java开发的同 ...
- Spring JMX之一:使用JMX管理Spring Bean
spring中关于jmx包括几个概念: MBeanExporter: 从字面上很容易理解, 用来将一些spring的bean作为MBean暴露给MBEanServer.MBeanServerFacto ...
- spring boot / cloud (二) 规范响应格式以及统一异常处理
spring boot / cloud (二) 规范响应格式以及统一异常处理 前言 为什么规范响应格式? 我认为,采用预先约定好的数据格式,将返回数据(无论是正常的还是异常的)规范起来,有助于提高团队 ...
- Spring Data(二)查询
Spring Data(二)查询 接着上一篇,我们继续讲解Spring Data查询的策略. 查询的生成 查询的构建机制对于Spring Data的基础是非常有用的.构建的机制将截断前缀find-By ...
- spring boot / cloud (二十) 相同服务,发布不同版本,支撑并行的业务需求
spring boot / cloud (二十) 相同服务,发布不同版本,支撑并行的业务需求 有半年多没有更新了,按照常规剧本,应该会说项目很忙,工作很忙,没空更新,吧啦吧啦,相关的话吧, 但是细想想 ...
- Spring IOC(二)容器初始化
本系列目录: Spring IOC(一)概览 Spring IOC(二)容器初始化 Spring IOC(三)依赖注入 Spring IOC(四)总结 目录 一.ApplicationContext接 ...
- 深入理解Spring AOP之二代理对象生成
深入理解Spring AOP之二代理对象生成 spring代理对象 上一篇博客中讲到了Spring的一些基本概念和初步讲了实现方法,当中提到了动态代理技术,包含JDK动态代理技术和Cglib动态代理 ...
- spring AOP 之二:@AspectJ注解的3种配置
@AspectJ相关文章 <spring AOP 之二:@AspectJ注解的3种配置> <spring AOP 之三:使用@AspectJ定义切入点> <spring ...
随机推荐
- 把CDLinux制作成U盘启动
因为用下了CDlinux,本来想在虚拟机上运行的.发现虚拟机跑的时候无法识别集成的笔记本网卡,坑爹啊.后来想刻碟的,发现手头上还没有现成的东西,光驱是只读的,又要用到光驱,于是想到了了用U盘,正好手上 ...
- unity里面查找所有物体
测试的时候发现一个很诡异的bug,在prefab里面的物体的属性居然不断的在变化,最后一步步调试才发现,区别是查找物体的api,特此记录下 两种api Canvas[] canvasArray = ( ...
- Mysql中用between...and...查询日期时注意事项
select count(1) from user where regist_date between '2017-07-25 00:00:00' and '2017-07-25 24:00:00' ...
- FatJar—Java Application制作jar包
Fat Jar功能非常强大,先下载吧. 下载地址:sourceforge.net/projects/fjep/files/ http://files.cnblogs.com/files/nidongd ...
- 十一、jdk命令之Jstatd命令(Java Statistics Monitoring Daemon)远程的监控工具连接到本地的JVM执行命令
目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...
- javascript如何判断手机端的浏览器是否支持触碰功能
if(document.hasOwnProperty("ontouchstart")) alert("浏览器支持触屏"); else alert("浏 ...
- Solr中Facet用法和Group用法
Group分组划分结果,返回的是分组结果: Facet分组统计,侧重统计,返回的是分组后的数量: 一.Group用法: //组查询基础配置params.set(GroupParams.GROUP, & ...
- 如何在Solr中实现多core查询
基于solr或者elasticsearch提供的多核,多索引,多shard等查询能力,一般都是由lucene提供的多索引查询的功能演化而来的,这个功能在单机版的lucene里面确实没有发挥多大的威力, ...
- pycharm中使用redis模块入门
数据缓存系统:1:mongodb:是直接持久化,直接存储于硬盘的缓存系统2:redis: 半持久化,存储于内存和硬盘3:memcache:数据只能存储在内存里的缓存系统 redis是一个key-val ...
- uva-11234-表达式
后缀表达式,使用队列计算,要求计算的结果一样,输出队列的输入串 表达式转二叉树,层次序遍历,先右孩子,然后字符串反转输出 #include <iostream> #include < ...