Mbean

Mbean

名词解释

  1. Mbean
    managed beans 被管理的bean
    描述一个可管理的资源。
    是一个Java对象,遵循以下一些语义:
    java对象的属性(property)叫属性(attribute),方法(method)叫操作(operations)。

    • Mbean的定义:
      必须:是公用的,非抽象的类
      必须:有至少一个公用的构造器
      必须:实现它自己的相应的MBean接口或者实现 javax.management.DynamicMBean 接口
      可选:一个MBean可以实现 javax.management.NotificationBroadcaster 接口
    • Mbean的类型
      标准MBean
      动态MBean
      模型MBean
      开放MBean
    • Mbean的使用步骤
      1)注册Mbean
      一个MBeanServer的主要职责是在一个JMX代理中维护一个MBean的注册表。
      MBean能够以下面两个方法中的任意一个注册:
      <1>创建一个MBean实例并注册它到MBeanServer用方法:

      public ObjectInstance registerMBean(Object object, ObjectName name)   
      

      这里,object是创建的MBean实例,name部分是MBean的一个唯一标志符。
      <2>使用createMBean 方法中的一个:

      public ObjectInstance createMBean(String classname, ObjectName name) 
      public ObjectInstance createMBean(String classname, ObjectName name, ObjectName loader) 
      public ObjectInstance createMBean(String classname, ObjectName name, Object[] params, String[] types) 
      public ObjectInstance createMBean(String classname, ObjectName name, ObjectName loader, Object[] params, String[] types) 
      

      createMBean方法使用java自省来创建一个MBean实例。对所有的createMBean方法,有两个变量是通用的:
      String classname – 要创建的MBean的实例的类名。
      ObjectName name – MBean要注册的对象名称。
      如果用两个变量的createMBean构造器,缺省的类装载器(class loader)用来装载MBean类,MBean被使用缺省的构造器初始化。如果MBean已经被初始化,这个实例将被MBeanServer用第二个变量的对象名称注册。如果你想使用指定的类装载器,那么可以使用三个变量的构造器。这个类装载器将被MBeanServer注册为一个MBean。这个类装载器的对象名称将用做第三个变量。
      当实例化一个类,如果任何参数必须传入,那么可以使用四个参数的createMBean方法。这个createMBean方法的最后的两个参数分别包含对象数组(类的初始化必须的)和他们的署名。如果MBean类必须用其他指定的类装载器装载,那么应该使用五个参数的构造器。
      2)注册一个MBean的多个实例
      你可能需要监控十多个Web 服务器。如果所有的web服务器的管理信息是相同的,那么你不必编写十个MBean。一个MBean足够了。我们能够创建多个实例并注册每一个实例以一个唯一的对象名称。
      现在可以看到使用对象名称来避免混淆的重要性。
      很明显服务器的端口数字和服务器的名称将是任意服务器的唯一,那是因为,在一个机器上,你不能运行两个服务器在一个端口上。
      于是,可以创建对象名称如
      Servers:hostName=localhost,portNumber=xxxx
      假设超过一个服务器在同一个机器上启动,那么对象名称应该为
      Servers:hostName=localhost,portNumber=yyyy
      由于对象名称是注册MBean的唯一标志,多个MBean的实例将被注册为不同的对象名称。
      对象名称通常用他们包含的关键值对来区分,如一个服务器MBean的主机名和端口名关键字及他们各自的值。同理,唯一标志相似的MBean组,对象名称将用相应的关键字和值对拼装。例如,type=ServerMBean指出这个MBean是一个服务器MBean类型。由此,对象名称值Server:type=ServerMBean,hostName=localhost,portNumber=8050 提供一个简单的MBean分组,产生为服务器MBean的实现。并且也提供了一个方法来唯一标志在localhost:8050上运行的服务器的MBean实例。
      一个简单的示范
      让提供管理信息(所有web服务器通用的)的Mbean为动态MBean,并且起名为ServerInfo。
      让两个web服务器运行在机器A(machineA)的端口8080和80。让一个web服务器运行在机器B(machineB)的8080端口,另一个web服务器运行在机器C(machineC)的80端口。总之,我们需要管理这四个web服务器。我们能够用ServerInfo 类和创建四个实例来管理每一个web服务器。注册四个MBean的代码片断如下:

      ServerInfo srvr1 = new ServerInfo(); 
      ServerInfo srvr2 = new ServerInfo(); 
      ServerInfo srvr3 = new ServerInfo(); 
      ServerInfo srvr4 = new ServerInfo();
      MBeanServer mbs = null;
      try { 
          mbs = MBeanServerFactory.createMBeanServer( ); 
          mbs.registerMBean(srvr1, new ObjectName("Server:hostName=machineA,portNumber=8080")); 
          mbs.registerMBean(srvr2, new ObjectName("Server:hostName=machineA,portNumber=80")); 
          mbs.registerMBean(srvr3, new ObjectName("Server:hostName=machineB,portNumber=8080")); 
          mbs.registerMBean(srvr4, new ObjectName("Server:hostName=machineC,portNumber=80")); 
      } catch (Exception e) {
       e.printStackTrace(); 
      }
      

      3)注销MBean
      MBean能够用MBeanServer的下面方法注销:

      public void unregisterMBean(ObjectName name) 
      

      这里name是这个MBean实例注册的对象名称。
      注销MBean后,MBeanServer将不再保存任何这个MBean实例的关联。
      控制MBeanRegistration
      JMX定义了一个接口叫MBeanRegistration。这个接口的目的是允许MBean开发者对在MBeanServer上注册和注销进行一些控制。这通过MBean实现javax.management.MBeanRegistration接口来达到。
      MBeanRegistration接口定义注册控制机制的行为。它定义了以下四个方法:

      public ObjectName preRegister(MBeanServer mbs, ObjectName name) 
      public void postRegister() 
      public void preDeRegister() 
      public void postDeRegister()
      

      所有以上的方法都是回调方法,MBeanServer将在恰当的时机调用这些方法。
      如果一个MBean实现MBeanRegistration并且这个MBean被注册,MBeanServer在注册前调用preRegister方法。这个方法返回的对象名称将在MBean注册过程中使用。在成功完成MBean注册后,MBeanServer调用postRegister方法。
      如果以上的MBean被注销,在注销前MBeanServer调用preDeRegister方法。如果注销成功,MBeanServer调用postDeRegister方法。
      需要记住的几点
      对于一个单一MBean类,多个实例能够被创建,并能够被注册为注册时MBean提供的对象名称。
      无论何时一个MBean被注册,MBeanServer创建一个类型为 jmx.mbean.created 的消息。MBeanServerDelegate MBean 广播这个消息到所有注册的监听者。
      MBeanRegistration接口提供注册和注销过程监控的钩点。

  2. JMX

    • 知识简介
      JMX(Java Management Extensions,即Java管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架。JMX可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。
      JMX在Java编程语言中定义了应用程序以及网络管理和监控的体系结构、设计模式、应用程序接口以及服务。通常使用JMX来监控系统的运行状态或管理系统的某些方面,比如清空缓存、重新加载配置文件等。
      优点是可以非常容易的使应用程序被管理
      伸缩性的架构使每个JMX Agent服务可以很容易的放入到Agent中,每个JMX的实现都提供几个核心的Agent服务,你也可以自己编写服务,服务可以很容易的部署,取消部署。
      主要作用是提供接口,允许有不同的实现 。
    • JMX架构分层
      JMX体系结构分为以下四个层次:
      设备层
      设备层(Instrumentation Level):主要定义了信息模型。在JMX中,各种管理对象以管理构件的形式存在,需要管理时,向MBean服务器进行注册。该层还定义了通知机制以及一些辅助元数据类。
      代理层
      代理层(Agent Level):主要定义了各种服务以及通信模型。该层的核心是一个MBean服务器,所有的管理构件都需要向它注册,才能被管理。注册在MBean服务器上管理构件并不直接和远程应用程序进行通信,它们通过协议适配器和连接器进行通信。而协议适配器和连接器也以管理构件的形式向MBean服务器注册才能提供相应的服务。
      分布服务层
      分布服务层(Distributed Service Level):主要定义了能对代理层进行操作的管理接口和构件,这样管理者就可以操作代理。然而,当前的JMX规范并没有给出这一层的具体规范。
      附加管理协议API
      定义的API主要用来支持当前已经存在的网络管理协议,如SNMP、TMN、CIM/WBEM等。
  3. Spring中对Mbean的支持
    Spring中提供了MbeanExporter,将Spring bean的属性和方法导出为MBean服务器中的JMX属性和操作。通过JMX服务器,JMX管理工具(例如JConsole)可以查看到正在运行的应用程序的内部情况。
    Spring的MbeanExporter使用方法如下

    //args为将要导出的bean对象
    @Bean  
    public MbeanExporter mbeanExporter(Object args) {
        MbeanExporter exporter = new MbeanExporter();
        Map<String, Object> beans = new HashMap<>();
        beans.put("ObjectName", args);
        exporter.setBeans(beans);
        return exporter;
    }
    

    另外一种XML配置的方法

    <bean id="mbeanExporter" class="org.springframework.jmx.export.MBeanExporter">  
        <property name="beans">  
            <util:map>  
                <!-- 这里的value-ref都为之前定义的bean的id -->
                <entry key="bean:name=requestRule" value-ref="requestRule"/>  
                <entry key="bean:name=responseRule" value-ref="responseRule"/> 
            </util:map>  
        </property>  
    </bean>
    

    对MbeanExporter代码的阅读,本文中只摘取部分说明
    MebanExporter.java

    public class MBeanExporter extends MBeanRegistrationSupport
      implements MBeanExportOperations, BeanClassLoaderAware, 
      BeanFactoryAware, InitializingBean, SmartInitializingSingleton, DisposableBean{
        public static final int AUTODETECT_NONE = 0;
        public static final int AUTODETECT_MBEAN = 1;
        public static final int AUTODETECT_ASSEMBLER = 2;
        public static final int AUTODETECT_ALL = 3;
        private static final String WILDCARD = "*";
        private static final String MR_TYPE_OBJECT_REFERENCE = "ObjectReference";
        private static final String CONSTANT_PREFIX_AUTODETECT = "AUTODETECT_";
        private static final Constants constants = new Constants(MBeanExporter.class);
        private Map<String, Object> beans;
        private Integer autodetectMode;
        private boolean allowEagerInit;
        private MBeanInfoAssembler assembler;
        private ObjectNamingStrategy namingStrategy;
        private boolean ensureUniqueRuntimeObjectNames;
        private boolean exposeManagedResourceClassLoader;
        private Set<String> excludedBeans;
        private MBeanExporterListener[] listeners;
        private NotificationListenerBean[] notificationListeners;
        private final Map<NotificationListenerBean, ObjectName[]> registeredNotificationListeners;
        private ClassLoader beanClassLoader;
        private ListableBeanFactory beanFactory;
    
        ......
        ......
    
        //随容器启动而启动
        public void afterPropertiesSet() {
            //获取到MbeanServer
            if (this.server == null)
              this.server = JmxUtils.locateMBeanServer();
        }
    
        public void destroy() {
            this.logger.info("Unregistering JMX-exposed beans on shutdown");
            unregisterNotificationListeners();
            unregisterBeans();
        }
    
        public ObjectName registerManagedResource(Object managedResource)
            throws MBeanExportException  {
            Assert.notNull(managedResource, "Managed resource must not be null");
            try {
              ObjectName objectName = getObjectName(managedResource, null);
              if (this.ensureUniqueRuntimeObjectNames)
                objectName = JmxUtils.appendIdentityToObjectName(objectName, managedResource);
            } catch (Exception ex) {
              throw new MBeanExportException("Unable to generate ObjectName for MBean [" + managedResource + "]", ex);
            }
            ObjectName objectName;
            registerManagedResource(managedResource, objectName);
            return objectName;
        }
    
        public void registerManagedResource(Object managedResource, ObjectName objectName) throws MBeanExportException {
            Assert.notNull(managedResource, "Managed resource must not be null");
            Assert.notNull(objectName, "ObjectName must not be null");
            try {
                if (isMBean(managedResource.getClass())) {
                    doRegister(managedResource, objectName);
                } else {
                    ModelMBean mbean = createAndConfigureMBean(managedResource, managedResource.getClass().getName());
                    doRegister(mbean, objectName);
                    injectNotificationPublisherIfNecessary(managedResource, mbean, objectName);
                }
            } catch (JMException ex) {
                throw new UnableToRegisterMBeanException("Unable to register MBean [" + managedResource + "] with object name [" + objectName + "]", ex);
            }
        }
    
        public void unregisterManagedResource(ObjectName objectName) {
            Assert.notNull(objectName, "ObjectName must not be null");
            doUnregister(objectName);
        }
    
        protected void registerBeans() {
            if (this.beans == null) {
                this.beans = new HashMap();
                if (this.autodetectMode == null) {
                    this.autodetectMode = Integer.valueOf(3);
                }
            }
            int mode = (this.autodetectMode != null) ? this.autodetectMode.intValue() : 0;
            if (mode != 0) {
                if (this.beanFactory == null) {
                    throw new MBeanExportException("Cannot autodetect MBeans if not running in a BeanFactory");
                }
                if ((mode == 1) || (mode == 3)) {
                    this.logger.debug("Autodetecting user-defined JMX MBeans");
                    autodetectMBeans();
                }
                if ((((mode == 2) || (mode == 3))) && (this.assembler instanceof AutodetectCapableMBeanInfoAssembler)) {
                    autodetectBeans((AutodetectCapableMBeanInfoAssembler)this.assembler);
                }
            }
            if (!(this.beans.isEmpty()))
                for (Map.Entry entry : this.beans.entrySet())
                    registerBeanNameOrInstance(entry.getValue(), (String)entry.getKey());
        }
    
        protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey)
        throws MBeanExportException {
            try {
                Object bean;
                if (mapValue instanceof String) {
                    if (this.beanFactory == null) {
                        throw new MBeanExportException("Cannot resolve bean names if not running in a BeanFactory");
                    }
                    String beanName = (String)mapValue;
                    if (isBeanDefinitionLazyInit(this.beanFactory, beanName)) {
                        ObjectName objectName = registerLazyInit(beanName, beanKey);
                        replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
                        return objectName;
                    }
    
                    bean = this.beanFactory.getBean(beanName);
                    ObjectName objectName = registerBeanInstance(bean, beanKey);
                    replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
                    return objectName;
                }
    
                if (this.beanFactory != null) {
                    Map beansOfSameType = this.beanFactory.getBeansOfType(mapValue.getClass(),false, this.allowEagerInit);
                    for (Map.Entry entry : beansOfSameType.entrySet()) {
                        if (entry.getValue() == mapValue) {
                            String beanName = (String)entry.getKey();
                            ObjectName objectName = registerBeanInstance(mapValue, beanKey);
                            replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
                            return objectName;
                        }
                    }
                }
                return registerBeanInstance(mapValue, beanKey);
            } catch (Exception ex) {
                throw new UnableToRegisterMBeanException("Unable to register MBean [" + mapValue + "] with key '" + beanKey + "'", ex);
            }
        }
    
        private ObjectName registerBeanInstance(Object bean, String beanKey) throws JMException {
            ObjectName objectName = getObjectName(bean, beanKey);
            Object mbeanToExpose = null;
            if (isMBean(bean.getClass())) {
                mbeanToExpose = bean;
            } else {
                DynamicMBean adaptedBean = adaptMBeanIfPossible(bean);
                if (adaptedBean != null) {
                    mbeanToExpose = adaptedBean;
                }
            }
            if (mbeanToExpose != null) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Located MBean '" + beanKey + "': registering with JMX server as MBean [" + objectName + "]");
                }
    
                doRegister(mbeanToExpose, objectName);
            } else {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Located managed bean '" + beanKey + "': registering with JMX server as MBean [" + objectName + "]");
                }
    
                ModelMBean mbean = createAndConfigureMBean(bean, beanKey);
                doRegister(mbean, objectName);
                injectNotificationPublisherIfNecessary(bean, mbean, objectName);
            }
            return objectName;
        }
        ......
        ......
    
    }
    

    MbeanRegistrationSupport.java(部分代码段)

    protected void doRegister(Object mbean, ObjectName objectName) throws JMException {
        ObjectName actualObjectName;
        synchronized (this.registeredBeans) {
            ObjectInstance registeredBean = null;
            try {
                registeredBean = this.server.registerMBean(mbean, objectName);
            } catch (InstanceAlreadyExistsException ex) {
                if (this.registrationPolicy == RegistrationPolicy.IGNORE_EXISTING) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Ignoring existing MBean at [" + objectName + "]");
                    }
                } else if (this.registrationPolicy == RegistrationPolicy.REPLACE_EXISTING) {
                    try {
                        if (this.logger.isDebugEnabled()) {
                            this.logger.debug("Replacing existing MBean at [" + objectName + "]");
                        }
                        this.server.unregisterMBean(objectName);
                        registeredBean = this.server.registerMBean(mbean, objectName);
                    } catch (InstanceNotFoundException ex2) {
                        this.logger.error("Unable to replace existing MBean at [" + objectName + "]", ex2);
                        throw ex;
                    }
                } else {
                    throw ex;
                }
            }
    
            actualObjectName = (registeredBean != null) ? registeredBean.getObjectName() : null;
            if (actualObjectName == null) {
                actualObjectName = objectName;
            }
            this.registeredBeans.add(actualObjectName);
        }
        onRegister(actualObjectName, mbean);
    }
    

    研究源码得出:Spring的MbeanExporter中声明了一个beans(类型为map)用来保存将要被导出到Mbean的对象,底层是使用MbeanServer的registerMBean方法实现。
    对于Spring中Mbean的一些具体操作,会在后续章节详述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值