JMX的一些讨论

最近工作中用到了JMX,遇到了一些问题,正好记录一下。
spring的jmx配置文件就是参考文档的,见最后。

稍稍说明三点:
(1) Registry bean用来注册一个rmi的连接器,告知开启的端口号。
(2) ServerConnector用来构建服务器端的连接,这里用的是iiop的连接方式。objectName和serviceUrl要匹配。
(3) Assembler配置了对外暴露的mbean,这里就是把mbeanName这个接口的方法都暴露出去。

在使用的过程中,我碰到了一些问题和疑问,总结如下:
1、 本机启动应用之后,发现jmx端口没有打开,可是用jconsole连接serviceUrl的服务,却可以连接的上?

因为这个时候serviceUrl就是本机地址127.0.0.1的,这个通信连接是本机进程之间的通信。进程间的通信(Interprocess Communication)有多种方式,主要有以下几种:
◎ 文件映射:一个进程建立一个文件映射对象,写入数据,另一个进程从中取出数据,也就是这两个进程共享了文件中的数据。
◎ 共享内存:与文件映射类似,一个进程把数据写入内存,另一个进程从内存中取出数据。
◎ 管道:两个进程之间的有序通道。
◎ 套接字(socket):网络应用大多使用它。

所以尽管我连接的是“service:jmx:iiop://10.13.37.62:9099/”(10.13.37.62是本机IP),但其实并不是通过socket来通信的,估计是通过共享内存或者文件映射来通信的,具体实现我并不清楚。所以,这个时候,jmx的端口并没有开启。
加上registry bean的配置之后,可以看到JMX的端口9099端口就可以打开了。
所以,不要以为本地可以连接就OK了啊~~


2、 RMI-IIOP是什么?

在RMI-IIOP出现之前,分布式程序设计只有两种选择,RMI和CORBA。RMI就是远程方法调用,仅用于java对java的分布式远程调用,所以RMI对java开发者而言相当透明而且易于实现,而CORBA是面向对象的分布式系统的建立标准,对语言独立,接口采用了非常通用的标准。RMI-IIOP结合了RMI的简单和CORBA的多语言的优点。
我这次用的是iiop,如果要指定其他URL或者要用 MBeanServer 注册 JMXConnectorServer, 要使用相应的 serviceUrl 和 ObjectName 属性。


3、 关于远程调用的参数调用

讲到这里,我顺便把Java中的传值调用好好写写。
Java中,如果传递的是基本数据类型(如int, double, char等)的参数的话,实际传入方法内部的是输入参数的一个拷贝,这个拷贝进入方法之后就作为局部变量,所有在方法内部的操作都是针对这个局部变量来进行的,方法结束之后,这个局部变量就完成了使命。所以在方法内部改变参数的值,并不会对输入的参数造成影响。这也就是为什么像下面的swap方法不起作用的原因。

public static void main(String[] args) {
	int i = 2;
	int j = 3;
	swap(i,j);
	System.out.println("i===" + i);
	System.out.println("j===" + j);
}
	
private static void swap(int pram1, int pram2) {
	int temp = pram2;
	pram2 = pram1;
	pram1 = temp;
}

输出结果:
i===2
j===3


如果参数是对象的话,传递的是这个对象引用的一个copy。一个对象在建立的时候,会创建一个指向这个对象的引用a。如下图所示:
JMX的一些讨论
当把这个对象作为参数传递给方法的时候,会重新拷贝一个对象的引用b,这个时候,引用a和b都指向了同一个对象。所以,尽管方面里面的局部变量b与实际创建对象时候的a并不是同一个引用,但是它们指向的都是同一个对象。在方法里修改b的属性的时候,其实也就是修改b指向的对象的属性。
JMX的一些讨论
举例:
public static void main(String[] args) {
	TestClass a = new TestClass();
	a.setClassName("class a");
	System.out.println("before changeClassName======className is " + a.getClassName());
	changeClassName(a, "class b");
	System.out.println("after changeClassName======className is " + a.getClassName());	
} 
	
private static void changeClassName(TestClass object, String className) {
	bject.setClassName(className);
} 

class TestClass{
	private String className;

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}
}

上面代码的执行结果为:
before changeClassName======className is class a
after changeClassName======className is class b


对于远程调用来说,大体上的规则还是一样的,只是因为数据要在client和server端进行传输,所以要把参数序列化与反序列化。
比如,本地为客户端client,要调用server端的userService.changeUserName(User user)这个方法,我在client上新建了一个user,现在这个user是client上的一个对象,然后通过RMI来调用远程方法changeUserName(user),那么就需要把user这个对象序列化,传递给server,然后在server端反序列化user,创建一个User对象,做相应的修改操作之后,再把server端的这个user对象序列化了传回client。最后,client反序列化server传递过来的user对象,再修改client本地的对应的user对象。所以,修改user name的操作就是在服务器上做的。

最后,附上spring的jmx配置文件:
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">	<property name="port" value="9099"></property>
</bean> 
<bean id="mbeanName"  class="com.***.jmx.***MBeanImpl">
	<constructor-arg value="9099" />
</bean>
<bean id="assembler" class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">   
	<property name="managedInterfaces">
		<value>com.***.jmx.***MBean</value>
        </property>
</bean>
<bean id="namingStrategy" class="org.springframework.jmx.export.naming.KeyNamingStrategy" >
</bean>	
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter"  lazy-init="false">
	<property name="beans">
		<map>
			<entry key="bean:name=***Bean" value-ref="mbeanName"/>
		</map>
	</property>
	<property name="server" ref="mbeanServer"/>
	<property name="autodetect" value="false"/>
	<property name="assembler" ref="assembler" />
	<property name="namingStrategy" ref="namingStrategy"/>
</bean>
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
</bean>
<!-- Expose JMX over RMI -->
<bean id="serverConnector" class="com.***.jmx.ConnectorServerFactoryBean" depends-on="registry">
	<property name="objectName" value="connector:name=iiop" />
	<property name="server" ref="mbeanServer"/>
	<property name="serviceUrl" value="service:jmx:iiop://localhost:9099" />
</bean>

你可能感兴趣的:(spring,应用服务器,bean,socket,网络应用)