搜索
您的当前位置:首页WAS管理编程常用技巧

WAS管理编程常用技巧

来源:飒榕旅游知识分享网
WebSphere Application Server 管理编程简述

WebSphere Application Server(以下简称为WAS)提供了两种管理途径: 基于Web方式的管理控制台和基于命令行方式的 wsadmin 工具;

还可以通过管理编程接口(WebSphere Management API)来开发符合特定需求的管理应用

WAS 的管理体系是基于 JMX 规范的,JMX 规范定义了三层结构:

Distributed layer:包含各种适配器,使得使用不同协议 ( 如 RMI,HTTP ) 的管理应用能访问代理层。

Agent layer:包含 Mbean Server,是 Mbean 的注册中心,操纵各种 Mbean 并对外提供各种管理服务,如监控,定时任务,Mbean 的动态加载等。

Instrumentation layer:包含各种 Mbean,Mbean 实现对资源的访问和代表了资源状态。 图 1.JMX 规范的三层结构示例

JMX 即 Java Management Extensions Java管理扩展 MBean 即 managed beans 被管理的Beans

一个MBean是一个被管理的Java对象,有点类似于JavaBean,一个设备、一个应用或者任何资源都可以被表示为MBean,MBean会暴露一个接口对外,这个接口可以读取或者写入一些对象中的属性,通常一个MBean需要定义一个接口,以MBean结尾, 例如: EchoMBean, 格式为XXXMBean,这个是规范,必须得遵守。描述一个可管理的资源。

是一个java对象,遵循以下一些规则:

1.必须是公用的,非抽象的类 2.必须有至少一个公用的构造器

3.必须实现它自己的相应的MBean接口或者实现javax.management.DynamicMBean接口 4.可选的,一个MBean可以实现javax.management.NotificationBroadcaster接口MBean的类型。

WAS 的管理体系,如图 -2 所示: 图 2.WAS 的管理体系

本文主要介绍上图中 custom client 的编程。管理编程分为下面两种途径: 1.直接调用 Mbean

2.使用 WAS 的管理编程接口

WebSphere JMX Mbeans Mbeans 介绍

WAS 提供了各种类型的 Mbean, 封装了各种管理功能,如对 WAS 系统环境,J2EE 应用,J2EE 资源等的管理和监控。

获得某个 Mbean:每个 MBean 都有一个 ObjectName,在使用该 MBean 之前必须先找到它。ObjectName 可以通过 AdminClient,以格式化的查询串进行查询。格式化的查询串可以选择性地包括以下的特性:域名、节点名、进程名、类型、名称等等。 一个查询串既可惟一标识单个 ObjectName,也可以代表多个具有公共特性的 ObjectName。MBean 通常是以它们的类型进行分类的。 一些 MBean 类型(例如 Perf)会在应用服务器中提供单个的

实例,但其他 MBean 类型(例如 servlet 和 EJB)会在应用服务器中提供多个实例。

清单 1. 获得某个 server 上的类型为 JVM 的 MBean

String query = “*:type=JVM,process=server1,node=node1,*\"” ; queryName = new ObjectName(query);

Set mBeans = null; try {

mBeans = adminClient.queryNames(queryName, null); } catch (ConnectorException e) { e.printStackTrace(); }

我们也可以基于 JMX connector specification 和 JMX Remote application programming interface (API) (JSR 160) 来访问 Mbean。 参见 WAS 信息中心文章 “Create a JMX remote client program by using the JMX remote API”。

在一个 WAS Network Deployment 环境中,我们可以通过 AdminClient 连接到 dmgr,也可以直接去连接某个 nodeagent 或 server。 如果我们连接的是 dmgr ,那么通过 dmgr 去访问 nodeagent 和 server 上的 MBean 时,前提条件是这个 nodeagent 或 server 必须是启动的。

访问 Mbean 的属性和方法 我们知道,调用 EJB 或 Web service 最终都要通过 Java 接口来进行, 但 Mbean 却不同。调用 Mbean 的方法与 java 反射机制类似,要提供方法名称,方法的参数类型,最后才能 invoke 该方法。

访问 Mbean 的普通属性:

清单 2. 访问 Mbean 的普通属性

Object heapsize = adminClient.getAttribute(mbean, \"heapSize\") ; 调用 Mbean 的方法:

清单 3. 调用 Mbean 的方法

ObjectName jvmBean = MBeanFactory.getInstance().getJVMMBean (server.nodeName, server.serverName) ; String signature[] = { \"java.lang.String\" };

server.hostIP = (String)adminClient.invoke(jvmBean, \"getIPAddress\ new Object[]{server.hostName}, signature) ;

WebSphere management API

WAS 提供的管理编程接口包含在以 com.ibm.websphere.management 开头的包中。下面介绍一下包中的实用 API。

AdminClient 和 AdminService

AdminClient 用于连接远程的 JVM,AdminService 用于连接本地 JVM,如果你的管理代码运行在和被管理的服务器相同的 JVM 内,那可以使用 AdminService 接口。AdminService 具有和 AdminClient 类似的方法,也能访问服务器上的 Mbean。 下面是获得 AdminClient 接口的代码: 清单 4. 获得 AdminClient 接口的代码 Properties props = new Properties();

props.put(AdminClient.CONNECTOR_TYPE, AdminClient.CONNECTOR_TYPE_SOAP); props.put(AdminClient.CONNECTOR_HOST, host.getHostIP()); props.put(AdminClient.CONNECTOR_PORT, host.getSoapport());

props.put(AdminClient.CONNECTOR_AUTO_ACCEPT_SIGNER, true);

if (isSecurityEnabled()) {

props.setProperty(AdminClient.CONNECTOR_SECURITY_ENABLED, Boolean.toString(true));

props.setProperty(AdminClient.USERNAME, host.getUsername()); props.setProperty(AdminClient.PASSWORD, host.getPasswd()); }

AdminClient 既可以运行在 admin thin client 中,也可以运行在 WAS server runtime 中。 获得 AdminService 接口 :

清单 5. 获得 AdminService 接口的代码

AdminService adminService = AdminServiceFactory.getAdminService() ;

Wsadmin API 和 management API 之间的对应关系

WAS 命令行脚本工具提供了几个管理对象 AdminApp, AdminTask, AdminConfig, AdminControl。它们分别对应不同的管理 API: 1. AdminApp:

AdminApp 对象的功能对应于两个包 com.ibm.websphere.management.application 和

com.ibm.websphere.management.application.client。 通过这两个包下面的 API,我们可以安装 / 卸载,启动 / 停止一个 J2EE 应用。和应用管理相关的编程比较固定,本文没有过多介绍这些 API 的使用,读者可以参考本文提供的例子 ApplicationMgr.java,里面包含了应用安装和启停的示例。

2. AdminControl: AdminControl 汇集了一些常用的 Mbean 的功能,如 Server Mbean。此外,它能直接调用任何一个 Mbean 对象。所以, AdminControl 提供的功能可以由 AdminClient/AdminService 来替换。

3. AdminConfig: AdminConfig 对象对应于两个包 com.ibm.websphere.management.configservice 和 com.ibm.websphere.management.configservice.tasks。

4. AdminTask: AdminTask 对象对应于两个包 com.ibm.websphere.management.cmdframework 和 com.ibm.websphere.management.cmdframework.provider。

本文主要介绍 AdminConfig 和 AdminTask 对应的管理编程。 使用 ConfigService

WAS 的配置信息有些可以通过 Mbean 去获得,如 cell/node/server 的名称,也可以通过 ConfigServer 去获取。而有些配置信息只能通过 ConfigService 去获得。 下面是使用 ConfigService 时会遇到的几个概念:

ConfigData :config data 对应于 config 目录下的某个 xml 文件或 xml 文件的某个片段,通过操纵 config data,就可以读写该 xml 文件。

ConfigType :config data 的类型。首先要知道你要访问配置信息的类型才能去访问。 通过 configService 的 getSupportedConfigObjectTypes() 方法可以获得所有的 ConfigData 的类型信息。例如我们要获得 WAS 上所有的数据源的配置信息,通过查找上述类型列表,可以知道数据源的 ConfigType 为 DataSource。 ConfigData Id :ConfigData 的唯一标识。 如何访问某个 ConfigData ?

通过 ConfigData type 来查询 ConfigData 通过 ConfigDataId 来创建 ConfigData

ConfigData 和 ConfigDataId 的关系如下:

清单 6. ConfigData 和 ConfigDataId 的转换关系 // 获得 ConfigData 的 ConfigDataId

ConfigDataId configDataId = ConfigServiceHelper.getConfigDataId(configData) ;

// 已知 ConfigDataId,得到其 ConfigData

public ObjectName createConfigData(String dataId) { ObjectName configData = null ;

ConfigDataId id = new ConfigDataId(dataId) ;

configData = ConfigServiceHelper.createObjectName(id) ; return configData ; }

使用 ConfigService 获得环境信息

下面举例说明如何用 MBean 和 ConfigService 获取集群信息,方便读者的对比。关于更多其它环境信息的获取,读者可以参考本文例子 WASEnvHelper.java。 清单 7. 通过 MBean 获得所有集群及集群成员 public void listClusterMembersFromMBean() {

Set clusters = queryMBeanList(\"WebSphere:type=Cluster,*\") ; Iterator ci = clusters.iterator() ;

String signature[] = { \"java.lang.String\" }; while (ci.hasNext()) { ObjectName cluMBean = (ObjectName) ci.next(); try { String clustername = cluMBean.getCanonicalName(); clustername = (String)adminClient.getAttribute(cluMBean, \"clusterName\") ;

System.out.println(clustername); ClusterMemberData[] membersData = (ClusterMemberData[])adminClient.invoke(cluMBean, \"getClusterMembers\ for (ClusterMemberData clusterMemberData : membersData) { System.out.println(clusterMemberData.memberName); } } catch (Exception e) { e.printStackTrace() ; } }

清单 8. 通过 ConfigService 获得所有集群及集群成员

public HashMap listClusterMembersFromCfg() { HashMap map = new HashMap() ; ObjectName pattern = ConfigServiceHelper.createObjectName(null, \"ServerCluster\"); try { ObjectName[] configData = configService.queryConfigObjects(session, null, pattern , null); for (int i = 0; i < configData.length; i++) { List members = new ArrayList() ; String clustername = (String)configService.getAttribute(session , configData[i] , \"name\") ; List _members = (ArrayList) configService.getAttribute( session, configData[i], \"members\"); for (AttributeList member : _members) { String name = (String)ConfigServiceHelper.getAttributeValue( member , \"memberName\") ; members.add(name) ; } map.put(clustername, members) ; } } catch (Exception e) { e.printStackTrace() ; } return map ; }

创建新的配置

创建配置的难点在于确立 AttributeList 的结构,尤其是对于嵌套复杂的 AttributeList,往往需要先写个读取的程序来判断里面每个对象的类型。下面是创建 JDBC Provider 和 Datasource 的实例。注意,在不同的 scope 下都有 resources.xml,所以在查询 resources.xml 中的 ConfigData 时要先确定 scope。

清单 9. 通过 ConfigService 获得所有集群及集群成员

public void createJDBCResource(AdminClient adminClient) { Session session = new Session(); ConfigService configService = null ; try {

configService = new ConfigServiceProxy(adminClient);

ObjectName scope = configService.resolve(session, \"Node=kuNode05:Server=server1\")[0];

ObjectName pattern = ConfigServiceHelper.createObjectName(null, \"JDBCProvider\"); ObjectName[] configData = configService.queryConfigObjects(session, scope, pattern , null);

ObjectName parent = configData[0] ; System.out.println(parent);

AttributeList provAttrs = new AttributeList();

provAttrs.add(new Attribute(\"name\ provAttrs.add(new Attribute(\"implementationClassName\ com.mycompany.MyConnectionPoolDataSource\"));

provAttrs.add(new Attribute(\"description\

//create the provider

ObjectName jdbcProv = configService.createConfigData(session, scope, \"JDBCProvider\ \"JDBCProvider\

System.out.println(\"create the JDBC provider successfully.\"); configService.addElement(session,jdbcProv,\"classpath\

// Prepare the attribute list

AttributeList dsAttrs = new AttributeList();

dsAttrs.add(new Attribute(\"name\

dsAttrs.add(new Attribute(\"jndiName\

//create a new datasource

ObjectName dataSource = configService.createConfigData(session, jdbcProv, \"DataSource\

// Add a propertySet.

AttributeList propSetAttrs = new AttributeList();

ObjectName resourcePropertySet = configService.createConfigData(session,dataSource, \"propertySet\

System.out.println(\"create the DataSource successfully.\");

configService.save(session, false); } catch (Exception ex) { ex.printStackTrace(); } }

修改已有配置

下面的 updateAttributelist 是一个通用的方法,相对于设置好 Attributelist 里的值之后做一个提交。

清单 10. 提交更新的通用方法 // 设置新的属性值

ConfigServiceHelper.setAttributeValue(threadpool, \"minimumSize\ new Integer((int)pool.getMinSize())) ;

ConfigServiceHelper.setAttributeValue(threadpool, \"maximumSize\ new Integer((int)pool.getMaxSize())) ; // 更新整个 Attributelist

updateAttributelist(threadpool) ;

public void updateAttributelist(AttributeList attrs) { try {

ConfigDataId id = ConfigServiceHelper.getConfigDataId(attrs) ;

ObjectName objectName = ConfigServiceHelper.createObjectName(id) ; configService.setAttributes(session, objectName, attrs) ; }catch (Exception e) e.printStackTrace() ; } }

修改 ConfigData 的属性。修改 configdata 的某个属性时,需要先判断该属性的数据类型。最简单的办法是打印出该 configdata 的信息: 采用 System.out.println(obj); 和

System.out.println(obj.getClass().getName()); 即可。如果数据类型为 ObjectName,说明该属性值指向另一个 configdata,那我们在设置该属性的 value 之前, 需要先查询到那个 configdata。

清单 11. 修改 ConfigData 的属性

ObjectName pattern = ConfigServiceHelper.createObjectName(null, \"Security\"); ObjectName[] configData

= configService.queryConfigObjects(session, null, pattern, null);

String curID =\"\"; String ltpaID = \"\";

for (int i = 0; i < configData.length; i++) { System.out.println(configData[i]);

Object obj = configService.getAttribute(session , configData[i], \"activeAuthMechanism\") ;

Object id = ConfigServiceHelper.getConfigDataId((ObjectName)obj) ; System.out.println(id);

//configService.getAttributes(session, configData[i], \"activeUserRegistry\

System.out.println(obj);

System.out.println(obj.getClass().getName());

AttributeList enableSecurity = new AttributeList();

ObjectName pattern1 = ConfigServiceHelper.createObjectName(null, \"CustomUserRegistry\"); ObjectName[] configData1 = configService.queryConfigObjects(session, null, pattern1, null);

//System.out.println(configData1[0]);

ObjectName d = createConfigData(configDataId) ;

enableSecurity.add(new Attribute(\"activeUserRegistry\ enableSecurity.add(new Attribute(\"cacheTimeout\ enableSecurity.add(new Attribute(\"enabled\ enableSecurity.add(new Attribute(\"appEnabled\

updateAttributelist(enableSecurity); }

configService.save(session, false); 使用 Command Framework

WAS 大量的管理功能包含在 wsadmin 的 AdminTask 对象中。WAS 提供了 command framework programming API,可以帮助我们开发等价于 AdminTask 脚本功能的程序。cmdframework 的命令名称通常就是 AdminTask 的方法名称,命令的参数与 AdminTask 方法的参数也一致,但需要做类型转化,即将 AdminTask 中 python 的数据类型转化成 Java 的数据类型,这种对应关系并不难确立。此外还需要注意一个 AdminTask 中是否包含 CommandStep ,可以通过 listCommandSteps() 检查 。

清单 12. 为指定的 role 分配用户组的 wsadmin 脚本

AdminTask.mapGroupsToNamingRole('[-roleName CosNamingWrite -specialSubjects [EVERYONE ]]') AdminConfig.save()

清单 13. 将上述 wsadmin 脚本转化为 Java 编程

// 下面的 import 实际上列出了 cmdframework 管理编程的常用类 import com.ibm.websphere.management.AdminClient;

import com.ibm.websphere.management.AdminClientFactory; import com.ibm.websphere.management.Session;

import com.ibm.websphere.management.cmdframework.AdminCommand;

import com.ibm.websphere.management.cmdframework.CommandMgr; import com.ibm.websphere.management.cmdframework.CommandResult; import com.ibm.websphere.management.cmdframework.CommandStep; import com.ibm.websphere.management.cmdframework.TaskCommand; import com.ibm.websphere.management.async.client.AsyncCommandClient;

public class CmdFrameworkSample { public static void main(String args[]) { AdminClient adminClient ; // 获得 adminClient

CommandMgr cmdMgr = CommandMgr.getClientCommandMgr(adminClient); // 创建一个异步通知监听器

AsyncCmdTaskHandler listener = new AsyncCmdTaskHandler(); String cmdName = \"mapGroupsToNamingRole\";

AdminCommand cmd = cmdMgr.createCommand(cmdName); cmd.setConfigSession(session);

cmd.setParameter(\"roleName\

cmd.setParameter(\"specialSubjects\ asyncCmdClientHelper.processCommandParameters(cmd); // Call the asynchronous command client to run the command. asyncCmdClientHelper.execute(cmd);

// Check the command result.

CommandResult result = cmd.getCommandResult(); if (result != null) {

if (result.isSuccessful()) {

System.out.println(\"Modified the CosNamingRole successfully.\"); }else { } }

ConfigService configService = new ConfigServiceProxy(adminClient); configService.save(session, false); } }

清单 14. 通过 cmdframework 来添加 cluster member try {

Session configSession = new Session();

AsyncCmdTaskHandler listener = new AsyncCmdTaskHandler();

AsyncCommandClient asyncCmdClientHelper = new AsyncCommandClient( session, listener);

CommandMgr cmdMgr = CommandMgr.getCommandMgr(adminClient); TaskCommand createMemberCmd = (TaskCommand) cmdMgr createCommand(\"createClusterMember\");

createMemberCmd.setConfigSession(configSession);

createMemberCmd.setParameter(\"clusterName\

}catch(Exception ex) { }

CommandStep step1 = createMemberCmd.getCommandStep(\"memberConfig\");

step1.setParameter(\"memberNode\ step1.setParameter(\"memberName\

step1.setParameter(\"memberWeight\ step1.setParameter(\"genUniquePorts\ step1.setParameter(\"replicatorEntry\

asyncCmdClientHelper.processCommandParameters(createMemberCmd); // Call the asynchronous command client to run the command. asyncCmdClientHelper.execute(createMemberCmd);

CommandResult res = createMemberCmd.getCommandResult();

if (!res.isSuccessful()) {

System.out.println(res.getException().getMessage()); } else {

System.out.println(\"Created successfully!\"); }

//sync() ;

configService.save(configSession, false); } catch (Throwable e) { e.printStackTrace() ; }

目前已经有大量的 wsadmin 脚本例子和脚本库可供 WAS 用户使用, 但基于管理编程接口编程的实例仍很稀少。本文总结了管理编程中最常用的几种接口:MBean,ConfigService 和 Cmdframework 的使用,以及将 wsadmin 脚本编程转化为 Java 编程的一般途径,为开发自定制管理客户端的人员提供了参考。

因篇幅问题不能全部显示,请点此查看更多更全内容

Top