JMX的一点研究

JMX学习总结

前段时间研究tomcat,发现里面涉及到了好多JMX的内容,那么抽点时间学习研究了一下,总结如下:

1.JMX是什么?

JMX(java ManagementExtensions)java管理扩展,“扩展”顾名思义就是不属于JDK的一部分,只是JDK的扩展。不过这个概念有点过时,JDK1.5以后的版本实现了默认的JMX引擎。也就是现在的JMX已经属于JDK的不可分割的一部分了。Tomcat中应用的JMX如果不额外配置的话,就采用了平台默认的MBeanServer :com.sun.jmx.mbeanserver.JmxMBeanServer.

2.JMX可以干什么?

JMX可以在运行期动态的配置和管理资源,说白了就是不需要重启服务器就可以实现配置的变更。另外一个重要的点就是通过JMX可以动态的跟踪我们的资源的信息。比如要跟踪JVM的内存,线程,类加载状况,cpu使用情况等.现在JMX已经广泛应用于tomcat等诸多服务器软件当中。 Java的自带的Jconsole客户端程序就是一个监控JVM信息的JMX客户端工具。

3.如何将我们的Bean交给JMX管理。

这里不说JMX的体系结构,这些原理性的东西网上一找一堆.我们按照JMX的编写要求来开发几个DEMO(其实也是一找一堆,我找了两个典型的)。

若要使一个java对象成为JMX管理的资源,则必须按照规范创建一些MBean,JMX的MBean类型分为4种:标准类型,动态类型,开放类型,模型类型。创建完MBean将其注册到MBean Server。 本次只研究一下实现最简单的标准MBean和在tomcat中应用的模型MBean,其他的两种MBean用的不多先不研究。

标准MBean的一个DEMO:

Car.java:

public class Car implements CarMBean{

   private String color = "red";

   public String getColor() {

      return color;

   }

   public void setColor(String color){

      this.color = color;

   }

   public void drive() {

      System.out.println("Baby you can drive my car");

   }

}

CarMBean.java:

//标准MBean

public interfaceCarMBean {

 

   public String getColor();

   public void setColor(String color);

   public void drive();

}

 

StandardAgent.java:

public classStandardAgent {

 

   private MBeanServer mBeanServer = null;

  

   public StandardAgent(){

      mBeanServer = MBeanServerFactory.createMBeanServer();

   }

  

   public MBeanServer getMBeanServer(){

      return mBeanServer;

   }

  

   public ObjectNamecreateObjectName(String name) {

     

      ObjectNameobjectName = null;

     

      try {

         objectName= newObjectName(name);

      }catch(MalformedObjectNameException e) {

         e.printStackTrace();

      }catch(NullPointerException e) {

         e.printStackTrace();

      }

      return objectName;

   }

  

   private voidcreateStandardBean(ObjectName objectName,String managedResourceClassName){

     

      try {

         mBeanServer.createMBean(managedResourceClassName,objectName);

      }catch(InstanceAlreadyExistsException e) {

         e.printStackTrace();

      }catch(NotCompliantMBeanException e) {

         e.printStackTrace();

      }catch(MBeanRegistrationException e) {

         e.printStackTrace();

      }catch(ReflectionException e) {

         e.printStackTrace();

      }

   }

  

   public static void main(String[] args){

      StandardAgentagent = newStandardAgent();

      MBeanServermBeanServer = agent.getMBeanServer();

      Stringdomain = mBeanServer.getDefaultDomain();

      StringmanagedResourceClassName = "standard.mbean.Car";

      ObjectNameobjectName = agent.createObjectName(domain+":type="+managedResourceClassName);

      agent.createStandardBean(objectName,managedResourceClassName);

      //这里的Color开头字母必须是大写

      AttributecolorAttribute = newAttribute("Color","blue");

      try {

         mBeanServer.setAttribute(objectName,colorAttribute);

         System.out.println(mBeanServer.getAttribute(objectName,"Color"));

         mBeanServer.invoke(objectName,"drive",null,null);

      }catch(Exception e) {

         e.printStackTrace();

      }

   }

}

运行一下发现还是挺有意思的,Car类已经听StandardAgent的指挥了,开放一个端口通过网页来指挥这辆Car其实更有意思。要通过网页访问这个资源的话,你可以利用com.sun.jdmk.comm.HtmlAdaptorServer

在上面的main函数中加上:

ObjectNameadapterName = newObjectName("CarAgent:name=htmladapter,port=8082");

      HtmlAdaptorServeradapter = newHtmlAdaptorServer();

      server.registerMBean(adapter,adapterName);

    adapter.start();

通过8082端口就可以设置Car的属性了. Ok 继续…

       模型MBean:

       Car.java :

public classCar {

   private String color = "red";

   public Car(){

      System.out.println("Car constructor");

   }

   public String getColor() {

      return color;

   }

   public void setColor(String color){

      this.color = color;

   }

   public void drive() {

      System.out.println("Baby you can drive my car.");

   }

}

Ps: 有没有发现下面这个Car和上面那个Car有什么区别? 没错下面这辆Car就是一个POJO 没有实现或继承任何父类或接口。而上面那个必须实现一个MBean接口,这个也就是标准MBean的一个致命缺陷,即我们要管理某个Bean资源需要更改代码,但是代码有时我们是改不了的。

ModleAgent.java:

public classModelAgent {

 

   private Registry registry;

   private MBeanServer mBeanServer;

  

   public ModelAgent(){

      try {

         registry = createRegistry();

         mBeanServer = Registry.getServer();

      }catch(Exception e) {

         e.printStackTrace(System.out);

         System.exit(1);

      }

   }

  

   public MBeanServergetMBeanServer(){

      return mBeanServer;

   }

  

   public RegistrycreateRegistry(){

     

      try {

         URLurl = ModelAgent.class.getResource("/model/mbean/modeler/api/car-mbean-descriptor.xml");

         InputStreamstream = url.openStream();

         Registry.loadRegistry(stream);

         stream.close();

         return Registry.getRegistry();

      }catch(Exception e) {

         e.printStackTrace();

      }

      return registry;

   }

  

   public ModelMBeancreateModelMBean(String mBeanName) throws Exception{

     

      ManagedBeanmanaged = registry.findManagedBean(mBeanName);

      if(managed == null){

         System.out.println("ManagedBean null");

         return null;

      }

      ModelMBeanmbean = managed.createMBean();

      ObjectNameobjectName = createObjectName();

      return mbean;

   }

  

   private ObjectNamecreateObjectName(){

     

      ObjectNameobjectName = null;

      Stringdomain = mBeanServer.getDefaultDomain();

      try {

         objectName= newObjectName(domain+":type=myCar");

      }catch(Exception e) {

         e.printStackTrace();

      }

      return objectName;

   }

  

   public static void main(String[] args){

      ModelAgentagent = newModelAgent();

      MBeanServermBeanServer = agent.getMBeanServer();

      Carcar = newCar();

      System.out.println("Creating ObjectName");

      ObjectNameobjectName = agent.createObjectName();

      try {

         ModelMBeanmodelMBean = agent.createModelMBean("myMBean");

         modelMBean.setManagedResource(car,"ObjectReference");

         mBeanServer.registerMBean(modelMBean,objectName);

      }catch(Exception e) {

         e.printStackTrace();

      }

      try {

         Attributeattribute = newAttribute("Color","green");

         mBeanServer.setAttribute(objectName,attribute);

         Stringcolor = (String) mBeanServer.getAttribute(objectName, "Color");

         System.out.println("Color:"+color);

         attribute= newAttribute("Color","blue");

         mBeanServer.setAttribute(objectName,attribute);

         color= (String) mBeanServer.getAttribute(objectName, "Color");

         System.out.println("Color:"+color);

         mBeanServer.invoke(objectName,"drive",null,null);

      }catch(Exception e) {

         e.printStackTrace();

      }

   }

}

 

Car-mbean-descriptor.xml:

<mbeans-descriptors>

   <mbean name="myMBean" className="javax.management.modelmbean.RequiredModelMBean"

    description="The ModelMBeanthat manages our Car object"

    type="model.mbean.modeler.api.Car">

      <attribute name="Color" description="The carcolor" type="java.lang.String"/>

      <operation name="drive" description="drivemethod" impact="ACTION"returnType="void">

         <parameter name="driver" description="the driverparameter" type="java.lang.String"/>

      </operation>

      <operation name="setColor" description="The setColor" returnType="void">

         <parameter name="color" description="the setvalue" type="java.lang.String"/>

      </operation>

      <operation name="getColor" description="The setColor" returnType="void"/>

   </mbean>

</mbeans-descriptors>

模型MBean不需要被管理的Bean实现自己的接口,但是有一点必须要做到,就是必须让MBean知道被管理的Bean的特征,比如标准MBean是定义了和原类的一套接口来获取到原来类的行为的。则模型MBean则是通过在xml文件中将被托管的Bean的模型描述出来。这个描述文件就是上面的 那个xml文件。

4. tomcat中JMX的应用:

Tomcat中采用了上文描述的第二种模型MBean:我们可以先搜索一下相关的xml配置文件,看看里面对mbean的描述信息,截图如下:


我们可以看到好多的mbeans-descriptors.xml文件。为什么都叫这个名:其实它们分属不同的包下,并且命名Registry这个类中默认写死了:


Tomcat中定义的而资源是怎么注册到MBeanserver的呢?

记得上次分析tomcat启动过程的时候,在Bootstrap类中看到了如下代码埋点:

还记得Bootstrap包含了三个类加载器,在构造完每个类加载器的时候就直接注册到了MBeanServer当中,好多的资源组建都是这么注册进来的。 例如:


通过调试发现在没有配置MBeanServer的情况下,采用了平台默认的MBeanServer:com.sun.jmx.mbeanserver.JmxMBeanServer. 上面那个ManagementFactory其实维护了一个统一的单例的 MBeanServer,保证我们的资源都在一个MBeanServer当中。

 

可见这个工厂里维护一个静态的MBeanServer成员。在其他地方注册时候获取的同样是同一个MBeanServer资源。

除了在代码中主动的向MBeanServer服务器注册一些资源外,在tomcat启动的时候还会根据事件的触发去加载注册一些MBean资源,同理在关闭的时候也会卸载这些资源. 具体的实现是这样的:在tomcat的基础配置 server.xml中维护了这么个监听器:

看注释可以看出来,这两个监听器是专门用来为JMX提供支持:

这两个监听器主要是在启动、关闭事件发生是去触发注册MBean的操作。


5.监控指定tomcat服务器中JVM的信息:

因为tomcat支持了JMX的规范,所以我们就可以通过JConsole监控上面的JVM状态,首先在tomcat启动的时候设置启动参数如下:

-Dcom.sun.management.jmxremote.port=9999

-Dcom.sun.management.jmxremote.ssl="false"

-Dcom.sun.management.jmxremote.authenticate="false"

        然后在打开我们的JConsole:指定远程的机器地址和端口号


然后就连上来了。


  6: SecurityManager :

       SecurityManager和上面说的没什么关系了,但是在看tomcat源码的时候发现好多地方都涉及了这段代码:


       这个是在干嘛呢?原来他在找看看是否有设置了安全管理器,其实java是自己内置了一个SecurityManager的,只是开关没有打开,在启动的时候默认加上这个参数-Djava.security.manager就打开了默认的SecurityManager,打开这个的话java在加载一些class的时候就会查找一个授权文件,看看是否允许:这个授权文件的路径是:jdk1.6.0_10\jre\lib\security\java.policy


里面定义类似上图。当然我们也可以自己定义SecurityManager,自己定义SecurityManager的话只需要继承一个SecurityManager类然在代码中设置一下即可:


类签名:


SecurityManager就不多说了,必经主要先看下JMX嘛!

Ps:以上就是从应用层面学习了一下JMX,本来是想从源码层面解读一下,发现这里面的东西还是挺复杂的,有时间在读它的源码了。还有一个问题抛出来,本来是想用本机的jconsole连接一下daily服务器的,发现已经配置了jmx远程连接端口,但是这个端口用jconsole连接不上(当然线上不能随便连接哈)。有点想不明白,为什么呢,ping都ping不通,不知为什么?有知道的请多多指教吧。


 

 

 

 

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值