首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

15.5  GlassFish对JMX的应用

GlassFish中的管理架构是基于JMX技术来构建的。无论是命令行工具还是管理控制台,都是通过服务器端的MBean来完成管理功能或相应的服务。

15.5.1  GlassFish中的MBean

因为GlassFish对JMX标准提供完全支持,通过JDK附带的JMX管理应用工具JConsole可以地看到GlassFish中的MBean。

【例15.6】查看GlassFish中的MBean。

在本机启动GlassFish,运行JConsole。选择“远程进程”,并在输入框中填写localhost:8686或service:jmx:rmi:///jndi/rmi://hostname:8686/jmxrmi,用户名为admin,口令为adminadmin,如图15-13所示。

图15-13  从JConsole登录GlassFish

登录后,JConsole以树形结构显示了GlassFish上运行的MBean,树的层次是依据MBean的ObjectName解析出来的。比如对象名为amx:J2EEServer=server, j2eeType=JDBCResource, name=jdbc/__TimerPool的MBean,在树中的位置就是amx→JDBCResource→jdbc/__TimerPool,如图15-14所示。

GlassFish对JMX的实现构建在Java EE 5的标准之一JSR-77的基础上。GlassFish中的MBean分为5类,如表15-2所示。

在表15-2中,除了User MBean是用户自行开发的MBean外,其他四类MBean均为系统自带的MBean,这四类MBean又可以被分为两种:JMX MBean和AMX MBean。其中,JMX MBean是指标准的JMX MBean,包括Configuration、Monitor和JSR-77三类MBean,只供内部使用。AMX(AppServer Management Extensions) MBean是GlassFish特有的MBean,除了具备JMX标准MBean的特性外,还有自身独到的特点。GlassFish对JMX所做的扩充集中体现在AMX技术上。AMX MBean封装了系统的JMX MBean,以方便被管理应用的以面向对象的方式的调用,因此也被称作其他MBean的门面(Facade)。下面具体对AMX加以介绍。

图15-14  JConsle显示的GlassFish中的MBean

表15-2  MBean的分类

类  型

对象名

说  明

Configuration

前缀com.sun.appserv

含有标识category=config

用来读写和创建domain.xml中定义的配置,相关接口以Config结尾。都为Model MBean

Monitoring

前缀com.sun.appserv

含有标识category=monitor

用来统计监控数据,相关接口以Monitor结尾。都为动态MBean

JSR-77

前缀com.sun.appserv

含有标识category=runtime

封装JSR-77规范中定义的对象,不可直接调用,只能通过MEJB访问。都为Model MBean

AMX

前缀amx

仅有的公用MBean,封装各类JMX MBean

User

前缀user

用户自定义的MBean

15.5.2  AMX概述

AMX技术是对JMX的扩充,其主要目的是使MBean的应用更加方便和面向对象。AMX将GlassFish服务器端的MBean重新封装,并在客户端映射成对等的代理,称为动态客户端代理(Dynamic Client-side Proxy,DCP)。通过DCP,可以以面向对象的方式开发JMX管理应用。

AMX技术在GlassFish中被广泛地应用在以下两个方面。

(1)   服务器端配置修改,比如部署应用,增删JDBC对象等。

(2)   监控运行实例的状态。

AMX所带来的好处如下:

l   以面向对象的方法来操作远程的MBean。DCP屏蔽了远程访问的细节和JMX的实现,使得对服务器端MBean的访问如同访问一个本地的对象。

l   良好设计的层次结构并有一致的对象名命名规则与之对应。这使得AMX MBean便于查询和以通用的方式被访问。AMX对Java EE 5中各类可管理对象的封装与规范JSR-77中的定义完全对应。

l   更全面系统的约定。这种约定体现在数据类型、命名方法、参数、返回值和事件等方面。

l   一致并且结构化的配置管理。AMX封装了GlassFish的各类配置,封装后的接口类名放置在domain.xml文件中。

15.5.3  动态客户代理(Dynamic Client Proxy)

AMX支持以两种方式来访问服务器端的MBean:标准的JMX方式(通过MBeanServer- Connection)和 GlassFish所特有的DCP方式访问。

DCP方式充分体现了AMX的优点,即更加方便和面向对象。DCP方式借助于客户端的一套预定义的组件,这套组件保存了MBean的ObjectName和MBeanServerConnection,并实现了AMX相关接口定义的属性和方法。通过这套组件,避免了标准JMX方法繁琐的关于MBean调用方法名、输入参数和返回参数的说明,而是如同调用本地对象一样直接调用MBean接口。查看如表15-3所示的DCP所实现的AMX接口和JMX标准的MBeanInfo,对此会有更深刻的认识。

表15-3  AMX和MBeanInfo的比较

AMX Interface代理模式

MBeanInfo模式

Set getContaineeJ2EETypes();
Map getMultiContaineeMap(...);
Map getContaineeMap(...);
AMX getSingletonContainee(...);
Set getContaineeSet(...);
Set getContaineeSet( );
Set getContaineeSet(...);
Set getByNameContaineeSet(...);
AMX getContainee(...);

AbcConfig createAbcConfig(...);

Abc getAbc();

Set getContaineeJ2EETypes();
Map getMultiContaineeObjectNameMap(...);
Map getContaineeObjectNameMap(...);
ObjectName getSingletonContaineeObjectName(...);
Set getContaineeObjectNameSet(...);
Set getContaineeObjectNameSet( );
Set getContaineeObjectNameSet(...);
Set getByNameContaineeObjectNameSet(...);
ObjectName getContaineeObjectName(...);

ObjectName createAbcConfig(...);

ObjectName getAbcObjectName();

注:表中ABC表示某个具体类。

与JMX的标准实现相比,DCP的代码更加简单直观,此外DCP还可以缓存部分对象以提高效率。DCP将缓存不常变化的MBeanInfo和其他一些不常变化的属性,比如ContainerObjectName、InterfaceName、FullType、Group和Name,但对于属于Configuration和Monitoring的MBean,由于其MBeanInfo中的属性会根据配置和监控的状态经常变化,通常不被缓存。

运用了DCP技术的客户端实例可以以面向对象的方式访问服务器端的AMX MBean,同时,通过Extra的接口,AMX实例也可以访问到服务器端标准JMX MBean的特性。Extra不是标准的JMX特性,它是AMX MBean所特有的。从AMX实例中得到JMX标准所支持的连接可以通过以下代码进行:

final MBeanServerConnection conn =

Util.getExtra(amx).getConnectionSource().getMBeanServerConnection();

下面是DCP应用实例。它通过连接AppserverConnectionSource,访问到docroot,再由docroot访问到其他的DCP对象。

【例15.7】DCP应用:

package amxsamples;

import com.sun.appserv.management.DomainRoot;

import com.sun.appserv.management.client.AppserverConnectionSource;

import com.sun.appserv.management.config.DomainConfig;

import com.sun.appserv.management.util.misc.ExceptionUtil;

import com.sun.appserv.management.util.misc.StringUtil;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.net.ConnectException;

import java.util.Map;

import java.util.Properties;

public final class SampleMain {

    private final DomainRoot mDomainRoot;

    public SampleMain() throws IOException {

        final Properties props = getConnectProperties(

"SampleMain.properties");

        //Domain Admin Server的机器名或IP地址

        final String host = props.getProperty(

"connect.host", "localhost");

        //RMI管理端口,默认8686。注意这里不是连接到管理控制台的端口4848或4849

        final int port = Integer.parseInt(props.getProperty(

"connect.port", "8686"));

        //管理员名

        final String user = props.getProperty("connect.user", "admin");

        // 管理员密码

        final String password = props.getProperty(

"connect.password", "adminadmin");

        AppserverConnectionSource conn = null;

        try {

            final String info = "host=" + host + ", port=" + port

                    +", user=" + user + ", password=" + password;

            System.out.println("Connecting...:" + info);

            //用默认的协议RMI

conn = new AppserverConnectionSource(

AppserverConnectionSource.PROTOCOL_RMI,

                    host, port, user, password, null, null);

            // 强制连接

            conn.getJMXConnector(false);

        } catch(Throwable t) {

//AMX通过ExceptionUtil的方法getRootCause(e),来简化和统一进行错误处理

            final Throwable rootCause = ExceptionUtil.getRootCause(t);

            System.out.println("Caught " + rootCause.getClass().getName());

        }

       

        assert conn != null : "不能连接到服务器";

        mDomainRoot  = conn.getDomainRoot();

        handleList();

    }

   

    public static void main(final String[] args) {

        try {

            new SampleMain();

        } catch(final Throwable t) {

            final Throwable rootCause = ExceptionUtil.getRootCause(t);

            if (rootCause instanceof ConnectException) {

                System.out.println("不能连接到指定的机器名和端口");

            } else {

                rootCause.printStackTrace();

            }

        }

    }

   

    /**

     * 得到已部署的各类应用并显示

     */

    public void handleList() {

        final DomainConfig dcp = mDomainRoot.getDomainConfig();

        System.out.println("\n--- 已部署的组件--- \n");

        displayMap("J2EEApplicationConfig",

dcp.getJ2EEApplicationConfigMap());

        displayMap("EJBModuleConfig", dcp.getEJBModuleConfigMap());

        displayMap("WebModuleConfig", dcp.getWebModuleConfigMap());

        displayMap("RARModuleConfig", dcp.getRARModuleConfigMap());

        displayMap("AppClientModuleConfig",

dcp.getAppClientModuleConfigMap());

        displayMap("LifecycleModuleConfig",

dcp.getLifecycleModuleConfigMap());

    }

   

    /**

     * 在System.out上打印输出Map对象

     */

    private void displayMap(final String msg, final Map<?, ?> m){

        System.out.println(msg + ": " +  m.keySet());

    }

    /**

     * 从文件中读取properties

     */

    private final Properties getConnectProperties(final String file)

    throws IOException {

        final Properties props = new Properties();

        if (file != null) {

System.out.println("Reading properties from: " +

StringUtil.quote(file));

            final File f  = new File(file);

            System.out.println("file:"+f.getAbsolutePath());

            if (f.exists()) {

                final FileInputStream is = new FileInputStream(f);

                try {

                    props.load(is);

                } finally {

                    is.close();

                }

            } else {

                System.out.println("File \"" + file +

" does not exist, using defaults." );

            }

        }

        return(props);

    }

}

15.5.4  AMX对JMX的扩展

除了通过DCP以面向对象的方式访问AMX MBean外,AMX还对JMX的其他方面进行了扩展。这其中包括JMX的Notifications模型和Dotted Name支持。

1. JMX Notifications扩展

沿用JMX定义的Notifications模型。对于一些特定的应用,AMX利用了UserData来存放Notification的用户数据。UserData是一个java.util.Map结构,这个结构维护着一个Key-Value列表,其中每个key是由每个发出Notification的AMX接口来定义的。com.sun.appserv.management.Util提供了以下方法来访问Notification中的用户数据:

Map<String, Serializable> getAMXNotificationData(Notification notif);

Serializable getAMXNotificationValue(Notification notif, String key);

<T extends Serializable> T getAMXNotificationValue(Notification notif,  String key, Class<T> theClass);

2. Dotted Name支持

Dotted Name是GlassFish命令行工具asadmin定义的一套约定。AMX全面支持Dotted Names约定,并将Dotted Names当成MBean的属性来处理。在这套约定的支持下,asadmin的三个子命令(list、set和get )可以通过一个由“.”分隔的字串寻址到GlassFish中的MBean。Dotted Name分为三部分,如下所示:

dotted-name = scope-name '.' [ path '.' ]value-name

其中,第一部分scope-name是对组件的分类。它的值只能是“server”、“server-config”或“domain”。

第二部分映射着组件所对应MBean的ObjectName。具体的映射是由一个叫DottedNameRegistry的MBean来实现的。

第三部分是关于组件的属性。

【例15.8】Dotted Name的使用。

要查看所有属于server的组件,可以键入命令:

asadmin> list server.*

server.admin-service

server.admin-service.das-config

server.admin-service.jmx-connector.system

server.application-ref.EventAction

server.application-ref.JBIFramework

server.application-ref.MEjbApp

server.application-ref.WSTCPConnectorLCModule

server.application-ref.WSTXServices

...

可以看到server中组件以Dotted Name形式被列举出来。另外,可以借助Dotted Name来定位某个组件。比如,要查看的组件server.resources.jdbc-connection-pool.DerbyPool的属性,可以键入命令:

asadmin> get server.resources.jdbc-connection-pool.DerbyPool.*

server.resources.jdbc-connection-pool.DerbyPool

.allow-non-component-callers = false

server.resources.jdbc-connection-pool.DerbyPool

.associate-with-thread = false

server.resources.jdbc-connection-pool.DerbyPool

.connection-creation-retry-attempts = 0

server.resources.jdbc-connection-pool.DerbyPool

.connection-creation-retry-interval-in-seconds = 10

server.resources.jdbc-connection-pool.DerbyPool

.connection-leak-reclaim = false

server.resources.jdbc-connection-pool.DerbyPool

.connection-leak-timeout-in-seconds = 0

server.resources.jdbc-connection-pool.DerbyPool

.connection-validation-method = auto-commit

AMX还提供了ConfigDottedNames和MonitoringDottedNames接口,这样所有的Configuration和Monitoring类型的AMX MBean也都可以通过Dotted Name被访问到。

15.5.5  AMX实现

下面将从GlassFish的源代码的角度说明其对AMX的实现。

1. AMX接口和实现的物理分布

AMX的实现类主要来自com.sun.enterprise.management包或其子包,AMX的接口类主要来自com.sun.appserv.management包或其子包。为简单起见,后面对AMX的类名引用省略了其共同前缀的包名。比如,support.AMXImplBase表示的是类com.sun.enterprise.management. support.AMXImplBase。关于GlassFish中AMX的具体接口和实现分布说明参见表15-4。

表15-4  GlassFish源代码中AMX的接口和实现分布

想了解

请查看

JMX MBean的相关接口

包com.sun.enterprise.admin.mbeanapi

JMX MBean的相关实现

包com.sun.enterprise.admin

AMX MBean的相关接口

包com.sun.appserv.management,项目admin-core/mbeanapi

AMX MBean的相关实现

包com.sun.enterprise.management,项目admin/mbeanapi-impl

Configuration MBean的持久性实现

文件admin-mbeans-descriptors.xml

JSR-77 MBean的持久性实现

文件runtime-mbeans-descriptors.xml

User MBean的持久性实现

文件domain.xml

其中,关于MBean持久性的实现是结合几个XML文件的设置来完成的。相关代码列举如下。

(1)   文件admin-mbeans-descriptors.xml中关于JDBC-resource MBean的设置:

<mbean name="jdbc-resource" group="config" >

   <descriptor>

      <field name="elementChangeEvent" value="ResourceDeployEvent" />

<field name="ObjectName" value="{0}:type=jdbc-resource, jndi-name={1},

category=config" />

<field name="xpath"

value="/domain/resources/jdbc-resource[@jndi-name='{1}']" />

      <field name="CLIName" value="domain.resources.jdbc-resource.{1}" />

   </descriptor>

</mbean>

(2)   文件runtime-mbeans-descriptors.xml中关于JSR-77 MBean的JDBC-resource设置:

<mbean name="JDBCResource" group="runtime">

    <descriptor>

        <field name="ObjectName" value="{0}:j2eeType=JDBCResource, name={2},

J2EEServer={1}, category=runtime"/>

    </descriptor>

</mbean>

2. AMX接口和实现的相关类图

GlassFish通过一系列接口和实现类来实现AMX。图15-15和图15-16分别以JDBCResource为例说明了AMX接口和实现的相关类图。

图15-15  AMX的JDBCResource MBean相关接口的类图

图15-16  AMX的JDBCResource MBean相关实现的类图

对图15-15和图15-16中的主要接口介绍如下。

(1)   AMX接口是所有AMX借以扩展的最基本接口。其关键方法说明如表15-5所示。

表15-5  AMX接口说明

方法名

说  明

getName()

返回AMX对象名,即ObjectName中的name属性值

getJ2EEType()

返回对象的j2eeType,即ObjectName中的j2eeType属性值。有着相同j2eeType的AMX对象实现了相同的接口

getContainer()

返回AMX容器。除了DomainRoot,每个AMX对象都包含于一个容器

getDomainRoot()

DomainRoot是所有AMX对象的容器(Container)

getFullType()

返回对象的j2eeTypes,并前缀以包含关系

比如:J2EEServer.J2EEApplication.WebModule.Servlet

类型是Servlet,包含关系是J2EEServer下的J2EEApplication下的WebModule

注意:J2EEServer不是根节点,它包含于DomainRoot下的J2EEDomain

getGroup()

AMX对象所属的组

(2)   Container接口用以说明是否包含其他AMX对象。每个AMX对象的容器都可通过getContainer()得到。DomainRoot是唯一的例外,它的容器是空(null)。

AMXImplBase类是所有AMX MBean的默认实现,包括对Delegate的应用。

(3)   Delegate接口。AMX MBean都是标准JMX MBean,即必须实现getMBeanInfo等方法,对此它们通常是委托一类叫Delegate的对象来实现的。每个Delegate都要实现接口com.sun.enterprise.management.support.Delegate:

public interface Delegate{
public Object getAttribute(String name)throws            

AttributeNotFoundException;

    public boolean supportsAttribute(String name);
    public AttributeList getAttributes(final String[] attrNames);
    public void setAttribute(final Attribute attrName
        throws AttributeNotFoundException, InvalidAttributeValueException;
    public AttributeList setAttributes(final AttributeList attrs);
    public boolean supportsOperation(String name, Object[] args, String[] types);
    public MBeanInfo getMBeanInfo();
    public Object invoke(String operationName, Object[] args, String[] types );
    public void setOwner(DelegateOwner owner);

}

针对离线或本地AMX MBean所对应的委托实现是offline.ConfigDelegate。类support.DelegateToMBeanDelegate是委托的另一种方式,它是将一个MBean的实现委托给另一个MBean来完成。

【例15.9】AMX MBean调用其对应的Delegate。

代码摘自com.sun.enterprise.management.support.AMXImplBase,显示了AMX MBean如何调用一个它的Delegate,从而得到指定的属性值:

protected Object delegateGetAttribute(final String name)

throws Exception {

assert(name != null);

//得到对应的Delegate

   final Delegate delegate = getDelegate();

    assert(delegate != null);

//调用Delegate方法得到指定的属性值

    final Object value = delegate.getAttribute(name);

    //将属性值由通用的Object对象转换成具体类型

Object result = value;       

   if (value != null) {

        Class<?> attrClass  = getAttributeClass(name); 

         if (attrClass != null) {

             if (ClassUtil.IsPrimitiveClass(attrClass)) {

                  attrClass = ClassUtil

.PrimitiveClassToObjectClass(attrClass);

              }               

              if (!attrClass.isAssignableFrom(value.getClass())) {

try {

result = convertToClass(value, attrClass);

} catch(Exception e) {

                      // OK, there are a few exceptions

                       result  = value;

                  }

             }

         } else {

             getMBeanLogger().warning(

"AMXImplBase.delegateGetAttribute:"

                            + "Can't find class for attribute: "

+ name + "=" + value + " in object "

+ getObjectName());

        }

}       

return(result);

}

3. 实现类与接口的对应

每个AMX MBean的实现类与接口之间有一定的对应关系,表15-6列举了各个AMX MBean实现类和接口之间的对应关系。

表15-6  AMX MBean实现类与接口的对应关系

接  口

实  现

AMX、AMXDebug、Container

AMXImplBase(被AMXNonConfigImplBase扩展)

AMXConfig

AMXConfigImplBase

ConfigFactoryCallback(impl)

ConfigFactory、ResourceFactoryImplBase

J2EEManagedObject

J2EEManagedObjectImplBase

Monitoring

MonitoringImplBase

MonitoringStats

MonitoringStatsImplBase(扩展MonitoringImplBase)

BeanMonitor

BeanMonitorImplBase(扩展MonitoringStatsImplBase)

ModuleConfig

DeployedItemConfigBase(扩展AMXConfigImplBase)

J2EEResource

J2EEResourceImplBase

EJB

EJBImplBase

J2EEModule

J2EEModuleImplBase

AMXJMXMonitor

JMXMonitorBase

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论