第二部分。 JMX代理规范
本章概述了Java管理扩展(JMX)代理架构及其基本概念。 它作为JMX代理的介绍规范。
JMX代理是在Java虚拟机(JVM)中运行的管理实体充当MBeans和管理应用程序之间的联络人。 一个JMX代理由一个MBean服务器组成,一组代表被管理的MBean资源,作为MBean实现的最少数量的代理服务,并且通常至少有一个协议适配器或连接器。
JMX代理体系结构中的关键组件可以进一步定义如下:
远程管理应用程序可以通过不同的协议访问代理适配器和连接器。 这些对象是代理应用程序的一部分,但它们是不属于JMX代理规范的一部分。
图5-1显示了业务代表的组件如何相互关联和相互关联管理应用。
……
FIGURE 5-1 Key Concepts of the JMX Agent Architecture
JMX体系结构允许对象在JMX上执行以下操作剂。 这些对象可以位于代理端应用程序中,也可以位于远程端管理应用。 他们能:
在JMX体系结构中,所有这些操作都是直接执行或执行的间接地通过JMX代理的MBean服务器。
代理规范中描述的所有代理组件和类都是强制性的。 为了符合代理规范,JMX代理实现必须遵守提供以下组件:
协议适配器和连接器使代理可以从远程管理访问应用。 它们通过MBean的特定协议提供视图在MBean服务器中实例化并注册。 他们启用管理JVM之外的应用程序可以:
Connectors用于将代理连接到启用远程JMX的管理应用程序,即使用分布式开发的管理应用程序JMX规范的服务。 这种通信涉及一个连接器代理中的服务器和管理器中的连接器客户端。
这些组件透明地传达管理操作的点对点一个特定的协议。 管理端的分布式服务提供了一个远程服务
接口到管理应用程序可以通过其执行操作的MBean服务器。 连接器是特定于给定协议的,但管理是特定的应用程序可以无差别地使用任何连接器,因为它们具有相同的远程设备接口。
Protocol adaptors通过给定的方式提供JMX代理的管理视图协议。 他们将MBean和MBean服务器的操作调整为在给定的协议中的表示,并且可能成为不同的信息型号,例如SNMP。
连接到协议适配器的管理应用程序通常特定于给定的协议。 传统管理解决方案通常就是这种情况依赖于特定的管理协议。 他们不通过访问JMX代理远程表示MBean服务器,但是通过映射的操作到那些MBean服务器。
连接器服务器和协议适配器都使用MBean服务器的服务将他们收到的管理操作应用于MBeans,并转发通知给管理应用程序。
要使代理可管理,它必须至少包含一个协议适配器或连接服务器。 但是,代理人可以包含任何数量的代理人,允许代理人执行此操作通过不同的协议同时进行远程管理。
JMX实现提供的适配器和连接器规范应该作为MBean来实现。 这允许他们按照管理以及根据需要动态加载和卸载。
基础类描述用作参数类型或返回的对象各种Java管理扩展(JMX)API的方法中的值。该本章介绍的基础类有:
所有基础类都包含在JMX Instrumentation API中,以便使用MBeans可以完全根据仪器规范进行开发,但可以进行操作由JMX代理。
对象名称唯一标识MBean服务器中的MBean。 管理应用程序使用此对象名称来标识要在其上执行的MBean管理运作。 类ObjectName表示一个对象名称由两部分组成:
对象名称的组件如下所述。
域名是区分大小写的字符串。 它提供了命名的结构JMX代理或全局管理解决方案中的空间。 域
名称部分可以在对象名称中省略,因为MBean服务器可以提供一个默认域。 当需要完全匹配时(请参阅“模式匹配”)第117页),省略域名将具有与使用默认值相同的结果由MBean服务器定义的域。
域名的结构如何取决于应用程序。 域名字符串可以包含除终止域的冒号(:)以外的任何字符名称和星号(*)和问号(?),它们是通配符。JMX总是处理域名作为一个整体,因此任何语义子定义在字符串内对于JMX实现是不透明的。
为了避免不同供应商提供的MBeans之间的冲突,一个有用的约定是以域名的反向DNS名称开始
指定MBeans的组织,后跟句点和字符串的解释由该组织决定。 例如,指定的MBeanSun Microsystems Inc.,DNS名称sun.com将拥有诸如com.sun.MyDomain。 这与Java语言的惯例基本相同包名称。
建议域不应该包含字符串“//”,它是保留供将来使用。
关键属性列表允许您为给定的MBean分配唯一的名称域。 关键属性是属性值对,属性不需要以对应于MBean的实际属性。
关键属性列表必须包含至少一个关键属性。 它可以包含任何关键属性的数量,其顺序不重要。
键属性中的值是一个任意字符串,但不能包含任何字符串这些人物:
:”=*?
如果需要具有这些特殊字符的字符串,则存在引用机制。 使用ObjectName.quote将任何字符串转换为可用作键的引用形式属性值和ObjectName.unquote转换回原始字符串。
一个有用的约定是在每个对象名称中包含一个type属性。 就这样所有类型为user的MBean都可以匹配模式“:type = user,”。
对象名称通常使用它们的字符串表示来构建和显示具有以下语法:
[domainName]:property=value[,property=value]*
可以省略域名来指定默认域。
对象的规范名称是对象的特定字符串表示名称,其中关键属性按照词汇顺序排序。 这种表示对象名称用于执行选择MBean的词典对比基于它们的对象名称。
大多数基本的MBean操作(例如create,get和set属性)需要通过其对象名称唯一标识一个MBean。 在那种情况下,完全匹配的名字被执行。
另一方面,对于查询操作,可以通过选择一系列MBean提供一个对象名称表达式。 MBean服务器将使用模式匹配对象的名称。 名称组件的匹配功能是在以下各节中进行介绍。
Domain Name
匹配语法与标准文件通配符一致,即:
Key Property List
通配符匹配也可以使用键来对关键属性的值执行相同的匹配语法(*和?字符)。 此外,关键属性的列表可能不完整并用作模式。
也是整个关键属性的通配符; 它取代了任何数量的可以采取任何价值的关键属性。 如果整个关键属性列表被给出为,这将匹配选定域中的所有对象。 如果至少有一个键属性在列表模式中给出,通配符可以位于给定模式中的任何位置,前提是它仍然是以逗号分隔的列表:“:property = value,”和“:,property = value”都是有效的模式。 在这种情况下,对象具有给定关键属性作为其关键属性列表的子集将被选中。
如果不使用通配符,则只使用与完整关键属性列表匹配的对象名称将被选中。 同样,该列表是无序的,所以列表模式中的关键属性可以以任何顺序给出。
如果在MBean服务器中注册了具有以下名称的示例MBean:
MyDomain:description=Printer,type=laser
MyDomain:description=Disk,capacity=2
DefaultDomain:description=Disk,capacity=1
DefaultDomain:description=Printer,type=ink
DefaultDomain:description=Printer,type=laser,date=1993
Socrates:description=Printer,type=laser,date=1993
以下是可以使用模式匹配执行的查询的一些示例:
ObjectInstance类用于表示MBean对象之间的链接名称和它的Java类。 它是MBean中MBean的完整描述服务器,但它不允许您通过引用访问MBean。
ObjectInstance类包含以下元素:
在创建并使用MBean时返回ObjectInstance随后进行查询。
这些类用于表示MBean属性及其值。 他们包含属性名称字符串及其值作为Object实例强制转换。
JMX定义了以下类:
Attribute和AttributeList对象通常用于传达MBean的属性值,作为getter操作的结果,或作为参数的设置操作。
JMX异常是由不同的方法引发的一组异常JMX接口。 本节描述哪些错误情况被这些封装例外。
主要发生JMX异常:
定义的JMX异常的组织基于错误的性质大小写(运行时间与否)以及生产地点(经理,代理人或者客户)在沟通过程中)。
只有代理提出的例外才属于本版本的范围规范。 本节仅介绍由MBean引发的异常服务器。 代理服务还定义并抛出特定的异常,这些都是描述在由Javadoc工具生成的各自的API文档中。
本章介绍作为核心的Managed Bean服务器或MBean服务器Java管理扩展(JMX)代理基础结构的组件。
MBean服务器是代理中MBean的注册表。 MBean服务器是组件,它提供用于操作MBean的服务。 所有管理在MBean上执行的操作通过MBeanServer接口完成。
通常,在MBean服务器中注册以下几种MBean:
JMX代理具有一个工厂类,用于通过。查找或创建MBean服务器工厂的静态方法。 这允许更灵活的代理应用程序和可能代理中的多个MBean服务器。
MBeanServer接口定义JMX代理上可用的操作。 一个JMX代理规范的实现提供了一个实现该类的类MBeanServer接口。 在整篇文档中,我们使用术语MBean服务器来参考一个可用的MBeanServer接口的实现剂。
MBeanServerFactory是一个静态方法返回实例的类实现类。 此对象作为MBeanServer的实例返回接口,从而将其他对象与MBean的任何依赖隔离服务器的实际实现类。 在创建MBean服务器时,调用者可以还要指定它所代表的JMX代理中使用的默认域的名称。
代理应用程序使用这些方法创建单个或多个MBean包含其MBean的服务器。 JMX代理规范仅定义行为的单个MBean服务器。 JMX代理中需要额外的行为包含多个MBean服务器不在本规范的范围内。
工厂还定义了用于查找已有的MBean服务器的静态方法被创建。 通过这种方式,加载到JVM中的对象可以访问现有的MBean服务器,而无需事先了解代理应用程序。
从Java 2平台标准版(J2SE 5.0平台)的5.0版开始,每个Java应用程序都有一个可以使用的平台MBean服务器java.lang.management.ManagementFactory.getPlatformMBeanServer()。此MBean Server包含特定数量的由指定的MBeanjava.lang.management包也可以作为一种方便的方式来使用在应用程序的不同模块之间共享应用程序MBean。
访问MBeanServerFactory类的静态方法由MBeanServerPermission类。 MBeanServerPermission扩展了基本的Java权限,并授予对以下MBean服务器操作的访问权限:
权限检查将在第12章“安全性”中进一步介绍。
MBean服务器的首要职责是成为MBean的注册中心。MBean可以由代理应用程序或其他MBean注册。 界面的MBeanServer类允许两种不同类型的注册:
object name在注册时被分配给MBean。 对象名称是字符串,其结构在第115页的“ObjectName类”中详细定义对象名称允许在MBean的上下文中唯一地标识MBean服务器。 这种唯一性在注册时由MBean服务器检查,将拒绝具有重复名称的MBean。
MBean开发人员可以对注册和注销进行一些控制MBean服务器中的MBean。 这可以通过实现MBean来完成MBeanRegistration接口。 在注册和注销注册之前和之后MBean,MBean服务器动态检查MBean是否实现了MBeanRegistration接口。 如果是这种情况,则适当的回调是调用。
MBeanRegistration接口实际上是JMX的一个API元素仪器规范。 这里描述的是因为它是执行MBean服务器定义了注册控制机制的行为。
实现这个接口也是MBeans可以获得的唯一方法引用它们所注册的MBeanServer。 这意味着他们有关于他们的管理环境的信息并变得有能力对其他MBean执行管理操作。
如果MBean开发人员选择实施MBeanRegistration接口,必须提供以下方法:
图7-1描述了MBeanRegistration的方法被调用的方式MBean服务器在执行MBean注册或注销时执行。该以粗框显示的方法是MBeanServer方法,其他方法是在MBean中实现。
……
MBeanServer接口的方法定义了以下管理要在已注册的MBean上执行的操作:
MBean服务器的方法是通用的:它们都采用一个对象名称确定执行操作的MBean。 MBean的作用服务器将解析此对象名称引用,确定请求的操作是否被允许在指定的对象上,如果是,则调用MBea方法执行操作。 如果出现结果,则MBean服务器将其值返回给呼叫者。
在MBean服务器中调用方法需要适当的权限。权限在第12章“安全”中描述。
API中给出了所有MBean服务器操作的详细描述由Javadoc工具生成的文档。
作为调用MBeanServer接口的通用方法的替代方法直接访问特定MBean的代码可以为其构建代理。 代理是一个实现与MBean本身相同接口的Java对象。 一种方法代理上的此接口通过MBean服务器路由到MBean。
在可能的地方使用代理而不是调用代码更简单,更不易出错MBean服务器的方法直接。
代理使用newMBeanProxy和newMXBeanProxy方法构造在类javax.management.JMX中。 该类的Javadoc详细解释如何构建和使用它们。
MBean服务器定义了一个名为“JMImplementation”的域,其中包含一个域MBeanServerDelegate类的MBean已注册。 这个对象标识和描述了注册的MBean服务器。 它也是广播公司由MBean服务器发出的通知。 换句话说,这个MBean就像一个代表它所代表的MBean服务器。
此代理对象的完整对象名称由JMX指定规范,如下所示:“JMImplementation:type = MBeanServerDelegate”。
委托对象提供有关MBean服务器的所有信息其中显示为字符串类型的只读属性:
MBeanServerDelegate类实现NotificationBroadcaster接口并发送由此发出的MBeanServerNotificationsMBean服务器。 对于接收这些通知的对象,他们必须注册委派对象(请参阅第134页的“MBean服务器通知”)。
注 - “JMImplementation”域名保留供JMX Agent使用实现。 MBeanServerDelegate MBean不能从中注销MBean服务器。
使用代理中适当的连接器服务器进行远程管理应用程序能够通过相应的操作在MBean上执行操作连接器客户端,一旦建立连接。
通常,远程客户端能够执行该操作中的一部分操作MBeanServer接口,通过该接口的父级MBeanServerConnection。因为远程连接可能会失败,所以MBeanServerConnection中的每个方法都会失败在throws子句中声明IOException。 请参阅“MBeanServerConnection接口”一节第140页。
图7-2显示了如何从远程传播管理操作管理应用程序添加到代理端的MBean。 这个例子说明了用于获取标准MBean的“State”属性的方法的传播以下情况:
….
MBean服务器将在MBean注册时始终发出通知注销。 为此定义了Notification类的特定子类用途:MBeanServerNotification类,包含对象名称列表参与该行动。
MBean服务器对象本身不会广播通知:它的唯一代理MBean实现NotificationBroadcaster接口来广播通知在它的地方。
要注册MBean服务器通知,监听器将调用与注册时一样,MBean服务器的addNotificationListener方法MBean通知,但它将提供MBean的标准化对象名称服务器委托对象(请参阅第121页的“MBean服务器委托MBean”)。
在接收MBean通知时,对象必须实现NotificationListener接口接收MBean服务器通知。
通过它的委托,MBean服务器发出以下两种类型的通知:
注 - 当注册的属性时,MBean服务器不发送通知MBean更改值。 实施时,处理这种类型的通知直接由MBean执行,如第58页上的“属性更改通知”中所述。
查询根据它们的对象从MBean服务器中检索MBean集合名称,它们的当前属性值或两者。 JMX规范定义了用于构建查询表达式的类。 这些对象然后传递给MBeanServer接口执行查询的方法。
执行查询的MBeanServer接口的方法是:
这两种方法的参数含义是相同的。 对象名称参数定义了一个模式:查询的范围是其对象的MBeans集合名字满足这种模式。 查询表达式是用户定义的标准基于其属性值过滤作用域内的MBean。 如果任一查询方法找不到在给定范围内或满足给定查询的MBean表达式或两者,返回的Set将不包含元素。
当对象名称模式为空时,范围等同于所有MBeanMBean服务器。 当查询表达式为空时,MBean不被过滤,结果等同于范围。 当两个参数都为空时,结果就是集合所有在MBean服务器中注册的MBean。
在MBean服务器中注册的所有MBean的集合始终包含该委托MBean,以及任何注册MBean的计数。 其他查询也可以返回委托MBean,如果其对象名称在范围内并且它满足查询表达式(如果有)(请参阅第121页的“MBean Server委托MBean”)。
范围由对象名称模式定义:请参阅第117页上的“模式匹配”。只有那些对象名称与模式匹配的MBean才会被考虑查询。 查询表达式必须应用于作用域中的每个MBean,以过滤查询的最终结果。 如果查询机制得到正确实施并且用户给出了相关的对象名称模式,查询的范围可以大大的提高减少查询的执行时间。
该模式可能是一个完整的对象名称,这意味着该对象的范围该查询是单个MBean。 在这种情况下,查询等同于测试存在具有该名称的注册MBean,或者如果查询表达式不存在null,测试该MBean的属性值。
查询表达式是根据属性值的约束(例如“等于”和“小于”的数字值和“匹配”的字符串)。这些限制可以然后由关系运算符(和,或者,而不是)形成复杂关联涉及几个MBean属性的表达式。
例如,代理或经理应该能够表达一个查询,例如:“检索属性年龄至少为20的MBean和属性名字以G开头,以ling结尾“。
查询表达式一次在单个MBean上进行评估,当且仅当表达式为真,则MBean包含在查询结果中。 MBean服务器测试表达式在查询范围内针对每个MBean单独表达。不是这样查询表达式可能适用于多个MBean:没有用于定义交叉MBean约束的机制。
如果对范围中的给定MBean的查询表达式进行评估,则结果为异常,MBean从查询结果中被忽略。例外不是传播给queryMBeans或queryNames的调用者。错误(的子类)java.lang.Error)可以传播,但是。
为开发查询表达式定义了以下类和接口:
实际上,用户不会实例化ValueExp和QueryExp实现直接上课。 相反,他们依靠Query类的方法来返回值和表达式,将它们组合在一起以形成最终的查询表达式。
Query类的静态方法用于构造值,约束,和查询表达式的子表达式。
以下方法返回可用作a的一部分的ValueExp实例约束,如下所述:
以下方法表示对一个或多个值的约束。他们拿ValueExp对象并返回一个QueryExp对象,该对象指示约束是否为在运行时满意。这个返回对象可以用作查询表达式,或者它可以用逻辑运算符组成一个更复杂的表达式。
一个约束可以被看作是计算一个布尔值并且可以被用作a子表达式转换为以下方法。 约束还返回一个QueryExp对象可以在查询中使用,也可以作为更复杂的子表达式使用相同的方法进行查询:
使用这些方法,本节开头提到的示例查询是建设如下。 当在字符串值上构造约束时,星号(*)是a通配符可以替换任意数量的字符,包括零。或者,程序员可以使用查询的子字符串匹配方法类。
CODE EXAMPLE 7-1 Building a Query
QueryExp exp = Query.and(
Query.geq(Query.attr("age"),
Query.value(20)),
Query.match(Query.attr("name"),
Query.value("G*ling")));
大多数查询都遵循上述模式:MBean的命名属性为受程序员定义的值约束,然后组成查询几个属性。 提供的所有公开属性都可用于过滤目的它们可以受数值,布尔值或字符串值的约束。
也可以根据Java类的名称执行查询使用Query类的classattr方法实现MBean。 (这个然而,功能大部分被Query.isInstanceOf查询取代。)代码示例7-2显示了如何构建用于过滤所有MBean的查询虚构类managed.device.Printer。 这个约束也可以组成对属性值进行约束以形成更具选择性的查询表达式。
CODE EXAMPLE 7-2 Building a Query Based on the MBean Class
QueryExp exp = Query.eq(
Query.classattr(),
Query.value(“managed.device.Printer”));
执行查询可能会导致某些特定于过滤的异常方法。 如果对给定MBean的查询的评估生成其中的一个异常时,查询结果中将省略MBean。 应用程序代码不会在通常情况下查看这些例外。 只有当应用程序本身抛出异常,或者如果它调用QueryExp.apply,它是否会看到这些异常。
JMX 1.2规范引入了一个新的接口MBeanServerConnection,MBeanServer的父接口。 这个接口的目的是提供一个用于访问MBean服务器的通用类型,无论它是否是远程的,即通过连接器或本地访问,并直接作为一个访问Java对象。
MBeanServerConnection接口类似于MBeanServer,但有两个主要区别:
与MBeanServerConnection交互的应用程序代码与本地应用程序一起工作MBean服务器或连接器的客户端,无论它是否是连接到服务器或连接器。
由于MBeanServerConnection的所有方法都可以抛出IOException,调用它们的应用程序代码必须准备好处理这个异常妥善处理。 对于本地MBean服务器,这些例外情况不能发生,但代码必须处理它们。 这是要付出的代价在本地和远程情况下都以同样的方式运行。
从JMX规范的1.2版本开始,系统属性可以设置javax.management.builder.initial来替换默认值
用不同的实现来实现MBeanServer接口。当createMBeanServer或newMBeanServer方法的时候
MBeanServerFactory类被调用,它会查询这个属性。如果存在一个值,那么它必须命名一个作为其子类的公共类javax.management.MBeanServerBuilder。该类被实例化并用于创建一个MBeanServer实例。
一个MBeanServerBuilder必须能够创建一个实例MBeanServerDelegate和MBeanServer的一个实例。该MBeanServerDelegate可以是标准例如,javax.management.MBeanServerDelegate或自定义子类,重写实现名称属性。 MBeanServer可以是一个完成MBeanServer接口的重新实现,或者它可以建立在MBeanServer上标准实现通过实例化javax.management.MBeanServerBuilder,调用它的newMBeanServer方法,并将生成的对象包装到另一个MBeanServer对象中。
本章介绍基于Java的类加载器的动态加载服务功能来提供使用新的检索和实例化MBean的能力
Java类和可能的本地库。 这些类和库的起源是在部署MBean服务器时不一定是已知的,并且可以包含代码从远程服务器加载。
动态加载通常由管理小程序(m-let)服务执行用于实例化从远程URL获取的MBean(通用资源定位器)在网络上。
Java管理扩展(JMX)规范也定义了较低级别类加载机制,允许开发人员扩展功能m-let服务或在没有它的情况下加载类。
本章介绍所有兼容JMX代理的强制功能。
m-let服务允许您从一个实例化并注册一个或多个MBean远程URL,位于MBean服务器中。 m-let服务通过加载m-let来完成此操作文本文件,指定要获取的MBean的信息。 信息每个MBean都在与XML中使用的标签类似的标签中指定,称为MLET标签。M-let文本文件的位置由URL指定。 当一个m-let文本文件是加载后,下载MLET标签中指定的所有类,并为每个类指定一个实例文件中指定的MBean已创建并注册。
m-let服务本身作为一个MBean实现,并在MBean中注册服务器,所以它可以被其他MBean,代理应用程序或远程使用管理应用。
图8-1说明了m-let服务的操作。
……
FIGURE 8-1 Operation of the M-Let Service
m-let文件可以包含任意数量的MLET标签,每个标签用于实例化不同的标签JMX代理中的MBean。 MLET标签具有以下语法:
<MLET
CODE = class | OBJECT = serfile
ARCHIVE = "archivelist"
[CODEBASE = codebaseURL]
[NAME = MBeanName]
[VERSION = version]
>
[arglist]
MLET>
这个标签的元素解释如下:
m-let服务的类是javax.management.loading的成员包。 MLet类实现包含方法的MLetMBean用于远程访问。 这意味着m-let服务本身就是一个MBean和可以像这样管理。
MLet类还扩展了java.net.URLClassLoader对象,这意味着它本身就是一个类加载器。 这允许几个快捷方式来加载没有的类需要一个m-let文件。
m-let服务的getMBeansFromURL方法执行类加载基于远程服务器上的m-let文本文件。 m-let文件和类文件需要可以在服务器上使用,如第144页的“MLET标签”中所述此方法的重载版本将URL参数作为字符串或java.net.URL对象。
m-let文件中的每个MLET标记描述了一个要下载和创建的MBean在MBean服务器中。 当对getMBeansFromURL方法的调用成功时,新下载的MBean在JMX代理中实例化并注册使用MBean服务器。 这些方法返回MBeans的对象实例被成功创建,并为那些不成功的对象抛出一个可抛出的对象。
MLet类的其他方法管理本地库的目录以JAR文件格式下载并由某些MBeans使用。 请参阅API文档由Javadoc工具生成更多细节。
m-let服务使用其类加载器功能来访问中给出的代码库一个m-let文件或由URL本身提供。这个代码库可以在m-let中使用用于从相同的代码库下载其他MBean的服务。
例如,一个m-let文件可以指定一些MLET标签来填充所有的JMX代理中的MBean。一旦getMBeansFromURL方法被调用做到这一点,m-let服务可以用来再次实例化这些MBean中的任何一个,或者在相同的代码库中的任何其他类。
这是通过将m-let服务的对象名称作为类加载器参数传递给MBean服务器的createMBean方法(请参阅相应的API由Javadoc工具生成的文档)。因为代码库已经被m-let服务访问,其类加载器功能可以访问代码再次基地。在这种情况下,MLET标签中的信息不再被采纳帐户,尽管可以使用createMBean方法的参数指定参数给类构造函数。
因为MBeanServer接口的createMBean方法需要该对象类加载器的名称,此功能也可用于远程管理在JMX代理中没有直接对象引用的应用程序。
m-let服务MBean还公开用于指定代码的addURL方法而不需要访问任何m-let文件。这些方法添加代码库由指定的URL指定给m-let服务的类加载器。 MBean类在此代码库中可以直接下载并在MBean服务器中创建通过createMBean方法,再次使用作为类给出的m-let服务加载器对象。
注 - 使用m-let服务的类加载器从中加载创建类任意代码库或从m-let代码库重新加载类意味着代理应用程序或MBean开发人员对代码库有一些预先知识运行时的内容。
m-let服务充当它加载的任何MBean的类加载器。这意味着如果MBean包含本地方法,并且它们加载包含该方法的本地库这些方法的代码使用System.loadLibrary,然后是m-let类加载器findLibrary方法将被调用来查找库。此方法被覆盖来自java.lang.ClassLoader。它会试图找到一个资源(通常是一个在JAR文件中输入),其名称是库的名称,在系统相关中修改办法。如果它找到了,它会将内容复制到目录中的文件中由MLet.getLibraryDirectory()方法返回,并返回名称该文件作为findLibrary的结果。这在API中进一步描述MLet.findLibrary规范。
并非所有系统都以这种方式支持本地库。一个不会的系统抛出getLibraryDirectory和UnsupportedOperationException异常MLet类中的setLibraryDirectory方法。
即使在支持此功能的系统上,最好不要依赖它因为它带来的可移植性问题。
MBean服务器在类加载器存储库中维护一个类加载器列表。该类加载器存储库有时也被称为默认加载器存储库。
类加载器存储库在以下情况下使用:
如果在同一个Java虚拟机中为几个MBean服务器创建例如调用MBeanServerFactory.createMBeanServer的程序几次,每个人都有自己的类加载器存储库,独立于其他。
在创建MBean服务器时,其类加载器存储库包含类加载器用于加载MBeanServer实现类。 此后,一堂课如果注册为MBean,则加载器将添加到存储库中。 如果MBean是随后未注册,则将其从存储库中删除。
换句话说,如果一个MBean被注册为一个后代java.lang.ClassLoader,它被添加到类加载器库中。
如果MBean是java.lang.ClassLoader的后代,但实现了接口javax.management.loading.PrivateClassLoader,那么它永远不会添加到类加载器存储库。
因为类javax.management.loading.MLet是的后代java.lang.ClassLoader,m-let在添加到类加载器库时它们在MBean服务器中注册。 JMX规范包含一个类PrivateMLet子类MLet并实现PrivateMLet。 一个除了永远不会被添加到外,PrivateMLet的行为就像MLet一样类加载器存储库。
存储库中类加载器的顺序非常重要。当一个类被加载使用存储库,每个类加载器依次被要求加载类。如果一个装载机成功加载课程,搜索停止。如果加载程序抛出ClassNotFoundException,搜索继续执行列表中的下一个加载器。如果没有加载器成功加载类,尝试结果为aClassNotFoundException异常。
类加载器存储库中的第一个加载器是用于加载该类的第一个加载器MBeanServer实现类。此后,每个条目都是一个MBeanjava.lang.ClassLoader的后代。这些装载机的顺序是英寸中的顺序MBeans被注册了。
更正式地说,如果createMBean或者.MBean m1出现在MBean m2之前,那么MBean m1会出现MBean m2之前registerMBean操作注册了m1之前完成的操作注册m2开始。如果两个操作都没有在另一个操作完成之前完成MBean同时在不同的线程中注册,并且之间的顺序m1和m2是不确定的。
m-let是一个类加载器,因此它遵循一个类的标准行为加载器使用loadClass方法加载类时:
如果这两个尝试均未找到该类,则m-let尝试加载该类通过类加载器存储库。我们说它委托给类加载器库。只有当这种尝试也失败时,m-let才会抛出aClassNotFoundException异常。
当m-let委托给类加载器存储库时,存储库中的每个加载器被依次要求加载班级。但是,如果m-let本身就在类加载器中存储库,只要到达m-let,搜索就会停止。也就是说,只有m-let委托给存储库中的加载器。
类加载器存储库可用作使公共类可用的一种方式到来自不同来源的MBean。常见的类放在存储库中,和m-let委托给存储库可以找到它们。因为只有m-let委托给存储库中它们之前的加载程序,加载程序的顺序注册是重要的。如果m-let m1定义了mlet中的类使用的类m2,那么m1必须在m2之前注册。
当创建一个m-let时,可以控制它是否委托给其他人通过存储库的装载机,以及其他装载机是否委托给它:
在1.2之前的JMX规范的版本中,m-let委托给完整列表类加载器存储库中的加载器。也就是说,如果一个m-let本身没有找到一个类,存储库中的每一个其他装载器都被咨询过。装载机被咨询不管它们是在库中的m-let之前还是之后。
这种行为对于某些Java虚拟机的一个微妙问题是开放的。注意一个类不一定是通过显式调用loadClass方法来加载的一些类加载器。更经常的是,一个类被加载,因为它被另一个类引用类,例如,因为它是该类中的字段的类型,或者是参数或类的字段类型在方法中返回值,或者它是该类的超类或超接口,或者是其中的一个该类中的方法构造它的一个实例,或者引用一个静态字段或方法。简化一下,我们可以说一个阶级的确切时刻加载无法预测。
当一个类c1第一次引用另一个类A时,A使用c1的类加载装载机。如果c1由m-let m1加载,则A也将使用m1加载。
如果m1没有通过它的父类加载器或通过它的列表找到类A.URL,它将委托给类加载器存储库。
参考图8-2,设想在另一个线程中同时出现一个类c2,由m-let m2装载,首次提到B类。 再次,B将被加载使用m2,如果m2没有找到类本身,它将委托给类加载器库。
如果m1搜索存储库中除本身之外的所有加载程序,m2会执行此操作同样,那么m1最终会发送一个请求到m2来加载A,m2将最终结束向m1发送请求以加载B.
某些没有的Java虚拟机实现会出现问题一次允许多个线程通过给定的类加载器加载类。因为线程1正在通过m1加载类A,线程2不能同时加载B级到m1级。 因为线程2正在通过m2加载B类,线程1不能同时通过m2加载A级。 每个线程都必须等待另一个线程在它可以继续之前完成,创造一个典型的死锁情况。
……
FIGURE 8-2 Deadlock scenario for m-let delegation
语义的变化避免了这种情况,因为两个m-let必须有一个在类加载器存储库中出现在另一个之后。 如果m2出现在m1之后,则m1将会出现从来没有尝试使用m2加载一个类,因为它只委托加载器出现的时间早于存储库中的时间。 所以僵局不会发生。
如果你准备好运行僵局的风险,或者你确定这样的场景由于上述情况不会发生,所以直接将MLet子类化并覆盖它loadClass方法来恢复以前的委托给所有加载器的语义在存储库中,无论是在m-let之前还是之后。 但是,您应该记住,如果通过这样一个MLet子类加载的类引用另一个没有的类存在之前,请参阅类加载程序存储库中的所有m-let抛出ClassNotFoundException。
类加载的一个微妙缺陷是由类加载器cl1创建的类a.b.C与类加载器cl2创建的类a.b.C不同。 在这里,“创建”指的是实际上使用其defineClass创建类的类加载器方法。 如果cl1和cl2都通过委托给另一个类加载器cl3来找到a.b.C,则它是同一班。
由cl1创建的“a.b.C”类型的值不能分配给变量或由cl2创建的“a.b.C”类型的参数。 试图这样做会导致一个异常,如ClassCastException。
对于JMX规范,这可能会造成方法参数的问题createMBean,invoke,setAttribute和MBean服务器的setAttributes。
假设您有一个具有以下接口的MBean:
CODE EXAMPLE 8-1 Simple MBean interface:
public interface AnMBean {
public void m(SomeClass x);
}
如果MBean服务器包含由该类创建的该MBean的一个实例装载机cl1。 在某个阶段,无论是在加载过程中,还是在第一次被引用时,cl1将加载类SomeClass。
现在假设您正在编写一个连接器。 在接收端(服务器端)连接器,您将获得调用MBean上的m的请求。 发件人将发送一个您必须重新创建SomeClass的实例,例如,通过反序列化它。 如果你用cl1以外的任何类加载器重新创建它,你会在得到一个异常时您尝试将其传递给方法m。
这意味着你的连接器服务器必须有一个实例化接收的方法使用正确的类加载器的对象。
为此,MBeanServer接口中有三个与类相关的方法加载:
以下各节将介绍这些方法。
代码示例8-1在152页适当的方法是:
public ClassLoader getClassLoaderFor(ObjectName name);
通过使用MBean的ObjectName调用此方法,您可以获取该类加载器创建了MBean的类,在我们的示例中为cl1。 然后你可以得到正确的类,SomeClass,使用cl1。
getClassLoaderFor方法适用于invoke,setAttribute,和setAttributes操作,因为适当的类加载器
这些操作的参数是目标MBean的类加载器。
getClassLoaderFor方法在JMX的1.2版本中引入规范。 以前,连接器服务器必须使用反序列化之一
MBeanServer接口中的方法。 这些方法现在已被弃用。因此,请使用getClassLoaderFor而不是反序列化(ObjectName名称,byte []数据)。
对于createMBean操作,目标MBean不存在,因为整个操作的目的是创建它。 有两类createMBean操作,具体取决于是否有指定的loaderName参数作为用于加载MBean类的类加载器的MBean的名称。
类似的考虑适用于MBeanServer的实例化方法接口。 但是,这些方法通常不会通过连接器暴露。
方法getClassLoader和getClassLoaderRepository是在JMX规范版本1.2中引入。 以前,连接器服务器必须在MBeanServer接口中使用三种反序列化方法之一。 这些方法现在已被弃用。
因此,使用getClassLoaderRepository而不是
deserialize(String className,byte [] data)
也可以使用getClassLoader代替
deserialize(String className,ObjectName loaderName,byte [] data)
本章指定了允许您观察的监视器MBean族其他MBean中的属性值的随时间变化,并在发送通知
阈值事件。 它们统称为监测服务。
监视服务是遵从JMX的代理的强制性部分规范,并且必须全面实施。
使用监视服务,可以从一个或多个给定属性中获取观察值其他MBean(观察到的MBean)会按照指定的时间间隔进行监视粒度周期。 该值是属性值或其中包含的值复杂类型的属性值。 对于每个观察到的MBean,监视器派生出一个来自这个观察的第二个值,称为派生量表。 这个派生的标准是要么是确切的观测值,要么是两者之间的差异数值类型的连续观测值。
每个监控服务发送一个特定的通知类型的派生量表满足一组条件之一。 条件被指定当监视器初始化时,或者通过监视器MBean的动态管理界面。 监视器也可以在某些错误情况下发送通知在监视属性值时遇到。
有关MBean中属性值的信息由三个提供不同类型的显示器:
所有类型的监视器都扩展了抽象的Monitor类,它定义了常见的类属性和操作。 观测值的类型必须被支持使用特定的监视器子类。
但是,监视器会验证返回的对象实例的类型属性的值,而不是观察到的MBean元数据中声明的属性类型。例如,这允许字符串监视器观察声明为Object的值在其元数据中,只要实际值是String实例。
每个监视器也是一个标准的MBean,允许它们被创建和由其他MBean或管理应用程序动态配置。
通知类的特定子类被定义为供所有监控使用服务:MonitorNotification类。
此通知用于报告以下情况之一:
MonitorNotification实例中的通知类型字符串标识特定的监视事件或错误情况,如图9-1所示。 a的领域MonitorNotification实例包含以下信息:
所有可以由生成的通知类型的树表示形式监控服务在图9-1中给出。 错误类型对所有人都是通用的监视器并在下面进行描述。 每个阈值事件都是特定于它的监视器并在相应的章节中进行介绍。
……
FIGURE 9-1 Tree Representation of Monitor Notification Types
以下通知类型对所有显示器都是通用的,并被发送到反映错误情况。 显示器启动时进行第一次测量:
以下通知类型对于计数器和计量监视器是通用的; 它被发射以反映特定的错误情况:
计数器监视器在观察到的计数器值达到或时发送通知超过了被称为阈值的比较水平。
计数器到达时可以翻转(也称为环绕)最大值。 在这种情况下,每次计数器触发通知达到或超过阈值,只要在阈值以下观察到自从之前的通知。 计数器不一定会翻转为零,但是这不会影响处理一般情况的显示器。
另外,偏移机制可以检测计数间隔,如下所示:
如果使用计数器差异选项,那么派生的计量器的值是计算为两个连续观察计数器值之间的差值观察结果。如果计数器会翻转,那么必须定义模量计数器差异是积极的。当计数器翻转时,两者之间的差异观察结果将是负值,模数的值需要加上。在时间t计算计数器差值的派生量表值(V [t])使用以下算法,其中GP是粒度周期:
计数器监视器有以下限制:
图9-2显示了偏移量为2的计数器监视器的操作。
监视器观察到随时间t变化的计数器C(t)。 粒度周期是GP并且比较级别是T. CounterMonitor何时发送通知计数器的值达到或超过比较(阈值)级别。 后通知已经发送,阈值增加了偏移值直到比较级别大于计数器的当前值。
除了监视器错误通知类型外,CounterMonitor MBean还可以广播以下通知类型:
仪表监视器观察表现为仪表的数值。 滞后机制是为了避免重复触发通知时仪表在阈值附近产生小振荡。 这种能力是通过成对指定阈值来提供; 一个是高门槛值另一个是低阈值。 阈值之间的差异是滞后区间。
GaugeMonitor MBean具有以下结构:
仪表监视器有以下限制:
仪表监视器具有以下行为:
如果使用标准差选项,则派生标准的值为计算为连续两次观测值的差值观察结果。
在t时刻使用计算出的量表差值的派生量表值(V [t])以下算法,其中GP是粒度周期:
假设两者都是GaugeMonitor的操作,如图9-3所示通知开关是真的。
……
FIGURE 9-3 Operation of the GaugeMonitor
除了监视器错误通知类型外,GaugeMonitor MBean还可以广播以下通知类型:
字符串监视器观察String类型的值。 在这种情况下派生的标准是始终是观察值。 字符串监视器被配置为一个值字符串称为字符串比较,并能够检测以下两个条件:
假设选择了两个通知,则此机制可确保匹配和不同的是严格交替的,每次都是在第一次观察条件时发生。
字符串监视器的操作如图9-4所示。 粒度周期是GP,字符串比较是“XYZ”。
……
FIGURE 9-4 Operation of the StringMonitor
除了监视器错误通知类型外,StringMonitor MBean还可以广播以下通知类型:
图9-5提供了各种监视器MBean类的包图他们实现的接口。 由Javadoc生成的API文档工具提供了所有监视服务接口的完整描述类。
……
FIGURE 9-5 The Package and Class Diagram of the Monitor MBeans
计时器服务会在特定日期和时间触发通知。 它也可以触发通知以固定的时间间隔重复。 通知被发送到所有对象注册接收定时器发出的通知。 定时器服务是一个可以管理的MBean,允许应用程序设置可配置的调度。
从概念上讲,Timer类管理发送的日期通知列表当他们的日期和时间到达。 提供这个类的方法来添加和从列表中删除通知。 实际上,通知类型是由。提供的用户,以及日期和可选的周期以及重复次数。该定时器服务总是发送其特定的通知实例TimerNotification类。
计时器服务可以通过两种不同的方式管理通知:
此行为由通知时传递给定时器的参数定义被添加到通知列表中。 每个通知添加到计时器服务被分配一个唯一的标识号码。 只有一个标识号码分配给通知,无论触发多少次。
定义了通知类的特定子类以供定时器使用服务:TimerNotification类。 通知类型包含在实例中
的TimerNotification类是特别的:它是由用户定义的通知被添加到定时器。 所有由定时服务广播的通知都是TimerNotification类的实例。
TimerNotification类具有唯一的通知标识符字段标识触发此通知实例的计时器通知。
定时服务维护一个已经过期的通知的内部列表请求发送。 通知被添加到这个列表使用Timer类’addNotification方法。 这些方法使用以下参数定时器创建一个TimerNotification对象,然后将其添加到列表中:
除了通知之外,addNotification方法也被重载参数和日期,它可以采用以下可选参数:
如果要插入的通知的日期在当前日期之前,那么addNotification方法的行为就像当前日期已被指定一样。更新正在添加的计时器通知的日期不会生成任何日期通知事件,而不是sendPastNotifications机制定时器启动时应用(请参阅“启动和停止定时器”打开第168页)。
addNotification方法返回新的计时器通知的标识符。该标识符可用于从中检索关于通知的信息定时器或从定时器的通知列表中删除通知。 然而,通知已添加到通知列表后,与其关联参数不能更新。
当发生一次性通知(周期为零或空)时,它将从中删除定时器的通知列表。
定时器服务MBean是一个带通知的标准通知广播器类型和时间由通过建立的通知列表定义addNotification方法。给定定时器MBean的所有侦听器都将收到其所有的侦听器计时器通知。配置为监听特定计时器通知的监听器在注册为侦听器时应指定适当的过滤器对象(请参阅“NotificationFilter接口”在第58页)。
当定时器处于活动状态并且定时器通知的日期到期时,定时器服务以给定类型,消息和用户数据广播该通知,以及定时器内的通知标识符。如果有定期通知指定的出现次数,该数字减1。访问定时器通知的出现参数总是返回剩余的访问时发生的次数。
当通知没有重复或已经用完时它会从定时器的通知列表中删除。的方法如果调用,则用于访问通知参数的Timer类将引发异常带有发送和删除的定时器通知的标识符。
计时器通知也可以使用其中一个从通知列表中删除遵循Timer类的方法:
定时器服务(由Timer类的一个实例表示)使用激活启动方法并使用停止方法停用。如果通知列表计时器启动时为空,计时器等待添加通知。没有定时器通知在定时器启动之前或停止之后触发。
您可以通过调用定时器来确定定时器是否正在运行方法isActive。如果计时器正在运行,isActive方法返回true。
如果计时器列表中的任何通知都有关联的日期已过当定时器启动时,定时器尝试更新它们。定期的日期通知按其间隔时间递增,直到日期大于当前日期。增量的数量可以受限于其定义的数量的事件。在开始日期和时间之前的一次性日期的通知通知数量有限,无法更新为超过开始日期将从计时器的通知列表中删除。
在定时器启动期间更新或删除通知时,其通知为可以触发或忽略,具体取决于sendPastNotifications属性Timer类的使用:
将sendPastNotifications标志设置为true会导致泛滥定时器启动时广播通知。 此标志的默认值
是错误的。 将此标志设置为true可确保发生的通知日期定时器停止不会丢失。 用户可以选择在计时器时接收它们即使它们不再符合它们的设定日期,它也会再次启动。
调用在已经启动的Timer上开始,或者在Timer上停止已经停止了,没有效果。 停止后,定时器处于初始状态,并可以在开始时重新启动。
作为代理规范的一部分,Java管理扩展(JMX)规范还定义了MBeans之间关系的模型。关系是一个用户定义的,在命名角色中的MBean之间的n元关联。 JMX规范定义用于构建表示关系的对象的类,以及它定义了关系服务,集中了代理中关系的所有操作。
所有关系都由提供有关角色信息的关系类型定义它包含诸如它们的多样性,以及满足这些MBeans的类名角色。通过关系服务,用户可以创建新的类型,然后创建,更新或删除满足这些类型的关系。关系服务也执行查询在所有关系中找到相关的MBean。
关系服务维护关系的一致性,检查所有操作和所有的MBean注销来确保一个关系总是符合它的
关系类型。如果关系不再有效,它将从关系服务中删除,尽管其成员MBean以其他方式继续存在。
一个关系由指定的角色组成,每个角色的值都是由该角色中的MBeans列表。 该列表必须符合角色信息定义相应角色的MBeans的多重性和类别。 一套一套或更多角色信息定义构成关系类型。 关系类型是a所有关联实例的模板,用于关联表示其角色的MBean。 我们使用术语关系来表示关联现有关系的特定实例MBean根据其定义关系类型中的角色。
JMX规范中的关系模型依赖于以下术语。 在这里,我们只定义由术语表示的概念,而不是相应的Java类。
在本章中,我们将使用书与书之间关系的例子他们的主人。
为了在JMX规范模型中表示这种关系,我们说图书和所有者是角色。 书籍代表给定MBean的任何数量的拥有书籍类,所有者是另一个MBean类的书籍所有者。 我们可能会定义一个关系键入包含这两个角色并称之为个人图书馆,代表书籍所有权的概念。
与UML相比,下面的图表代表此示例关系建模其相应的关联。
……
FIGURE 11-1 Comparison of the Relation Models
在JMX规范模型中,关系类型是一组静态角色。 关系类型可以在运行时定义,但一旦定义,它们的角色和角色信息不能修改。 给定类型的关系实例定义每个MBean角色并在必要时为其提供操作。
MBean通过由关系类型定义的关系实例关联关系服务,但是MBean仍然可以通过MBean完全访问
服务器。只有注册的MBean(由它们的对象名称标识)可以是a的成关系。关系服务从不在成员MBean上运行,它只提供他们的对象名称以回应查询。
关系服务阻止无效关系类型的创建,例如,如果角色信息不一致。同样,无法建立无效关系,要么是因为关系类型不受尊重,要么是因为关系类型的对象名称成员MBean在MBean服务器中不存在。角色值的修改也受到相同的一致性检查。
从关系服务中删除关系时,其成员MBean不是通过已移除的实例更长时间的关联,但不受影响。当一个关系类型被删除,该类型的所有现有关系首先被删除。该调用者负责了解删除关系类型的后果。
因为关系仅在已注册的MBean之间定义,所以注销a成员MBean修改关系。关系服务侦听所有MBean服务器通知,用于指示何时取消注册任何关系的成员。然后将相应的MBean从其出现的任何角色值删除。如果新基数的作用与相应的关系类型不一致,该关系从关系服务中删除。
关系服务在修改关系的所有操作之后发送通知实例,创建,更新或删除。此通知提供信息关于修改,例如关系的标识符和新的角色值。该通知还表明该关系是内部还是外部定义(请参阅第174页的“外部关系”)。第171页上的图11-1中介绍的两种模型有所不同。UML协会意味着每本书只能有一个所有者。JMX规范中的关系类型仅对一组角色建模,表明这一点一个关系实例在Books中有一个拥有者MBean和任意数量的MBean角色。JMX规范关系模型只保证MBean满足其要求指定的角色,它不允许用户定义MBean可以有多少关系出现在这里。这意味着关系服务不执行相互关系一致性检查。这些是管理应用程序的责任在创建或修改关系实例时。
如果需要这种一致性水平,管理解决方案的设计者就必须这样做在使用关系服务的对象中实施必要的验证。在我们的例子,设计师需要确保同一本书MBean不是添加到多个个人图书馆关系。一种方法是通过在执行任何操作之前调用关系服务的查询方法。
JMX规范定义了其行为实现这一点的Java类关系模型。第170页的“术语”中定义的每个概念都有一个相应的Java类(请参见第171页的图11-2)。随着行为关系服务对象本身,这些类决定了关系服务是如何的用于管理解决方案。
本节介绍关系服务与支持之间的交互类。所有课程的操作和其他细节将进一步介绍部分。异常类是RelationException类的所有子类并只提供一个消息字符串。 API生成的文档其他类的Javadoc工具指出哪些异常是由特定引发的操作。
实际上,角色描述结构是在关系服务之外处理的,并且它们的对象直接由用户实例化(请参阅“角色描述类”第184页)。角色信息对象被分组到数组中以定义关系类型。角色对象和角色列表被实例化传递给角色值的设置者。角色结果由角色值的获取者及其角色列表和未解决的角色返回可以提取列表进行处理。
javax.management.relation
«relation service»
RelationService
RelationServiceMBean
RelationNotification
MBeanServerNotificationFilter
«relation support»
RelationType
RelationTypeSupport
Relation
RelationSupport
RelationSupportMBean
«role description»
RoleInfo
Role
RoleList
RoleUnresolved
RoleUnresolvedList
RoleResult
RoleStatus
«exception superclass»
RelationException
«relation type creation errors»
InvalidRoleInfoException
InvalidRelationTypeException
«relation creation errors»
InvalidRelationServiceException
RelationServiceNotRegistered-Exception
RoleInfoNotFoundException
InvalidRoleValueException
RelationTypeNotFoundException
InvalidRelationIdException
«relation access errors»
RelationNotFoundException
RoleNotFoundException
FIGURE 11-2 Classes of the javax.management.relation package
另一方面,关系类型和关系实例由控制关系服务维护关系模型的一致性。该JMX规范关系模型的实现提供了一个灵活的设计由此关系类型和实例可以是关系的内部或外部服务。
内部关系类型和实例由关系服务创建并且仅可以通过其操作访问。 代表类型和关系的对象内部不能被用户访问。 外部关系类型和实例是在关系服务之外实例化并在其控制下添加的对象。用户可以以任何设计的方式访问这些对象,其中包括作为注册的MBean。
关系服务维护一个可用于定义的关系类型列表新的关系。关系类型必须在内部创建或外部实例化并在可用于定义关系之前将其添加到关系服务中。
表示外部关系类型的对象必须实现RelationType接口。关系服务依赖于它的方法来访问角色信息每个角色由外部对象定义。请参阅“RelationTypeSupport类”有关用于定义外部关系类型的类的描述,请参阅第181页。
关系类型是不可变的,意味着一旦它们被添加到关系中服务,他们的角色定义不能被修改。如果外部关系类型暴露用于修改角色信息集的方法,它们不应该由其调用在关系服务的控制下添加实例后的用户。该这样做的结果是未定义的,关系服务中的一致性是否定的更长的保证。
使用外部关系类型的好处是角色信息可以例如,在类构造函数中静态定义。这允许预定义的类型
被快速实例化,然后添加到关系服务中。
一旦它被添加到关系服务中,就可以使用外部关系类型创造内部和外部关系。外部关系类型也是以与内部关系类型相同的方式从关系服务中删除相同的后果(请参阅第177页的“RelationService类”)
关系服务还维护它所控制的关系的列表。内部关系是通过关系服务创建的,只能通过其关系服务来访问方法。外部关系是由用户实例化并在其下添加的MBean关系服务的控制。它们必须在MBean服务器中注册然后才能将其添加到关系服务中。他们都可以通过关系服务以及通过MBean服务器。
外部关系对象必须实现定义该关系的Relation接口关系服务用来访问其角色值的方法。外部关系是还负责维护自己的一致性,只允许访问它的角色值由其关系类型描述。最后,外部关系必须告知任何角色值被修改时的关系服务。
关系服务对象公开检查角色信息的方法更新其内部角色值。外部关系对象必须被设计为适当时调用这些。不这样做会导致不一致的关系服务的行为之后未定义。
外部关系的主要好处是能够提供返回的方法有关关系成员的信息,甚至是角色值。因为外部关系也是一个MBean,它可以选择公开这些方法作为属性和操作。
返回到第170页上的“关系示例”,图书所有权关系可以由仅包含角色书籍的一元关系类型表示。关系
将通过外部的所有者MBean的实例来实现关系服务。这个MBean可以有一个属性,如bookCount和诸如买卖之类的操作都适用于当前的成员关系。
有关外部关系的示例,请参见第182页的“RelationSupport类”。
关系服务在RelationService对象中实现,这是一个标准由RelationServiceMBean接口定义的MBean。 因此可以从管理应用程序远程访问和管理。
……
FIGURE 11-3 Relation Service Classes
关系服务MBean是通知广播者并且是唯一要发送的对象RelationNotification对象。 为了保持一致性,它还会监听MBean通过MBeanServerNotificationFilter对象的服务器通知。
关系服务提供了创建和删除关系类型和方法的方法关系实例以及访问关系中的角色。它也暴露了方法查询关系及其成员以找到相关的MBeans。
有两种方法来定义关系类型:
removeRelationType方法删除内部或外部关系类型。使用removeRelation方法将删除该类型的所有关系(请参阅第171页的“维护一致性”)。
removeRelation方法从关系服务中删除关系,这意味着它不能再被访问。成员MBeans中的角色关系继续存在。当外部关系被删除时,MBean实现它仍然可以在MBean服务器中使用。删除关系触发关系通知。
关系服务提供了访问由其标识的关系类型的方法独特的名称:getRoleInfo和getRoleInfos。
它提供了访问关系及其角色值的方法。所有角色的访问权限受限于关系类型中定义的访问模式和一致性检查,尤其是对于设置角色值:getRelationTypeName,getRole,getRoles,getAllRoles,getReferencedMBeans,setRole和setRoles。设置角色将会触发关系更新通知。
还有确定内部和外部关系的方法:
findRelationsOfType方法返回所有的关系标识符
给定关系类型的关系。
为了保持一致性,关系服务监听注销通知来自MBean服务器委托。 当有外部关系时会通知它MBean是未注册的,在这种情况下,关系被删除,或者MBean该关系的成员是未注册的(请参阅“维护一致性”第171页)。 purgeRelations方法将检查所有关系数据的一致性并删除所有不再有效的关系。
每次收到相关的撤销注册通知时,关系服务行为取决于清除标志属性:
关系服务还公开允许外部关系MBean的方法实现预期的行为,或通知关系服务,以便它可以保持一致性:
这个类的一个实例被创建并在关系时作为通知广播创建,添加,更新或删除。它定义了两个单独的通知类型这些事件中的每一个都取决于事件是关于内部还是事件外部关系。这个类的静态字段描述了所有的通知类型字符串关系服务可以发送(参见第176页的图11-3)。
此类的方法允许侦听器检索有关事件的信息:
这个类被关系服务用来只接收那些通知涉及作为角色成员或外部关系实例的MBean。 它过滤基于它们的对象名称的MBean,确保关系服务将只有接收有关MBeans的注销通知。
其方法允许关系服务在必须添加或更新过滤器时更新过滤器删除关系中的MBean或表示外部关系。
关系服务使用的过滤器实例未公开用于管理关系服务。 这个类在这里被描述,因为它是可用的一部分javax.management.relation包并可以在其他地方重用。
外部关系类型和关系实例依赖于在中定义的接口下图,可以选择扩展支持类以方便使用。JMX规范的实现也可以在内部依赖这些类。
……
FIGURE 11-4 Interfaces and Support Classes
关系类型的任何外部表示都必须实现RelationType界面被关系服务认可。 这个接口的方法公开关系类型的名称及其角色信息(请参阅“RoleInfo类”)。
关系服务调用此接口的方法来访问关系类型名称或角色信息。 因为关系类型是不可变的,所以返回在关系类型用关系注册时,值永远不会改变服务。
实现此接口的对象的实例可以作为外部添加关系类型,使用关系服务的addRelationType方法。提供它的实现是连贯的,它可以通过关系来访问服务方式与内部关系类型相同。 事实上,内部关系类型通常由也实现此接口的对象表示
这个类实现了RelationType接口并提供了一个通用的代表任何关系类型的机制。关系类型的名称是作为参数传递给类构造函数。
有两种方法通过一个实例定义一个特定的关系类型RelationTypeSupport类:
在使用此类的实例之后,不能添加角色信息在关系服务中定义一个外部关系类型。
用户也可以扩展这个类来创建自定义关系类型,而不需要重写角色信息访问方法。例如,。的构造函数子类可以确定要传递给超类的RoleInfo对象构造函数。这有效地将一个关系类型定义封装在一个可以的类中被动态下载和实例化。
关系服务的实现通常会实例化RelationTypeSupport类来定义内部关系类型,但这些对象是外部无法访问。
Relation界面描述了一个类的支持的操作预计实例将代表关系。 通过这个接口的方法,实现类公开了访问关系所需的所有功能。
实现Relation接口以表示外部关系的类必须装备为MBean。 该对象必须实例化并注册在它可以被添加到关系服务之前,在MBean服务器中。 那么,它可以通过关系服务或通过任何管理访问它在MBean服务器中公开的接口。
每个关系在关系服务中通过一个唯一的关系标识符进行标识通过getRelationId方法暴露。它返回的字符串必须是在服务注册时所有关系中都是独一无二的。关系服务将拒绝添加具有重复或空标识符的外部关系。
以同样的方式,getRelationTypeName方法必须返回一个有效的关系类型名称已在关系服务中定义。外部关系实例还必须知道它将被控制的关系服务对象:这可以通过getRelationServiceName方法进行验证。这种方法返回一个假定在与MBean相同的MBean服务器中有效的对象名称外部关系实施。
关系服务使用Relation界面的其他方法进行访问一个关系在其控制下的角色。角色值可以被读取或写入单独或批量使用(请参阅第181页的“角色描述类”)。个人无法访问的角色会导致其类指示其性质的异常该错误(请参阅第157页的图11-2中的异常类)。
用于批量角色访问的方法遵循“尽力而为”策略:访问所有指示尝试角色,无法访问的角色不会阻止该操作。那些由于输入错误或由于访问而无法访问的该角色的权利将返回一个未解决的角色对象,指示该角色的性质错误(请参阅“RoleUnresolved类”一节第187页)。
getReferencedMBeans方法返回所有MBean的对象名称列表在关系中引用,每个对象名称映射到其中的角色列表MBean是一个成员。
关系服务委托维护角色一致性的责任关系对象。 通过这种方式,可以在角色执行一致性检查通过外部关系的方法访问。 但是,关系服务必须通知任何角色修改,以便它可以更新其内部数据结构并发送通知。
在访问角色时,无论是获取或设置其值,关系实例都必须验证:
Relation接口的实现可以依靠checkRoleReading和提供给关系服务MBean的checkRoleWriting方法简化上述验证。
设置角色后,外部关系必须调用updateRoleMap操作关系服务,提供新老角色价值。这允许关系服务来更新其内部数据以保持一致性。
关系服务必须被告知所有新的角色值,以便它可以监听一个取消注册有关任何成员MBean的通知。当一个成员外部关系的MBean从MBean服务器(即关系)中注销服务检查它满足的角色的新基数。
如果基数不再有效并且清除标志为真,则关系服务删除此关系实例(请参阅“RelationService类”(第165页))。如果外部关系依然有效,关系服务称之为外部关系handleMBeanUnregistration方法。
在调用时,此方法将MBean从其引用的角色中移除(因为所有角色成员都必须注册MBean)。关系的保证服务将在必要时调用此方法以释放外部关系听取MBean注销本身。它也允许关系实现定义如何更新相应的角色。例如,取消注册一个给定角色的MBean可以更新其他角色。
在这种情况下,以及在暴露的方法修改角色值的任何其他情况下,实现使用自己的setRole方法或调用适当的关系服务方法,比如updateRoleMap。这是所有实现的责任Relation关系接口也维护其关系实例的一致性作为关系服务的角色价值。
这个类是Relation接口的完整实现,它提供了一个通用关系机制。这个类必须用一个有效的角色列表实例化定义它将表示的关系实例。构造函数也需要一个唯一的关系标识符,以及由该满足的现有关系类型的名称给出角色列表。
事实上,RelationSupport类实现了RelationSupportMBean扩展了Relation界面。这意味着它也是一个标准的MBean管理界面暴露了所有的关系访问方法。因为外部关系必须首先在MBean服务器中注册,外部实例关系支持类可以由远程应用程序管理。
用户还可以扩展RelationSupport类以利用它的优势在开发定制的外部关系时实施。用户也可以选择扩展其MBean接口以公开其他属性或操作访问关系。此自定义仍必须保持角色的一致性访问和角色更新,但它可以使用内置的一致性机制RelationSupport类的方法。
关系服务通常实例化RelationSupport类来定义内部关系实例,但这些对象不能从外部访问。
关系服务访问阅读和写作关系的角色值。 JMX规范定义了用于传递角色值的类参数并将其作为结果接收。 这些类也被外部使用实现关系行为的关系MBean。
……
FIGURE 11-5 Role Description Classes
角色信息提供角色的元数据描述。它规定:
当角色信息被用作新的关系类型的参数时,它是定义角色的信息。当关系类型在关系中声明时服务,对于每个角色,该服务将验证:
Role类的一个实例表示关系中角色的值。 它包含角色名称和引用现有MBean的对象名称列表。
角色值必须始终满足其关系类型的角色信息。 角色名称是将角色值与其定义的角色信息相关联的关键。
Role类用作两个关系的setRole方法的参数服务和关系接口。 它也是使用的列表的组成部分批量设置方法和定义初始角色值。 对于每个角色初始化或更新,关系服务验证:
该类扩展java.util.ArrayList以表示一组Role对象。
RoleList类的实例用于定义关系的初始值。 什么时候调用关系服务的createRelation方法,承认a的角色0的基数可以从角色列表中省略。 关系类型的所有其他角色在初始角色列表中必须具有格式良好的角色值。
角色列表对象也被用作两者的setRoles方法的参数关系服务和关系接口。 这些方法仅为其设置角色一个有效的角色值出现在角色列表中。
最后,所有批量访问方法都会返回包含RoleList对象的结果代表成功访问的角色。
此类的实例表示对给定的读取或写入访问不成功在关系中的作用。 它仅用于角色访问方法的返回值关系服务或实现Relation关系的对象。
该对象包含:
该类扩展java.util.ArrayList以表示一组RoleUnresolved对象。 所有批量访问方法都会返回包含RoleUnresolvedList的结果表示无法访问的角色的对象。
RoleResult类是所有批量访问方法的返回对象关系服务和Relation界面的实现。 角色结果包含角色及其值的列表,以及未解决的角色列表和原因每个都无法访问。
作为getter的结果,角色值包含请求的当前值角色。 未解决的列表包含无法读取的角色,可能是因为角色名称无效或角色不允许阅读。
作为setter的结果,角色值包含那些角色的新值手术成功了。 未解决的列表包含不可能的角色书面,出于任何访问或一致性原因。
这个类包含静态字段,给出未解决角色的可能错误代码。错误代码与访问权限或一致性检查相关。该这些字段的名称标识了问题的性质,如图11-5所示第185页。
Java管理扩展(JMX)MBean服务器可能有权访问敏感数据库信息,并可能能够执行敏感操作。 在这种情况下,它是希望控制谁可以访问那些信息以及谁可以执行这些信息操作。 JMX规范建立在标准的Java安全模型上定义控制对MBean服务器及其操作的访问权限。
本章介绍的安全检查仅在存在安全检查时执行安全经理。 也就是说,如果System.getSecurityManager()返回null,那么不执行检查。
假设读者对Java安全模型有一定的了解。一个出色的参考资料是李功的Inside Java™2平台安全性(Addison Wesley,1999年)。文档也可作为Java 2平台标准的一部分在线提供版(J2SE)标准开发工具包(SDK)。
敏感操作需要权限。在执行这样的操作之前,a执行检查以确保主叫方具有所需的权限或权限。
在程序执行过程中的任何一点,都有一组当前的执行线程持有的权限。当这样的线程调用JMX时规范操作,我们说这些是持有的权限。
执行安全检查的操作通过定义所需的权限来实现。如果持有的权限意味着需要的权限,则允许该操作。那是,至少有一个持有许可必须暗示需要的许可。
权限是一个Java对象,它是java.security.Permission的子类。这个类定义了以下方法:
public boolean implies(Permission permission);
持有的持有许可意味着需要所需的许可
held.implies(needed).
例如,要调用MBeanServerFactory.createMBeanServer,需要一个线程许可
MBeanServerPermission(“createMBeanServer”)
以下是一个线程可以容纳的一些权限,意味着需要权限:
不具有任何这些权限的线程,或任何其他权限暗示需要的一个,将无法调用createMBeanServer。 试图这样做会导致SecurityException。
JMX 1.2规范定义了三个权限:
这些权限在以下各节中进行介绍。
MBeanServerPermission控制对类的静态方法的访问javax.management.MBeanServerFactory。 (请参阅“MBean Server Factory”)MBeanServerPermission由单个字符串构成参数,而权限对象的含义取决于这个字符串,如下:
为了方便定义权限,可以使用两个或多个字符串结合在一个逗号分隔的列表中。 由此产生的权限意味着所有的列表中的操作。 因此,举例来说,持有MBeanServerPermission(“newMBeanServer,findMBeanServer”)是相当于同时拥有MBeanServerPermission(“newMBeanServer”)和MBeanServerPermission(“findMBeanServer”)。
持有MBeanServerPermission(“*”)等同于持有所有上面列表中的权限。
MBeanPermission控制对MBeanServer对象的方法的访问由MBeanServerFactory.createMBeanServer或MBeanServerFactory.newMBeanServer。 (请参阅第7章“MBean服务器”。)
MBeanPermission使用两个字符串参数构造。 首先参数通常被称为权限的名称,但我们在这里指它作为目标。 第二个参数是权限的行为。
MBeanPermission的目标将三条信息分组在一起,每一个都可以省略:
如果全部三个项目都存在,则持有的MBeanPermission只意味着需要的权限比赛。
如果所需的权限具有空类名称,则类名称与该类型无关行动被检查,所以持有的权限将匹配,无论其类名。
如果持有的权限具有空的类名称,则表示该权限涵盖任何类名称,所以无论其类名是什么,所需的权限都会匹配。
同样的规则适用于成员和对象名称。
目标中的三个项目使用以下语法编写为单个字符串:
className#member[objectName]
这三项中的任何一项都可以省略,但至少有一项必须存在。
三个项目中的任何一个都可以是字符“ - ”,表示空项目。空项目与空项目不同。举个例子,一个空的类名权限与“*”相同并表示任何类名。一个空的类名所需的权限被任何类名所隐含。所需的许可从来没有空的类名称,通常拥有的权限永远不会有空类名称。
以下是一些具有其含义的目标示例:
MBeanPermission的操作字符串表示一个或多个方法MBeanServer接口。 并非该接口中的所有方法都是可能的值操作字符串。 完整的清单如下:
……
以下MBean服务器方法不受权限检查:
MBeanPermission的queryMBeans和queryNames操作允许控制其中MBean对查询可见。 queryMBeans操作继续如下:
queryNames操作的规则与刚才陈述的完全相同,但与由queryNames替换queryMBeans。
有了这些规则,线程拥有的权限将完全控制集合线程可以通过查询看到的MBean。
所持有的权限未涵盖的MBeans是很重要的在执行查询之前从集合中删除。 换句话说,步骤3必须发生在第4步之前。否则,恶意代码可能会执行QueryExp界面将每个MBean保存在某个选定的集合中。
getDomains权限筛选关于MBean名称的信息对于线程可见,与queryMBeans和queryNames类似。该
线程的持有权限应该暗示:
MBeanPermission(“ - # - [ - ]”,“getDomains”)
否则,MBeanServer.getDomains()方法会抛出一个SecurityException异常。否则,MBean服务器首先获取域的列表如果没有安全检查,并且每个域d都会返回该列表检查所持有的权限意味着:
MBeanPermission(“ - # - [d:x = x]”,“getDomains”)
否则,该域将从列表中消除。
x = x是ObjectName工作方式的工件。一个实现可以使用任何其他关键=值的可能性,而是必须有一个。
定义持有权限时,例如在安全策略文件中,getDomains权限应始终忽略ObjectName或提供在关键属性中只有一个的ObjectName模式,比如“:*”,
“com.example。:”或“com.example.visible:*”。
用于查询的类似方案用于getAttributes和setAttributes操作。 getAttributes操作按如下进行:
setAttributes操作的规则与刚才陈述的完全相同,但是将getAttribute(s)替换为setAttribute(s)。
此许可表示签署者或代码源中的“信任”。 如果签署者或codesource被授予此权限,因此它被认为是MBeans的可信来源。只有来自可信来源的MBean才能在MBean服务器中注册。
结合MBeanPermission,MBeanTrustPermission可以实现细粒度的控制哪些MBean在MBean服务器中注册。该MBeanPermission的registerMBean操作控制哪些实体可以注册的MBean。 MBeanTrustPermission控制他们可以注册的MBean。
MBeanTrustPermission由单个字符串参数构造而成。 在这JMX规范的版本,参数可以有两个可能的值:
这两个值具有相同的含义,但是如果在将来的JMX版本中说明其他可能性,“*”将涵盖所有这些。
MBeanTrustPermission检查的详细信息如下所示例。
让c是要通过MBean服务器在MBean服务器中注册的MBean的Java类createMBean或registerMBean方法,并且让p成为构建的许可如下:
p = new MBeanTrustPermission(“register”);
然后,为了使createMBean或registerMBean成功,请执行以下操作表达必须是真实的:
c.getProtectionDomain()。暗示(p)的
否则,抛出SecurityException。
以下是前面介绍的权限的一些示例可以使用标准的Java策略文件语法来授予章节。
最简单的MBean访问策略是授予所有签名者和代码库访问权限的MBean:
grant {
permission javax.management.MBeanPermission “*”, “*”;
};
这是一个更严格的策略,它授予appl1.jar中的代码许可权获取MBean服务器的类加载器存储库:
grant codeBase “file:${user.dir}${/}appl1.jar” {
permission javax.management.MBeanPermission ““,
“getClassLoaderRepository”;
};
这是一个授予appl2.jar代码调用权限的策略来自任何类的MBean的isInstanceOf和getObjectInstance操作,只要它们在域“d1”中注册:
grant codeBase “file:${user.dir}${/}appl2.jar” {
permission javax.management.MBeanPermission “[d1:*]”,
“isInstanceOf, getObjectInstance”;
};
这是一个授予appl3.jar中代码查找MBean权限的策略服务器,并调用queryNames操作,但限制返回的设置域“JMImplementation”中的MBean:
grant codeBase “file:${user.dir}${/}appl3.jar” {
permission javax.management.MBeanServerPermission
“findMBeanServer”;
permission javax.management.MBeanPermission
“JMImplementation:*”, “queryNames”;
};
如果MBean服务器具有其他域中名称的MBean,例如一个MBean注册为“com.example.main:type = user,name = gorey”,他们会从不出现在由appl3.jar中的代码执行的queryNames的结果中。
这是一个授予appl4.jar代码创建权限的策略在任何对象名称下操作类“com.example.Foo”的MBean:
grant codeBase “file:${user.dir}${/}appl4.jar” {
permission javax.management.MBeanPermission
“com.example.Foo”, “instantiate, registerMBean”;
permission javax.management.MBeanPermission
“com.example.Foo#doIt”,
“invoke,addNotificationListener,removeNotificationListener”;
};
第一个权限忽略对象名称。 操作或属性名称不是这两项行动所要求的。
然而,第二个权限使用“调用”操作的成员部分忽略它的“add / removeNotificationListener”操作。
这是一个允许MBeans注册的策略,不管它们来自哪里从。 (注册MBeans的线程也必须具有相应的权限MBeanPermissions。)
grant {
permission javax.management.MBeanTrustPermission “register”;
};
这是一个只信任由“Gorey”签名的MBean的策略:
grant signedBy “Gorey” {
permission javax.management.MBeanTrustPermission “register”;
};