??xml version="1.0" encoding="utf-8" standalone="yes"?>
原文Q?a >http://www.ebook520.com/showbooktext.asp?id=2090&backcolor=E7F4FE&backsize=15Q?br />
jbossmx-1.1.2/jbossmx-1.1.2/lib/jboss-jmx.jar
jbossmx-1.1.2/jbossmx-1.1.2/lib/jboss-jmx-core.jar
JBOSS_HOME/client/gnu-regexp.jar
JBOSS_HOME/client/jbossall-client.jar
标准
1
Q计数器
MBean
下面是一个计数器
MBean
的开发示例?/span>
Q?/span>
1
Q确?/span>
MBean
的接口?/span>
分析计数器的功能Q确定了(jin)两个Ҏ(gu)Q?/span>
?/span>
add()
?/span>
get()
Q?/span>
add()
负责加数Q?/span>
get()
?/span>
责加数ƈ取回LQ?/span>
package
com.liuyang.jmx.mbeans.counter;
public interface
CounterMBean {
public void add(int num);
public int get(int num);
}
从代码中可以看到Q开发标?/span>
MBean
?/span>
MBean
接口和开发普通接口除?jin)需要在
MBean
cdU后面加上?/span>
MBean
”之外,没有其他区别?/span>
Q?/span>
2
Q实?/span>
MBean
接口?/span>
CounterMBean
是一个标?/span>
MBean
Q所?/span>
MBean
实现cȝ名称必须?/span>
MBean
接口
之间遵守标准
MBean
的命名规范,所?/span>
CounterMBean
的实现类
Counter
?/span>
CounterMBean
了(jin)N?/span>
MBean
部分Q下面是
Counter
的实C码:(x)
package
com.liuyang.jmx.mbeans.counter;
public
class Counter implements CounterMBean {
int
sum = 0;
public
void add(int num) {
sum+=num;
}
public
int get(int num) {
sum+=num;
return
sum;
}
}
从代码中也可以看刎ͼ标准
MBean
实现cM普通的
Java
E序也没什么区别?/span>
Q?/span>
3
Q利?/span>
JMX API
~写调用
CounterMBean
的程序?/span>
JMX API
?/span>
Sun
公司?/span>
JMX
技术所设计的一套用来开?/span>
JMX
应用的编E接口,通过
JMX API
可以理和控制前面开发的
CounterMBean
资源。下面是利用
JMX API
~写调用
CounterMBean
的程序代码:(x)
package
com.liuyang.jmx.mbeans.counter;
import
javax.management.MBeanServer;
import
javax.management.MBeanServerFactory;
import
javax.management.ObjectName;
public
class CounterServer {
public
static
void main(String[] args) throws Exception {
MBeanServer server = MBeanServerFactory.createMBeanServer();
ObjectName name = new ObjectName("book.liuyang:service=Counter");
server.registerMBean(new Counter(), name);
String[] sig1 = {"int"};
Object[] opArgs1 = {new Integer(3)};
Object result1 = server.invoke(name, "add", opArgs1, sig1);
System.out.println(result1);
String[] sig2 = {"int"};
Object[] opArgs2 = {new Integer(0)};
Object result2 = server.invoke(name, "get", opArgs2, sig2);
System.out.println(result2);
}
}
2
Q?/span>
ObjectName
ObjectName
代表一?/span>
MBean
对象的名Q创Z?/span>
ObjectName
需要符?/span>
MBean
的命名规范,例如Q?/span>
ObjectName name = new ObjectName("book.liuyang:service=Counter");
3
Q?/span>
MBeanServer
?/span>
CounterServer
E序中,首先创徏?/span>
MBeanServer
q个对象代表前文中介l的
MBean
服务器,它负责管?/span>
MBean
资源Q每?/span>
MBean
资源可以被注册到
MBeanServer
之中Q?/span>
server.registerMBean(new Counter(), name);
通过
MBeanServer
?/span>
invoke
Ҏ(gu)q可以调用一?/span>
MBean
Q在调用旉要传递一些与调用有关的参敎ͼ(x)
Object result1 = server.invoke(name, "add", opArgs1, sig1);
其中Q?/span>
name
是被调用对象的对象名?/span>
"add"
要求
调用被调对象的方法名U?/span>
opArgs1
是一个数l,包含着的每个数据将被作为参C递到被调Ҏ(gu)?/span>
sig1
?/span>
一个数l,包含着被作ؓ(f)参数传递的每个数据的数据类型?/span>
调用之后q回的对象包含着执行的结果?/span>
4
Q?/span>
MBeanServerFactory
MBeanServerFactory
是?/span>
MBeanServer
的工厂类Q用的
JMX
实现工具不同Q通过
MBeanServerFactory
创徏?/span>
MBeanServer
实现对象也不同。如?/span>
MBeanServer
已经被创Z(jin)Q那么可以通过下面的方法获取:(x)
MBeanServer server = MBeanServerFactory.newMBeanServer();
通过q个实例Q可以了(jin)解到使用
MBeanServer
来控?/span>
MBean
的基本方法,下面?/span>
用户查询
MBean
进一步介l通过
MBeanServer
?/span>
MBean
的属性进行查询的Ҏ(gu)?/span>
5
Q用h?/span>
MBean
首先Q确?/span>
MBean
的接口?/span>
用户查询
MBean
中的用户是这?/span>
MBean
所代表的对象,q个设计的用户包括名U和角色Q在q个例子中将对这两个属性进行监控,q是
JMX
为开发者提供的一U机Ӟ所有被理?/span>
MBean
都在
MBeanServer
的控制之中,q个控制不仅包括上个计数器实例中所演示的方法调用功能,也包含对q些
MBean
的相关信息进行考察的功能?/span>
package
com.liuyang.jmx.mbeans.user;
public
interface UserMBean {
public String getName();
publicvoid setName(String name);
}
UserMBean
中被讑֮?jin)两个属性:(x)
name
?/span>
role
Qƈ늅
Java Bean
的规则ؓ(f)它们提供?/span>
get()
?/span>
set()
Ҏ(gu)。通过q两个方法可以设?/span>
UserMBean
的两个属性?/span>
package
com.liuyang.jmx.mbeans.user;
public
class User implements UserMBean {
private String password = "";
public String getName() {
return name;
}
publicvoid setName(String name) {
this.name = name;
}
public
String getRole() {
return
role;
}
public
void setRole(String string) {
role = string;
}
}
User
q个cd是以最单的方式实现?/span>
UserMBean
接口?/span>
?/span>
?/span>
?/span>
UserQueries
演示?/span>
通过
MBeanServer
?/span>
MBean
的属性进行查询的Ҏ(gu)Q代码如下:(x)
package
com.liuyang.jmx.mbeans.user;
import
java.util.Iterator;
import
java.util.Set;
import
javax.management.Attribute;
import
javax.management.MBeanServer;
import
javax.management.MBeanServerFactory;
import
javax.management.ObjectName;
import
javax.management.Query;
import
javax.management.QueryExp;
public
class UserQueries {
publicstaticvoid main(String[] args) throws Exception {
MBeanServer server = MBeanServerFactory.createMBeanServer();
ObjectName user1 = new ObjectName("book.liuyang:Name=user1");
ObjectName user2 = new ObjectName("book.liuyang:Name=user2");
server.createMBean("com.liuyang.jmx.mbeans.user.User", user1);
server.createMBean("com.liuyang.jmx.mbeans.user.User", user2);
server.setAttribute(user1, new Attribute("Role", "code"));
server.setAttribute(user2, new Attribute("Role", "test"));
QueryExp exp = Query.match(Query.attr("Name"),Query.value("user1"));
ObjectName scope = new ObjectName("book.liuyang:*");
Set set = server.queryNames(scope, exp);
Iterator it = set.iterator();
System.out.println("
下列
MBean
的名字是Q?/span>
user1");
while
(it.hasNext()) {
System.out.println(it.next());
}
scope = new ObjectName("book.liuyang:*");
exp = Query.initialSubString(Query.attr("Role"),Query.value("t"));
set = server.queryNames(scope, exp);
it = set.iterator();
System.out.println("
下列
MBean
的角色是Q?/span>
test");
while
(it.hasNext()) {
System.out.println(it.next());
}
}
}
?/span>
UserQueries
中创Z(jin)两个
MBean
对象Q?/span>
server.createMBean("com.liuyang.jmx.mbeans.user.User", user1);
q是
MBeanServer
通过
MBean
cȝ名称创徏
MBean
实例的方法?/span>
然后分别讄它们的属性:(x)
server.setAttribute(user1, new Attribute("Name", "user1"));
一?/span>
Attribute
对象代表一个属性?/span>
JMX API
为查询服务徏立标准的接口Ҏ(gu)Q第一步是建立查询表达式:(x)
QueryExp exp = Query.match(Query.attr("Name"),Query.value("user1"));
q个查询表达式是以全匚w的方式进行的Q?/span>
JMX
q支持部分模p查询的功能Q?/span>
exp = Query.initialSubString(Query.attr("Role"),Query.value("t"));
initialSubString
建立的查询方法只?x)匹配名U的开始部分,在这里只要以?/span>
t
”开头的值都?x)被匚w?/span>
然后Q通过一?/span>
MBean
名称对象来代表查询范_(d)(x)
ObjectName scope = new ObjectName("book.liuyang:*");
最后,通过
MBeanServer
执行查询表达式的操作Q得到结果:(x)
Set set = server.queryNames(scope, exp);
q行
UserQueries
可以得到查询l果?/span>
JBoss
服务器是建立?/span>
JBoss
?/span>
JMX
实现工具Q?/span>
JBossMX
Q基上的Q访?/span>
JBoss
|站Q?/span>
http://www.jboss.org
Q可以下载到独立?/span>
JBoss JMX
实现工具软g?/span>
。将下蝲到的
jbossmx-1.1.2.zip
压羃包解压之后,把下?/span>
jar
文gd?/span>
CLASSPATH
中:(x)
public
String getRole();
public
void setRole(String string);
private
String name = "";
private
String role = "";
server.setAttribute(user1, new Attribute("Name", "user1"));
server.setAttribute(user2, new Attribute("Name", "user2"));
]]>
如自定义MBean服务依赖于其他MBean服务Q可以通过如下Ҏ(gu)实现Q?br />1、在自定义MBean接口中添加Service中Q何方法?br /> q种方式避免?jin)对JBoss具体接口的依赖?br />2、ؓ(f)自定义MBean接口扩展org.jboss.system.Service接口?br />
3、ؓ(f)自定义MBean接口扩展org.jboss.system.ServiceMBean接口?br /> 最单的办法是将自定义MBean接口l承于ServiceMBean接口Q将MBean实现cȝ承ServiceMBeanSupportcRServiceMBeanSupport已经实现?jin)ServiceMBean接口QServiceMBeanSupportq集成了(jin)日志、JBoss服务状态管理跟t功能,q些Ҏ(gu)需要我们具体实现createService、startService、stopService和destroyService中的部分Ҏ(gu)?br />
下面介绍ZServiceMBean接口和ServiceMBeanSupportcȝJNDIMapMBean接口?qing)其JNDIMap实现cR?br />
package org.joss.chap2.ex2;
import javax.naming.NamingException;
import org.jboss.system.ServiceMBean;
public interface JNDIMapMBean extends ServiceMBean
{
public String getJndiName();
public void setJndiName(String jndiName) throws NamingException;
}
package org.joss.chap2.ex2;
import java.util.HashMap;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingException;
import org.jboss.naming.NonSerializableFactory;
import org.jboss.system.ServiceMBeanSupport;
public class JNDIMap extends ServiceMBeanSupport implements JNDIMapMBean
{
private String jndiName;
private HashMap contextMap = new HashMap();
public JNDIMap()
{
super();
// TODO Auto-generated constructor stub
}
public String getJndiName()
{
return jndiName;
}
public void setJndiName(String jndiName) throws NamingException
{
String oldName = this.jndiName;
this.jndiName = jndiName;
if(super.getState()==STARTED)
{
unbind(oldName);
try
{
rebind();
}
catch(Exception e)
{
NamingException ne = new NamingException("Failed to update jndiName");
ne.setRootCause(e);
throw ne;
}
}
}
public void startService()throws Exception
{
rebind();
}
public void stopService()
{
unbind(jndiName);
}
private void rebind() throws NamingException
{
I(yng)nitialContext rootCtx = new InitialContext();
Name fullName = rootCtx.getNameParser("").parse(jndiName);
NonSerializableFactory.rebind(fullName,contextMap,true);
}
private void unbind(String jndiName)
{
try
{
I(yng)nitialContext rootCtx = new InitialContext();
rootCtx.unbind(jndiName);
NonSerializableFactory.unbind(jndiName);
}
catch(NamingException e)
{
System.out.println(e);
}
}
public String getName()
{
// TODO Auto-generated method stub
return null;
}
public int getState()
{
// TODO Auto-generated method stub
return 0;
}
public String getStateString()
{
// TODO Auto-generated method stub
return null;
}
public void jbossInternalLifecycle(String arg0) throws Exception
{
// TODO Auto-generated method stub
}
public void create() throws Exception
{
// TODO Auto-generated method stub
}
public void start() throws Exception
{
// TODO Auto-generated method stub
}
public void stop()
{
// TODO Auto-generated method stub
}
public void destroy()
{
// TODO Auto-generated method stub
}
public ObjectName preRegister(MBeanServer arg0, ObjectName arg1)
throws Exception
{
// TODO Auto-generated method stub
return null;
}
public void postRegister(Boolean arg0)
{
// TODO Auto-generated method stub
}
public void preDeregister() throws Exception
{
// TODO Auto-generated method stub
}
public void postDeregister()
{
// TODO Auto-generated method stub
}
}
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.joss.chap2.ex2.JNDIMap"
name="chap2.ex2:service=JNDIMap">
<attribute name="JndiName">inmemory/map/MapTest</attribute>
<depends>jboss:service=Naming</depends>
</mbean>
</server>
JBOSS实现?/span>JMX规范Q这个实例是ZJBOSS来实现的。请先去下蝲一?/span>JBOSSQ我?/span>jboss-3.2.6Q下载地址Q?/span>http://www.jboss.com/downloads/index#as。这个实例需?/span>JBOSS的两?/span>JAR包的支持Q?/span>jboss-system-3.2.6.jar?/span>jboss-jmx-3.2.6.jarQ如果你和我一L(fng)Eclipse来开发(推荐Q,那么把这个两个包加入到项目的库引用中Q加入到库引用的Ҏ(gu)参考前面两章)(j)?/span>
假设我们有一个叫message的属性要需要经常进行改动配|的Q那么我们就把它写成一?/span>MBean?/span>
1?/span>HelloWorldServiceMBean接口
在写MBean之前Q我们先需要写一?/span>MBean接口Q接口里的方法都是属性的set/getҎ(gu)。这个接口必ȝ承接?/span>ServiceMBean?/span>
2?/span>HelloWorldService实现c?/span>
然后写出HelloWorldServiceMBean接口的实现类HelloWorldServiceQ这个实现类q必ȝ?/span>ServiceMBeanSupportcR?/span>q种cd单不q了(jin)Q就是属性和相应?/span>set/getҎ(gu)Q?/span>EJB中叫实体cR?/span>Hibernate中叫POJO?/span>
import org.jboss.system.ServiceMBeanSupport;
public class HelloWorldService extends ServiceMBeanSupport implements HelloWorldServiceMBean {
private String message;
public String getMessage() {
System.out.println("getMessage()=" + message);
return message;
}
public void setMessage(String message) {
System.out.println("setMessage(" + message + ")");
this.message = message;
}
}
3、配|文?/span>jboss-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="example.mbean.HelloWorldService" name="www.chengang.com.cn:service=HelloWorld">
<attribute name="Message">Hello World</attribute>
</mbean>
</server>
说明Q?/font>
l codeҎ(gu)?/span>MBean的实现类HelloWorldService
l nameҎ(gu)一个名Uͼ格式一般是Q?/span>[说明性文?/span>]:service=[cd]
l attribute是ؓ(f)属性设|初始|q样?/span>JBOSS一加蝲HelloWorldServicecLQ?/span>message属性就有了(jin)一个初始?/span>Hello World。注?/span>Message的第一个字母必L大写?/span>
?/span>jboss-3.2.6\server\default\deploy目录下创Z?/span>hello.sar目录Q然后创建如下目录文件结构:(x)
hello.sar
|----example
| |----mbean
| |----HelloWorldService.class (注意Q是*.classQ不?/span>*.java)
| |----HelloWorldServiceMBean.class
|----META-INF
|----jboss-service.xml
其他说明Q?/font>
l 也可以将hello.sar目录?/span>zip格式压羃成一个同名的hello.sar文gQ放?/span>jboss-3.2.6\server\default\deploy目录下?br />l JBOSS支持热部|Ԍ也就是说你在布置q个目录时ƈ不需要重?/span>JBOSS?/span>
然后单击?/span>service=HelloWorld”项打开详细面如下Q?br />
?/span>HelloWorld”改成?/span>Hello WorldQ?/span>ChenGang”,再单几Z?/span>Apply Changes”应用修改,得到如下效果Q?br />
现在我们可以通过一个自动提供的WEB面来设|?/span>Message属性了(jin)Q接下来的问题是Q“在其他cM应该如何得到Message的属性值”?/span>MBean?/span>JBoss是只保留一?/span>MBean的实例(单例模式Q)(j)Q也是说问题{成我们如何去取得q个唯一实例。例E如下:(x)
1、创Z个用到Message属性的c?/span>
import org.jboss.mx.util.MBeanProxyExt;
注意Q?/span>goҎ(gu)里是三句。第一句比较长Q它是根?/span>jboss-service.xml文g中设|的MBean名称Q来取得?/span>MBean?/span>JBOSS中的实例?/span>
2、在Mbean中加一个相应的调用Client.go的方?/span>
?/span>HelloWorldServiceMBean接口中加入一句:(x)
void callGo();
?/span>HelloWorldServicecM加入现实Ҏ(gu)Q?/span>
public void callGo() {
new Client().go();
}
3、更新布|?/span>
三个类?/span>class文gQ?/span>Clien.class?/span>HelloWorldServiceMBean.class?/span>HelloWorldService.classQ更新到JBOSS?/span>hello.sar\example\mbean目录下。然后重?/span>JBOSS?/span>
4、查看效?/span>
打开JBOSS提供?/span>MBean讄面Q如下,发现多了(jin)一?/span>callGo?/span>
单击callGo后?/span>invoke按钮Q得到如下的DOS输出Q?/span>
l 本实例仅演示?jin)一?/span>Message属性,你当然可以在HelloWorldService中加入更多属性,别忘?jin)?/span>HelloWorldServiceMBean接口也加入相应的set/getҎ(gu)?br />l 本实例的message属性是Stringcd的,?/span>JMX也支持其他的cdQ甚xXML信息。对?/span>jboss-service.xml中的XML信息Q这时属性类型要求是org.w3c.dom.ElementQ?/span>JMX它?yu)装成?jin)一?/span>XML?/span>DOM对象?br />l 回顾一下,JMX也是配|信息写在了(jin)一个文Ӟjboss-service.xml文gQ里嘛,相对于将配置文g写到*.properties文g的方式,它似乎也没什么新鲜的地方。但通过本章实例我们可以看到JMX的一些好处:(x)我们不用写代码去读配|文件的信息Q而且JMX支持的属性类型是多种多样的(如上面说?/span>org.w3c.dom.ElementQ。更重要的是JMXq提供了(jin)一整套的属性之前互相访问、互相调用的功能Q这?/span>HelloWorld实例所反映的只是冰׃角而已?/span>
ModelMBeanOperationInfo getName = new ModelMBeanOperationInfo(//
"getName", //
"get name attribute", //
null, //
"java.lang.String", //
MBeanOperationInfo.ACTION, //
getStateDesc //
);
// 构?setName操作描述W信?br /> Descriptor setStateDesc = new DescriptorSupport(new String[] {
"name=setName", "descriptorType=operation", "class=Hello",
"role=operation" });
MBeanParameterInfo[] setStateParms = new MBeanParameterInfo[] { (new MBeanParameterInfo(
"name", "java.lang.String", "new name value")) };
ModelMBeanOperationInfo setName = new ModelMBeanOperationInfo(//
"setName", //
"set name attribute", //
setStateParms, //
"void", //
MBeanOperationInfo.ACTION, //
setStateDesc //
);
//构?printHello()操作的信息 ?
ModelMBeanOperationInfo print1Info = new ModelMBeanOperationInfo(//
"printHello", //
null, //
null, //
"void", //
MBeanOperationInfo.INFO, //
null //
);
// 构造printHello(String whoName)操作信息
ModelMBeanOperationInfo print2Info;
MBeanParameterInfo[] param2 = new MBeanParameterInfo[1];
param2[0] = new MBeanParameterInfo("whoName", STRING_CLASS, "say hello to who");
print2Info = new ModelMBeanOperationInfo(//
"printHello", //
null,//
param2,//
"void", //
MBeanOperationInfo.INFO, //
null//
);
//////////////////////////////////////////////////////////////////
// 最后d //
//////////////////////////////////////////////////////////////////
// create ModelMBeanInfo
ModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport(//
RequiredModelMBean.class.getName(), // MBeanc?br /> null, // 描述文字
new ModelMBeanAttributeInfo[] { // 所有的属性信息(数组Q?br /> nameAttrInfo },//只有一个属?br /> null, // 所有的构造函C?
new ModelMBeanOperationInfo[] { // 所有的操作信息Q数l)(j)
getName,
setName,
print1Info,
print2Info },//
null, // 所有的通知信息(本例?
null//MBean描述?br /> );
return mbeanInfo;
}
}
4、看效果的方法和以前一Pq行HelloAgentQ用览器打开Qhttp://localhost:8082 。效果图和standard mbean一P׃再帖出来?jin),ȝ一去看吧http://blog.sohu.com/members/somebody076/545896.html
二、ȝ
我们发现模型Mbean(Model MBean)要比标准MBean(standard mbean)复杂多了(jin)Q那有什么理p我们选择使用模型MBean吗?我认为,最大的理由是模型MBean可以动态配|。试想一下这个应用场景:(x)׃安全或其他原因,pȝ要把某个MBean公开的可理Ҏ(gu)隐藏h。这Ӟ如果你是用标准MBeanQ这需要修Ҏ(gu)口类Q然后重新编译发布;如果?Apache commons-modeler来写的模型MBeanQ则只需要修改XML文gp?jin),不需要重新编译发布(可能要重启一下系l)(j)。这是模型Mbean 优势之所在了(jin)?br />
l心(j)的h?x)发现动态MBean和这一节的模型Mbean非常怼Q但它们q是有很大不同的Q动态MBean没有Helloc,它要自己实现HellocM的方法逻辑?/p>
JMX是一UJAVA的正式规范,它主要目的是让程序且有被理的功能,那么怎么理解所谓的“被理”呢Q试想你开发了(jin)一个YӞ如DQ|? 站)(j)Q它是在Q4时不简断运行的Q那么你可能?x)想要“监控”这个Y件的q行情况Q比如收C(jin)多少数据Q有多少人登录等{。或者你又想“配|”这个YӞ 比如现在讉K人数比较多,你想把数据连接池讄得大一些?/font>
当然Q你也许?x)专门?f)q些理来开发YӞ但如果你借助JMXQ则?x)发现创L(fng)理E序是如此简单。因Z无需为管理程序来开发界面,已经 有通用的JMX理软gQ如MC4JQ或者是用一般都附带提供的HTML|页来管理,你要做的仅仅是将自己要被理和监控类的按照JMX规范修改一下即 可?/font>
中间件Y件WebLogic的管理页面就是基于JMX开发的Q而JBoss则整个系l都ZJMX构架。下面将JMX的一些概念,从JMX规范转帖如下Q?/font>
二、JMX构架中的各层?qing)相关的lg
MBean中有getter和setter的就是属性,如前一的HellocMName。如果只有getter则表C属性只诅R一共有四种MBeanQ如下:(x)