使用JMX查看一个简单的main方法java 运行main有多少

登录以解锁更多InfoQ新功能
获取更新并接收通知
给您喜爱的内容点赞
关注您喜爱的编辑与同行
966,690 二月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
JMX 在InfoQ上的内容
架构 & 设计
文化 & 方法
InfoQ.com及所有内容,版权所有 ©
C4Media Inc. InfoQ.com 服务器由 提供, 我们最信赖的ISP伙伴。
极客邦控股(北京)有限公司
找回密码....
InfoQ账号使用的E-mail
关注你最喜爱的话题和作者
快速浏览网站内你所感兴趣话题的精选内容。
内容自由定制
选择想要阅读的主题和喜爱的作者定制自己的新闻源。
设置通知机制以获取内容更新对您而言是否重要
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?
我们发现您在使用ad blocker。
我们理解您使用ad blocker的初衷,但为了保证InfoQ能够继续以免费方式为您服务,我们需要您的支持。InfoQ绝不会在未经您许可的情况下将您的数据提供给第三方。我们仅将其用于向读者发送相关广告内容。请您将InfoQ添加至白名单,感谢您的理解与支持。在生产环境中可能经常遇到各种问题,定位问题需要获取程序运行时的数据信息,如方法参数、返回值、全局变量、堆栈信息等。为了获取这些数据信息,我们可以通过改写代码,增加日志信息的打印,再发布到生产环境。通过这种方式,一方面将增大定位问题的成本和周期,对于紧急问题无法做到及时响应;另一方面重新部署后环境可能已被破坏,很难重新问题的场景。
对于程序员来说最头大的问题之一就是线上出了故障了,但是我们无法debug来找出问题原因,同时在上线的时候日志级别限定了我们不可能把所有的细节都打印到log上,这个时候故障都等在哪里,能办的手段无非看源码,通过仔细看代码来找出问题,并编译重新上线解决,这种手段能解决一部分代码,但是对于一些隐藏较深的bug就无能为力了,例如OOM或是频繁的full gc,一般是一个很多的对象没有被释放或是一个对象被频繁的创建调用。在一个复杂的项目中,一个OOM问题可能是一个对象被频繁创建,这种方式指望通过看源码是很难解决的,但是BTrace可以迅速帮助我们定位到问题所在地。
Btrace (Byte Trace)是sun推出的一款java 动态、安全追踪(监控)工具,可以不停机的情况下监控线上情况,并且做到最少的侵入,占用最少的系统资源。BTrace应用较为广泛的原因应该是其安全性和无侵入性,其中热交互技术,使得我们无需启动Agent的情况下动态跟踪分析,其安全性不会导致对目标Java进程的任何破坏性影响,使得BTrace成为我们线上产品问题定位的利器。无侵入性无需我们对原有代码做任何修改,降低上线风险和测试成本,并且无需重启启动目标Java进程进行Agent加载即可动态分析和跟踪目标程序,可以说BTrace可以满足大部分的应用场景。
下载BTrace(),解压至任意目录。
设置BTRACE_HOME,将bin目录加至环境变量PATH中。
jps命令查出需要监控的jvm pid
编写BTrace跟踪程序 (安装包中带有大量的Demo,附录会对各个Demo的功能进行一一说明)
执行:btrace &pid& BTrace跟踪程序
BTrace主要包含btracec和btracer两个命令编译和启动BTrace脚本:1. btrace
功能: 用于运行BTrace跟踪程序。
btrace [-I &include-path&] [-p &port&] [-cp &classpath&] &pid& &btrace-script& [&args&]
-I:没有这个表明跳过预编译
include-path:指定用来编译脚本的头文件路径(关于预编译可参考例子ThreadBean.java)
port:btrace agent端口,默认是2020
classpath:编译所需类路径,一般是指btrace-client.jar等类所在路径
pid:java进程id
btrace-script:btrace脚本可以是.java文件,也可以是.class文件
args:传递给btrace脚本的参数, 在脚本中可以通过$(), $length()来获取这些参数(定义在BTraceUtils中)
btrace -cp build/ 1200 AllCalls1.java
include-path指定头文件的路径,用于脚本预处理功能,可选;
port指定BTrace agent的服务端监听端口号,用来监听clients,默认为2020,可选;
classpath用来指定类加载路径,默认为当前路径,可选;
pid表示进程号,可通过jps命令获取;
btrace-script即为BTrace脚本;btrace脚本如果以.java结尾,会先编译再提交执行。可使用btracec命令对脚本进行预编译。
args是BTrace脚本可选参数,在脚本中可通过"$"和"$length"获取参数信息。2. btracec
功能: 用于预编译BTrace脚本,用于在编译时期验证脚本正确性。
btracec [-I &include-path&] [-cp &classpath&] [-d &directory&] &one-or-more-BTrace-.java-files&
参数意义同btrace命令一致,directory表示编译结果输出目录。3. btracer
功能: btracer命令同时启动应用程序和BTrace脚本,即在应用程序启动过程中使用BTrace脚本。而btrace命令针对已运行程序执行BTrace脚本。
btracer &pre-compiled-btrace.class& &application-main-class& &application-args&
pre-compiled-btrace.class表示经过btracec编译后的BTrace脚本。
application-main-class表示应用程序代码;
application-args表示应用程序参数。
该命令的等价写法为:
java -javaagent:btrace-agent.jar=script=&pre-compiled-btrace-script1&[,&pre-compiled-btrace-script1&]* &MainClass& &AppArguments&
虽然BTrace很强大,但Btrace脚本就是一个普通的用@Btrace注解的Java类,其中包含一个或多个public static void修饰的方法,为了保证对目标程序不造成影响,Btrace脚本对其可以执行的动作做了很多限制,如下:
不能创建对象
不能抛出或者捕获异常
不能用synchronized关键字
不能对目标程序中的instace或者static变量
不能调用目标程序的instance或者static方法
脚本的field、method都必须是static的
脚本不能包括outer,inner,nested class
脚本中不能有循环,不能继承任何类,任何接口与assert语句
方法上的注解
@ OnMethod用来指定trace的目标类和方法以及具体位置,被注解的方法在匹配的方法执行到指定的位置会被调用。
1、"clazz"属性用来指定目标类名,可以指定全限定类名,比如"java.awt.Component",也可以是正则表达式(表达式必须写在"//"中,比如"/java\\.awt\\..+/")。
2、"method"属性用来指定被trace的方法.表达式可以参考自带的例子(NewComponent.java和Classload.java,关于方法的注解可以参考MultiClass.java)。
3、有时候被trace的类和方法可能也使用了注解.用法参考自带例子WebServiceTracker.java。
4、针对注解也是可以使用正则表达式,比如像这个"@/com\\.acme\\..+/ ",也可以通过指定超类来匹配多个类,比如"+java.lang.Runnable"可以匹配所有实现了java.lang.Runnable接口的类.具体参考自带例子SubtypeTracer.java。
@OnTimer定时触发Trace,时间可以指定,单位为毫秒,具体参考自带例子Histogram.java。
@OnError当trace代码抛异常或者错误时,该注解的方法会被执行.如果同一个trace脚本中其他方法抛异常,该注解方法也会被执行。
@OnExit当trace方法调用内置exit(int)方法(用来结束整个trace程序)时,该注解的方法会被执行.参考自带例子ProbeExit.java。
@OnEvent用来截获"外部"btrace client触发的事件,比如按Ctrl-C中断btrace执行时,并且选择2,或者输入事件名称,将执行使用了该注解的方法,该注解的value值为具体事件名称。具体参考例子HistoOnEvent.java
@OnLowMemory当内存超过某个设定值将触发该注解的方法,具体参考MemAlerter.java
@OnProbe使用外部文件XML来定义trace方法以及具体的位置,具体参考示例SocketTracker1.java和java.net.socket.xml。
参数上的注解
@Self用来指定被trace方法的this,可参考例子AWTEventTracer.java和AllCalls1.java
@Return用来指定被trace方法的返回值,可参考例子Classload.java
@ProbeClassName (since 1.1)用来指定被trace的类名,可参考例子AllMethods.java
@ProbeMethodName (since 1.1)用来指定被trace的方法名,可参考例子WebServiceTracker.java。
@TargetInstance (since 1.1)用来指定被trace方法内部被调用到的实例,可参考例子AllCalls2.java
@TargetMethodOrField (since 1.1)用来指定被trace方法内部被调用的方法名,可参考例子AllCalls1.java和AllCalls2.java。
非注解的方法参数
未使用注解的方法参数一般都是用来做方法签名匹配用的,他们一般和被trace方法中参数出现的顺序一致.不过他们也可以与注解方法交错使用,如果一个参数类型声明为*AnyType[]*,则表明它按顺序"通吃"方法所有参数.未注解方法需要与*Location*结合使用:
Kind.ENTRY-被trace方法参数
Kind.RETURN-被trace方法返回值
Kind.THROW -抛异常
Kind.ARRAY_SET, Kind.ARRAY_GET -数组索引
Kind.CATCH -捕获异常
Kind.FIELD_SET -属性值
Kind.LINE -行号
Kind.NEW -类名
Kind.ERROR -抛异常
属性上的注解
@Export该注解的静态属性主要用来与jvmstat计数器做关联, 使用该注解之后,btrace程序就可以向jvmstat客户端(可以用来统计jvm堆中的内存使用量)暴露trace程序的执行次数, 具体可参考例子ThreadCounter.java。
@Property使用了该注解的trace脚本将作为MBean的一个属性,一旦使用该注解, trace脚本就会创建一个MBean并向MBean服务器注册, 这样JMX客户端比如VisualVM, jconsole就可以看到这些BTrace MBean, 如果这些被注解的属性与被trace程序的属性关联, 那么就可以通过VisualVM和jconsole来查看这些属性了, 具体可参考例子ThreadCounterBean.java和HistogramBean.java。
@TLS用来将一个脚本变量与一个ThreadLocal变量关联, 因为ThreadLocal变量是跟线程相关的, 一般用来检查在同一个线程调用中是否执行到了被trace的方法, 具体可参考例子OnThrow.java和WebServiceTracker.java。
类上的注解
@com.sun.btrace.annotations.DTrace用来指定btrace脚本与内置在其脚本中的D语言脚本关联, 具体参考例子DTraceInline.java。
@com.sun.btrace.annotations.DTraceRef用来指定btrace脚本与另一个D语言脚本文件关联, 具体参考例子DTraceRefDemo.java。
@com.sun.btrace.annotations.BTrace用来指定该java类为一个btrace脚本文件。
1.跟踪WildFly内存信息,用@OnTimer 这个annotation每隔4秒钟打印一次内存堆栈信息:
import com.sun.btrace.annotations.BT
import com.sun.btrace.annotations.OnT
import static com.sun.btrace.BTraceUtils.*;
public class TraceMemory {
//heapUsage()/nonHeapUsage() – 打印堆/非堆内存信息,包括init、used、commit、max
@OnTimer(4000)
public static void printM(){
//打印内存信息
println("heap:");
println(heapUsage());
println("no-heap:");
println(nonHeapUsage());
查找 WildFly pid:
[root@mdwareweb1 test]# jps
5513 jboss-modules.jar
btrace 5513 TraceMemory.java
[root@mdwareweb1 test]# btrace 5513 TraceMemory.java
init = 36K) used = 95K) committed = 4480K) max = 6048K)
init = 88K) used = 48K) committed = 12K) max = 1296K)
init = 36K) used = 31K) committed = 4480K) max = 6048K)
init = 88K) used = 48K) committed = 12K) max = 1296K)
init = 36K) used = 31K) committed = 4480K) max = 6048K)
init = 88K) used = 52K) committed = 12K) max = 1296K)
2、打印WildFly运行时系统信息:
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.BT
public class TraceJInfo {
println("java vm properties:===&");
printVmArguments();
println("System properties:===&");
printProperties();
println("OS properties:===&");
printEnv();
执行结果:
[root@mdwareweb1 test]# btrace 5513 TraceJInfo.java
java vm properties:===&
[-D[Standalone], -Xms64m, -Xmx512m, -XX:MaxPermSize=256m, -Djava.net.preferIPv4Stack=true, -Djboss.modules.system.pkgs=org.jboss.byteman, -Djava.awt.headless=true, -Dorg.jboss.boot.log.file=/opt/jboss/wildfly-8.0.0.Final/standalone/log/server.log, -Dlogging.configuration=]
System properties:===&
org.jboss.security.context.ThreadLocal = true
java.vm.version = 23.25-b01
sun.jnu.encoding = UTF-8
java.vendor.url =
java.vm.info = mixed mode
org.apache.xml.security.ignoreLineBreaks = true
jboss.server.name = mdwareweb1
java.awt.headless = true
user.dir = /opt/jboss/wildfly-8.0.0.Final/bin
sun.cpu.isalist =
logging.configuration =
3、排查ClassNotFoundException
写过Java代码的读者估计都碰到过ClassNotFoundException/NoClassDefFoundError/NoSuchMethodException(还有一个常见的ClassCastException就不在这里说了)。当碰到ClassNotFoundException/NoClassDefFound时,如果很确定这个class应该是从哪个路径装载的,则可以去相应的路径找下是否有对应的class文件存在,例如web应用通常会在*.war(ear)/WEB-INF/lib或classes目录下,对于lib下的jar包,可通过写个小脚本jar
-tvf的方式找找;如不确定class是从哪装载的,则可以先看看日志里是否有堆栈信息,如果有的话则可以看到具体是哪个ClassLoader实现在装载class,之后则可以通过www.grepcode.com或jar包反编译看看具体是从哪装载的class;如果日志中没有,则可以用btrace来跟踪下抛出以上两个异常的堆栈信息,btrace脚本类似如下:
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
@BTrace public class Trace{
@OnMethod(
clazz="java.lang.ClassNotFoundException",
method="&init&"
public static void traceExecute(){
拿到堆栈信息后,可以继续使用上面的方法进行排查,在确认了class装载的位置后,则可将相应的class/jar加上即可。
4、排查OutOfMemoryError
尽管JVM是自动管理内存的分配和回收的,但Java程序员们还是会经常碰到各种各样的内存问题。最常见的第一个问题是java.lang.OutOfMemoryError,估计写Java的读者都碰到过。在日志中可能会看到java.lang.OutOfMemoryError: Unable to create new native thread,可以先统计下目前的线程数(例如ps -eLf | grep java -c),然后可以看看ulimit -u的限制值是多少,如线程数已经达到限制值,如限制值可调整,则可通过调整限制值来解决;如不能调限制值,或者创建的线程已经很多了,那就需要看看线程都是哪里创建出来的,同样可通过btrace来查出是哪里创建的,脚本类似如下:
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
@BTrace public class Trace{
@OnMethod(
clazz="java.lang.Thread",
method="start"
public static void traceExecute(){
在找到是哪里创建造成了后,之后就可以想办法解决了,例如这种情况下常见的有可能是用了Executors.newCachedThreadPool这种来创建了一个没限制大小的线程池。
以下是笔者编写的一个demo,主要用于测试OOM,当然也会对BTrace的功能进行介绍。
首先,笔者编写了两个用于测试的类,如下:
StartObject.java
import java.util.R
public class StartObject {
private static int totalTime = 0;
public int work(int sleepTime) throws InterruptedException{
System.out.println("sleep " + sleepTime);
totalTime += sleepT
return totalT
HeapOOM.java
import java.util.ArrayL
import java.util.L
import java.util.R
public class HeapOOM {
public static void main(String agrs[]) throws InterruptedException{
Random random = new Random();
List&Integer& list = new ArrayList&Integer&();
Thread.sleep(10000);
while(true){
int sleepTime = random.nextInt(1000);
list.add(new StartObject().work(sleepTime));
由于笔者将运行时jvm参数设置为:-Xms10m -Xmx10m
因此程序会因为HeapOOM.java中红色一行代码不断创建对象而发生OutOfMemoryError异常。
以下,我们便通过StartObject这个类来查找是在哪不断新建对象并调用其work方法,于是编写BTrace脚本如下:
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
public class TraceObject {
@OnMethod(clazz = "StartObject", method = "work", location = @Location(value = Kind.CALL, clazz = "/.*/", method = "/.*/"))
public static void checkWhoCallMe() {
println("check who ActionObject.work method:");
通过jps查找到HeapOOM执行的pid
执行:btrace [pid] TraceObject.java
在终端我们看到HeapOOM类中执行StratObject.work方法,如此即可找到我们想要的执行对象,从而可以去修改。
若是得到work方法的执行时间的话,脚本如下:
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
public class TraceObjectCost {
static long startT
@OnMethod(clazz = "StartObject", method = "work", location = @Location(Kind.RETURN))
public static void start() {
startTime = timeMillis();
@OnMethod(clazz = "StartObject", method = "work", location = @Location(Kind.RETURN))
public static void getMethodExecuteCost(int sleepTime,@Return int totalTime) {
String str = str(timeMillis() - startTime);
String strcat = strcat("execute work method cost:", str);
String strcat2 = strcat(strcat, " ms");
println(strcat2);
若是期望的到一个method哪几行被执行了的话,脚本如下:
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
public class TraceObjectLineCall {
@OnMethod(clazz="StartObject",method="work",location=@Location(value=Kind.CALL, clazz="/.*/", method="/.*/"))
public static void lineCall(@Self StartObject self, @TargetMethodOrField String method, @ProbeMethodName String probeMethod){
println(Strings.strcat(method, Strings.strcat(" in ", probeMethod)));
虽然 Btrace 在关键时候能起到迅速排查问题的作用,但我个人感觉,这还是不到万不得已才使用的好。首先,我们代码上线前,应该充分 review ,充分和相关方进行沟通,以避免不必要的问题发生。其次,我们应该养成记 log 的良好习惯。遇到问题,如果有相关日志可以排查,是最方便的,同时也是最安全,成本最低的一种排查方法。最后,我们可以结合 btrace 和 jdk 自带的 tool 来排查问题,比如 jstack 、 jstat 等等,快速的定位问题。
相关实例说明
AWTEventTracer.java -演示了对EventQueue.dispatchEvent()事件进行trace的做法,可以通过instanceof来对事件进行过滤,比如这里只针对focus事件trace.
AllLines.java -演示了如何在被trace的程序到达probe指定的类和指定的行号时执行指定的操作(例子中指定的行号是-1表示任意行).
AllSync.java -演示了如何在进入/退出同步块进行trace.
ArgArray.java -演示了打印java.io包下所有类的readXXX方法的输入参数.
Classload.java -演示打印成功加载指定类以及堆栈信息.
CommandArg.java -演示如何获取btrace命令行参数.
Deadlock.java -演示了@OnTimer注解和内置deadlock()方法的用法
DTraceInline.java -演示@DTrace注解的用法
DTraceDemoRef.java -演示@DTraceRef注解的用法.
FileTracker.java -演示了如何对File{Input/Output}Stream构造函数中初始化打开文件的读写文件操作进行trace.
FinalizeTracker.java -演示了如何打印一个类所有的属性,这个在调试和故障分析中非常有用.这里的例子是打印FileInputStream类的close() /finalize()方法被调用时的信息.
Histogram.java -演示了统计javax.swing.JComponent在一个应用中被创建了多少次.
HistogramBean.java -同上例,只不过演示了如何与JMX集成,这里的map属性通过使用@Property注解被暴露成一个MBean.
HistoOnEvent.java -同上例,只不过演示了如何在通过按ctrl+c中断当前脚本时打印出创建次数,而不是定时打印.
JdbcQueries.java -演示了聚合(aggregation)功能.关于聚合功能可参考DTrace.
JInfo.java -演示了内置方法printVmArguments(), printProperties()和printEnv()的用法
JMap.java -演示了内置方法dumpHeap()的用法.即将目标应用的堆信息以二进制的形式dump出来
JStack.java -演示了内置方法jstackAll()的用法,即打印所有线程的堆栈信息.
LogTracer.java -演示了如何深入实例方法(Logger.log)并调用内置方法(field() )打印私有属性内容.
MemAlerter.java -演示了使用@OnLowMememory注解监控内存使用情况.即堆内存中的年老代达到指定值时打印出内存信息.
Memory.java -演示每隔4s打印一次内存统计信息.
MultiClass.java -演示了通过使用正则表达式对多个类的多个方法进行trace.
NewComponent.java -使用计数器每隔一段时间检查当前应用中创建java.awt.Component的个数.
OnThrow.java -当抛出异常时,打印出异常堆栈信息.
ProbeExit.java -演示@OnExit注解和内置exit(int)方法的用法
Profiling.java -演示了对profile的支持. //我执行没成功, BTrace内部有异常
Sizeof.java -演示了内置的sizeof方法的使用.
SocketTracker.java -演示了对socket的creation/bind方法的trace.
SocketTracker1.java -同上,只不过使用了@OnProbe.
SysProp.java -演示了使用内置方法获取系统属性,这里是对java.lang.System的getProperty方法进行trace.
SubtypeTracer.java -演示了如何对指定超类的所有子类的指定方法进行trace.
ThreadCounter.java -演示了在脚本中如何使用jvmstat计数器. (jstat -J-Djstat.showUnsupported=true -name btrace.com.sun.btrace.samples.ThreadCounter.count需要这样来从外部通过jstat来访问)
ThreadCounterBean.java -同上,只不过使用了JMX.
ThreadBean.java -演示了对预编译器的使用(并结合了JMX).
ThreadStart.java -演示了脚本中DTrace的用法.
Timers.java -演示了在一个脚本中同时使用多个@OnTimer
URLTracker.java -演示了在每次URL.openConnection成功返回时打印出url.这里也使用了D语言脚本.
WebServiceTracker.java -演示了如何根据注解进行trace.
huanghaifeng1990
浏览: 7293 次
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'最近在看一个开源的Cache框架,里面提到使用JMX来查看Cache的命中率以及响应时间等,于是翻了一些JMX的文章,整理了一下。
问题:什么是JMX?
问题:JMX的架构是什么样子的?
问题:JMX以及Mbean中的 概念都有那些?
问题:如何编写一个简单的Standard MBean?
问题:如何编写一个DynamicMBean?
问题:Open MBean 和Mode MBean是作用是啥?
问题:按照MBean的规范写,是不是有点繁琐,有没有简单点的办法?
问题:什么是JMX?
JMX(java management extensions)java管理程序扩展,是一个为应用程序、设备、系统等植入管理功能的框架。
JMX使用了最简单的一类javaBean,使用有名的MBean,其内部包含了数据信息,这些信息可能是程序配置信息、模块信息、系统信息、统计信息等。MBean可以操作可读可写的属性、直接操作某些函数。
问题:JMX的架构是什么样子的?
问题:JMX使用三层架构,各个层的详细描述是怎么样的?
Probe Level负责资源的检测(获取信息),包含MBeans,通常也叫做Instrumentation Level。
The Agent Level 或者叫做MBean Server,是JMX的核心,连接这个Mbeans和应用程序。
Remote Management Level通过connectors和adaptors来远程操作MBeanServer, Applications可以是大家比较熟悉的控制台,例如JConsole。
JMX以及Mbean中的 概念都有那些?
通常是一个java类,他提供接口,可以是这个类具有管理功能。
Standard Mbean是最简单的MBean,他能管理的资源必须定义在接口中,然后MBean必须实现这个接口,命名必须遵守一定的规范。
MBean interface:
1、名字必须以MBean结尾
2、必须与签名暴漏属性和操作
MBean implement
1、必须有个名字和接口中"MBean"的前缀相同
2、实现接口中的方法
Dynamic Mbean必须实现DynamicMBean,所有的属性和方法都在运行时定义。
1、必须实现DynamicMBean接口
2、在实现类中实现DynamicMBean中的方法
2、MBean Server
管理MBean的一个java类,需要向MBean Server中注册一个MBean之后,这个MBean才会具有管理功能,MBeanServer还提供了查询和注解监听器的功能,不同的JMX实现中MBean Server实现也不同。
3、JMX agent
agent是为了管理一些列的MBean而提供的一系列服务。agent可以利用protocal adapters(例如HTTP)和connectors使不同的客户端可以访问MBean。
问题:如何编写一个简单的Standard MBean?
1、编写MBean的接口:TestMBean.java
定义了属性的get和set方法以及一个操作方法
public interface TestMBean {
public void printHelloWorld();
public String getName();
public void setName(String name);
2、写一个类实现刚才的MBean接口Test.java
public class Test implements TestMBean {
public void printHelloWorld() {
System.out.println(name+",welcome to this world.");
public String getName() {
public void setName(String name) {
this.name =
3、编写一个main函数(将MBean注册到MBeanServer中)Main.java
import java.lang.management.ManagementF
import javax.management.MBeanS
import javax.management.ObjectN
public class Main {
public static void main(String[] args) throws Exception{
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("agent:name=test");
Test testMBean = new Test();
mBeanServer.registerMBean(testMBean, name);
Thread.sleep(5000000);
4、通过JConsole来链接java进程,获取agent信息,通过MBeanServer来操作MBean
问题:如何编写一个DynamicMBean?
1、搞一个类继承DynamicMBean(
TestDynamic.java)
初始化MBeanMeta 信息,包括Attribute和operation
实现Invoke方法
import javax.management.A
import javax.management.AttributeL
import javax.management.AttributeNotFoundE
import javax.management.DynamicMB
import javax.management.InvalidAttributeValueE
import javax.management.MBeanAttributeI
import javax.management.MBeanE
import javax.management.MBeanI
import javax.management.MBeanOperationI
import javax.management.ReflectionE
public class TestDynamic implements DynamicMBean {
private String name = "iamzhongyong";
public String getName() {
public void setName(String name) {
this.name =
public void printName(){
System.out.println(name);
public Object getAttribute(String attribute)
throws AttributeNotFoundException, MBeanException,
ReflectionException {
if(attribute==null){
throw new AttributeNotFoundException();
if("name".equalsIgnoreCase(attribute)){
return getName();
throw new AttributeNotFoundException();
public void setAttribute(Attribute attribute)
throws AttributeNotFoundException, InvalidAttributeValueException,
MBeanException, ReflectionException {
String name = attribute.getName();
Object value = attribute.getValue();
if("name".equalsIgnoreCase(name)){
this.setName(String.valueOf(value));
throw new AttributeNotFoundException();
public AttributeList getAttributes(String[] attributes) {
return null;
public AttributeList setAttributes(AttributeList attributes) {
return null;
public Object invoke(String actionName, Object[] params, String[] signature)
throws MBeanException, ReflectionException {
if("printName".equals(actionName)){
printName();
return null;
public MBeanInfo getMBeanInfo() {
MBeanAttributeInfo[] dAttributes = new MBeanAttributeInfo[] {
new MBeanAttributeInfo("name", "String", "缓存名称", true,
true, false)};
MBeanOperationInfo opers[] = {
new MBeanOperationInfo("printName","print",null,"void",MBeanOperationInfo.ACTION)};
MBeanInfo info = new MBeanInfo(this.getClass().getName(),
"TestDynamic",
dAttributes,
2、main函数编写(注册到MBeanServer中)
import java.lang.management.ManagementF
import javax.management.MBeanS
import javax.management.ObjectN
public class Main {
public static void main(String[] args) throws Exception{
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("agent:name=test");
TestDynamic testMBean = new TestDynamic();
mBeanServer.registerMBean(testMBean, name);
Thread.sleep(5000000);
问题:Open MBean 和Mode MBean是作用是啥?
其实这两类也是动态的MBean,OpenMBean和其他MBean不同之处在于公共接口的返回值有所限制,只能是基本类型或者openmbean包内的类型。(可能主要考虑到远端管理系统,可能不具备MBean接口中的特殊的类)
普通的动态的MBean缺少一些管理系统的支持,例如MBean的状态持久化或者日志记录等,因为JMX厂商提供不同的MobleMBean的实现,方便用户进行操作。
使用pojo-mbean来减少MBean繁琐的操作
问题:按照MBean的规范写,是不是有点繁琐,有没有简单点的办法?
有的,基于POJO-MBean来做JMX,通过注解来实现一些繁琐的步骤,让动态MBean不在那么蛋疼。
pojo-mbean提供了一种基于注解来减少繁琐的MBean的方式()。
pojo-mbean没有依赖任何第三方的包,需要JDK5以上,通过注解标示一个类,是这个类作为MBean,包括属性、操作以及参数等。
版本依赖:
&dependency&
&groupId&org.softee&/groupId&
&artifactId&pojo-mbean&/artifactId&
&version&1.1&/version&
&/dependency&
主要原理:
1、在注册MBeanServer的时候,扫描注解的类文件
2、然后转换MBean的Meta信息,把相关的信息通过反射完成
3、抽象类实现DynamicMBean
实例代码如下:
import org.softee.management.annotation.D
import org.softee.management.annotation.MB
import org.softee.management.annotation.ManagedA
import org.softee.management.annotation.ManagedO
import org.softee.management.annotation.P
import org.softee.management.helper.MBeanR
@MBean(objectName="pojo-agent-test:name=HelloWorld")
@Description("HelloWorld MBean by pojo-mbean")
public class HelloWorld {
private int
@ManagedOperation
@Description("print the name and age")
public void print(){
System.out.println("name="+name+",age="+age);
@ManagedOperation
@Description("increment the age and then return the new age")
public int incrementAge(@Parameter("age")int age){
this.age = this.age+
return this.
@ManagedAttribute @Description("about name")
public String getName() {
@ManagedAttribute
public void setName(String name) {
this.name =
@ManagedAttribute @Description("about age")
public int getAge() {
@ManagedAttribute
public void setAge(int age) {
this.age =
* 把MBean注册到MBeanServer中
* @throws Exception
public void initMBeanServer() throws Exception{
new MBeanRegistration(this).register();
public static void main(String[] args) throws Exception{
HelloWorld a = new HelloWorld();
a.initMBeanServer();
Thread.sleep(500000);
基于此,之后通过MBean来实现一些监控或者管理,就能比较方便了。
参考文章:
你看哪个开源Cache框架,还带有JMX功能?ehcache就有的
iamzhongyong
浏览: 523450 次
来自: 杭州
博主你好。如果groovy的代码是保存在数据库里,不是文件,这 ...
hi,兄弟,有没有兴趣来阿里巴巴专门做这方面的研究,https ...
有2个问题请教:1. 这里的base32算法为什么需要以负数的 ...
不错非常好!推荐一个以电商购物支付流程中,在各大参与者系统中可 ...
&分布式锁&这节里,如果本身“构建唯一索引 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 idea不能运行main方法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信