1、WebSphere Application Server 管理编程简述WebSphere Application Server(以下简称为 WAS)提供了两种管理途径:基于 Web 方式的管理控制台和基于命令行方式的 wsadmin 工具;还可以通过管理编程接口(WebSphere Management API)来开发符合特定需求的管理应用WAS 的管理体系是基于 JMX 规范的,JMX 规范定义了三层结构:Distributed layer:包含各种适配器,使得使用不同协议 ( 如 RMI,HTTP ) 的管理应用能访问代理层。Agent layer:包含 Mbean Server,是 Mb
2、ean 的注册中心,操纵各种 Mbean 并对外提供各种管理服务,如监控,定时任务,Mbean 的动态加载等。Instrumentation layer:包含各种 Mbean,Mbean 实现对资源的访问和代表了资源状态。图 1.JMX 规范的三层结构示例JMX 即 Java Management Extensions Java 管理扩展MBean 即 managed beans 被管理的 Beans一个 MBean 是一个被管理的 Java 对象,有点类似于 JavaBean,一个设备、一个应用或者任何资源都可以被表示为 MBean,MBean 会暴露一个接口对外,这个接口可以读取或者写入一
3、些对象中的属性,通常一个 MBean 需要定义一个接口,以 MBean 结尾, 例如: EchoMBean, 格式为 XXXMBean,这个是规范,必须得遵守。描述一个可管理的资源。是一个 java 对象,遵循以下一些规则:1.必须是公用的,非抽象的类 2.必须有至少一个公用的构造器 3.必须实现它自己的相应的 MBean 接口或者实现 javax.management.DynamicMBean 接口4.可选的,一个 MBean 可以实现 javax.management.NotificationBroadcaster 接口 MBean 的类型。WAS 的管理体系,如图 -2 所示:图 2.W
4、AS 的管理体系本文主要介绍上图中 custom client 的编程。管理编程分为下面两种途径:1.直接调用 Mbean2.使用 WAS 的管理编程接口WebSphere JMX MbeansMbeans 介绍WAS 提供了各种类型的 Mbean, 封装了各种管理功能,如对 WAS 系统环境,J2EE 应用,J2EE 资源等的管理和监控。获得某个 Mbean:每个 MBean 都有一个 ObjectName,在使用该 MBean 之前必须先找到它。ObjectName 可以通过 AdminClient,以格式化的查询串进行查询。格式化的查询串可以选择性地包括以下的特性:域名、节点名、进程名、
5、类型、名称等等。 一个查询串既可惟一标识单个 ObjectName,也可以代表多个具有公共特性的 ObjectName。MBean 通常是以它们的类型进行分类的。 一些 MBean 类型(例如 Perf)会在应用服务器中提供单个的实例,但其他 MBean 类型(例如 servlet 和 EJB)会在应用服务器中提供多个实例。清单 1. 获得某个 server 上的类型为 JVM 的 MBeanString query = “*:type=JVM,process=server1,node=node1,*“” ; queryName = new ObjectName(query); Set mBe
6、ans = 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
7、API”。在一个 WAS Network Deployment 环境中,我们可以通过 AdminClient 连接到 dmgr,也可以直接去连接某个 nodeagent 或 server。 如果我们连接的是 dmgr ,那么通过 dmgr 去访问 nodeagent 和 server 上的 MBean 时,前提条件是这个 nodeagent 或 server 必须是启动的。访问 Mbean 的属性和方法我们知道,调用 EJB 或 Web service 最终都要通过 Java 接口来进行, 但 Mbean 却不同。调用 Mbean 的方法与 java 反射机制类似,要提供方法名称,方法的参数类
8、型,最后才能 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
9、= (String)adminClient.invoke(jvmBean, “getIPAddress“, new Objectserver.hostName, signature) ;WebSphere management APIWAS 提供的管理编程接口包含在以 com.ibm.websphere.management 开头的包中。下面介绍一下包中的实用 API。AdminClient 和 AdminServiceAdminClient 用于连接远程的 JVM,AdminService 用于连接本地 JVM,如果你的管理代码运行在和被管理的服务器相同的 JVM 内,那可以使用 Admin
10、Service 接口。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.C
11、ONNECTOR_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,
12、host.getPasswd(); AdminClient 既可以运行在 admin thin client 中,也可以运行在 WAS server runtime 中。获得 AdminService 接口 :清单 5. 获得 AdminService 接口的代码AdminService adminService = AdminServiceFactory.getAdminService() ;Wsadmin API 和 management API 之间的对应关系WAS 命令行脚本工具提供了几个管理对象 AdminApp, AdminTask, AdminConfig, AdminContr
13、ol。它们分别对应不同的管理 API:1. AdminApp:AdminApp 对象的功能对应于两个包 com.ibm.websphere.management.application 和 com.ibm.websphere.management.application.client。 通过这两个包下面的 API,我们可以安装 / 卸载,启动 / 停止一个 J2EE 应用。和应用管理相关的编程比较固定,本文没有过多介绍这些 API 的使用,读者可以参考本文提供的例子 ApplicationMgr.java,里面包含了应用安装和启停的示例。2. AdminControl: AdminContro
14、l 汇集了一些常用的 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.mana
15、gement.cmdframework 和 com.ibm.websphere.management.cmdframework.provider。本文主要介绍 AdminConfig 和 AdminTask 对应的管理编程。使用 ConfigServiceWAS 的配置信息有些可以通过 Mbean 去获得,如 cell/node/server 的名称,也可以通过 ConfigServer 去获取。而有些配置信息只能通过 ConfigService 去获得。 下面是使用 ConfigService 时会遇到的几个概念:ConfigData :config data 对应于 config 目录下的
16、某个 xml 文件或 xml 文件的某个片段,通过操纵 config data,就可以读写该 xml 文件。ConfigType :config data 的类型。首先要知道你要访问配置信息的类型才能去访问。 通过 configService 的 getSupportedConfigObjectTypes() 方法可以获得所有的 ConfigData 的类型信息。例如我们要获得 WAS 上所有的数据源的配置信息,通过查找上述类型列表,可以知道数据源的 ConfigType 为 DataSource。ConfigData Id :ConfigData 的唯一标识。如何访问某个 ConfigDat
17、a ?通过 ConfigData type 来查询 ConfigData通过 ConfigDataId 来创建 ConfigDataConfigData 和 ConfigDataId 的关系如下:清单 6. ConfigData 和 ConfigDataId 的转换关系/ 获得 ConfigData 的 ConfigDataId ConfigDataId configDataId = ConfigServiceHelper.getConfigDataId(configData) ; / 已知 ConfigDataId,得到其 ConfigData public ObjectName creat
18、eConfigData(String dataId) ObjectName configData = null ; ConfigDataId id = new ConfigDataId(dataId) ; configData = ConfigServiceHelper.createObjectName(id) ; return configData ; 使用 ConfigService 获得环境信息下面举例说明如何用 MBean 和 ConfigService 获取集群信息,方便读者的对比。关于更多其它环境信息的获取,读者可以参考本文例子 WASEnvHelper.java。清单 7. 通过
19、 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.getC
20、anonicalName(); clustername = (String)adminClient.getAttribute(cluMBean, “clusterName“) ; System.out.println(clustername); ClusterMemberData membersData = (ClusterMemberData)adminClient.invoke(cluMBean, “getClusterMembers“, new Object, signature) ; for (ClusterMemberData clusterMemberData : membersD
21、ata) 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
22、 configData = configService.queryConfigObjects(session, null, pattern , null); for (int i = 0; i members = new ArrayList() ; String clustername = (String)configService.getAttribute(session , configDatai , “name“) ; List _members = (ArrayList) configService.getAttribute( session, configDatai, “member
23、s“); 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,往往需
24、要先写个读取的程序来判断里面每个对象的类型。下面是创建 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
25、 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
26、, null); ObjectName parent = configData0 ; System.out.println(parent); AttributeList provAttrs = new AttributeList(); provAttrs.add(new Attribute(“name“, “MyJDBCProvider“); provAttrs.add(new Attribute(“implementationClassName“, “com.mycompany.MyConnectionPoolDataSource“); provAttrs.add(new Attribute
27、(“description“,“ApsectJDBC driver“); /create the provider ObjectName jdbcProv = configService.createConfigData(session, scope, “JDBCProvider“, “JDBCProvider“, provAttrs); System.out.println(“create the JDBC provider successfully.“); configService.addElement(session,jdbcProv,“classpath“,“,-1); / Prep
28、are the attribute list AttributeList dsAttrs = new AttributeList(); dsAttrs.add(new Attribute(“name“, “myTestDS“); dsAttrs.add(new Attribute(“jndiName“, “jdbc/MyTestDS“); /create a new datasource ObjectName dataSource = configService.createConfigData(session, jdbcProv, “DataSource“,“DataSource“,dsAt
29、trs); / Add a propertySet. AttributeList propSetAttrs = new AttributeList(); ObjectName resourcePropertySet = configService.createConfigData(session,dataSource, “propertySet“, “,propSetAttrs); System.out.println(“create the DataSource successfully.“); configService.save(session, false); catch (Excep
30、tion ex) ex.printStackTrace(); 修改已有配置下面的 updateAttributelist 是一个通用的方法,相对于设置好 Attributelist 里的值之后做一个提交。清单 10. 提交更新的通用方法/ 设置新的属性值ConfigServiceHelper.setAttributeValue(threadpool, “minimumSize“, new Integer(int)pool.getMinSize() ; ConfigServiceHelper.setAttributeValue(threadpool, “maximumSize“, new Int
31、eger(int)pool.getMaxSize() ; / 更新整个 Attributelist updateAttributelist(threadpool) ; public void updateAttributelist(AttributeList attrs) try ConfigDataId id = ConfigServiceHelper.getConfigDataId(attrs) ; ObjectName objectName = ConfigServiceHelper.createObjectName(id) ; configService.setAttributes(s
32、ession, objectName, attrs) ; catch (Exception e) e.printStackTrace() ; 修改 ConfigData 的属性。修改 configdata 的某个属性时,需要先判断该属性的数据类型。最简单的办法是打印出该 configdata 的信息: 采用 System.out.println(obj); 和 System.out.println(obj.getClass().getName(); 即可。如果数据类型为 ObjectName,说明该属性值指向另一个 configdata,那我们在设置该属性的 value 之前, 需要先查询到那
33、个 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(co
34、nfigDatai); Object obj = configService.getAttribute(session , configDatai, “activeAuthMechanism“) ; Object id = ConfigServiceHelper.getConfigDataId(ObjectName)obj) ; System.out.println(id); /configService.getAttributes(session, configDatai, “activeUserRegistry“, false) ; System.out.println(obj); Sys
35、tem.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(configDa
36、ta10); ObjectName d = createConfigData(configDataId) ; enableSecurity.add(new Attribute(“activeUserRegistry“, configData10); enableSecurity.add(new Attribute(“cacheTimeout“, new Integer(100); enableSecurity.add(new Attribute(“enabled“, new Boolean(false); enableSecurity.add(new Attribute(“appEnabled
37、“, new Boolean(false); updateAttributelist(enableSecurity); configService.save(session, false);使用 Command FrameworkWAS 大量的管理功能包含在 wsadmin 的 AdminTask 对象中。WAS 提供了 command framework programming API,可以帮助我们开发等价于 AdminTask 脚本功能的程序。cmdframework 的命令名称通常就是 AdminTask 的方法名称,命令的参数与 AdminTask 方法的参数也一致,但需要做类型转化,
38、即将 AdminTask 中 python 的数据类型转化成 Java 的数据类型,这种对应关系并不难确立。此外还需要注意一个 AdminTask 中是否包含 CommandStep ,可以通过 listCommandSteps() 检查 。清单 12. 为指定的 role 分配用户组的 wsadmin 脚本AdminTask.mapGroupsToNamingRole(-roleName CosNamingWrite-specialSubjects EVERYONE ) AdminConfig.save()清单 13. 将上述 wsadmin 脚本转化为 Java 编程/ 下面的 impor
39、t 实际上列出了 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.CommandM
40、gr; 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
41、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);
42、 cmd.setConfigSession(session); cmd.setParameter(“roleName“, “CosNamingWrite“); cmd.setParameter(“specialSubjects“, new String“EVERYONE“) ; asyncCmdClientHelper.processCommandParameters(cmd); / Call the asynchronous command client to run the command. asyncCmdClientHelper.execute(cmd); / Check the co
43、mmand 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. 通过 cmdframewor
44、k 来添加 cluster membertry Session configSession = new Session(); AsyncCmdTaskHandler listener = new AsyncCmdTaskHandler(); AsyncCommandClient asyncCmdClientHelper = new AsyncCommandClient( session, listener); CommandMgr cmdMgr = CommandMgr.getCommandMgr(adminClient); TaskCommand createMemberCmd = (Tas
45、kCommand) cmdMgr createCommand(“createClusterMember“); createMemberCmd.setConfigSession(configSession); createMemberCmd.setParameter(“clusterName“, “mycluster“); catch(Exception ex) CommandStep step1 = createMemberCmd.getCommandStep(“memberConfig“); step1.setParameter(“memberNode“, “kuNode05“); step
46、1.setParameter(“memberName“, “member88“); step1.setParameter(“memberWeight“, Integer.valueOf(2); step1.setParameter(“genUniquePorts“, new Boolean(true); step1.setParameter(“replicatorEntry“, new Boolean(true); asyncCmdClientHelper.processCommandParameters(createMemberCmd); / Call the asynchronous co
47、mmand 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 编程的一般途径,为开发自定制管理客户端的人员提供了参考。