JBoss EAP应用获取运行模式、相关路径及节点信息
一、背景
某应用系统在JBoss EAP 7.0的standalone模式(单实例模式)下运行正常,但在切换到domain模式(域模式)后陆续发现一些问题。为解决这些问题产生了这样的需求:如何判断JBoss运行在哪种模式?随之又产生了其它需求:如何获取相关路径的信息?如何获取集群(Cluster)中的所有节点信息?
二、解决思路
对于第2个需求,是容易解决的,因为JBoss EAP预置的各种属性(property)中就包含了相关路径的定义,如:jboss.home.dir(JBoss EAP安装目录,即${JBOSS_HOME})、jboss.server.base.dir(JBoss EAP的当前Server的主目录)、jboss.domain.base.dir(JBoss EAP在域模式下的主目录)等等,详见https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.1/html-single/configuration_guide/的Table3.3。
以此为基础,则第1个需求也找到一个很简单的解决方法:根据jboss.domain.base.dir的值来判断,在域模式下它的值通常是:${JBOSS_HOME}/domain,而在单实例模式下,其值为null。经测试,在7.x及6.x版都运行正常。
但第3个需求的解决就困难的多,在查阅大量资料及反复进行试验后,终于发现可以通过wildfly-clustering-api-yyy.jar及wildfly-clustering-server-xxx.jar(其中xxx、yyy为各自的版本号)提供的接口来实现。由于wildfly-clustering-server-xxx.jar只在JBoss EAP 7.x内置加载,本解决方案只在7.x版得以验证,限于时间因素未能得出在6.x中实现的具体方法。
三、接口类、实现类、显示页面
重点有三个组成部分:接口类DispInfoRemote,实现类DispInfo,以及用于显示的index.jsp。
接口类示例代码:
package test; import java.util.List; import javax.ejb.Remote; @Remote public interface DispInfoRemote { public void setID(String sessionID); public void setTime(String createTime); public String getID(); public String getTime(); public List<String> getNodesInfo(); }
实现类示例代码:
package test; import java.util.ArrayList; import java.util.List; import javax.annotation.Resource; import javax.ejb.Remote; import javax.ejb.Stateless; import org.wildfly.clustering.group.Group; import org.wildfly.clustering.group.Node; /** * Session Bean implementation class DispInfo */ @Stateless @Remote public class DispInfo implements DispInfoRemote { @Resource(lookup = "java:jboss/clustering/group/web") private Group group; //sessionID和createTime用于验证域模式下是否实现session复制 private String sessionID; private String createTime; /** * Default constructor. */ public DispInfo() { } public void setID(String sessionID) { this.sessionID = sessionID; } public void setTime(String createTime) { this.createTime = createTime; } public String getID() { return sessionID; } public String getTime() { return createTime; } //获取集群中所有节点的信息 public List<String> getNodesInfo() { List<Node> nodes = group.getNodes(); List<String> lists = new ArrayList<String>(); for (Node node: nodes) { String str = node.getName() + ", " + node.getSocketAddress(); lists.add(str); } return lists; } }
需要指出的时,集群(cluster)并非只能在域模式下模式,在单实例模式下,多个节点也可通过standalone-ha.xml或standalone-full-ha.xml组成一个集群。限于篇幅,不在本文讨论。
index.jsp的示例代码:
<%@ page language="java" import="java.util.*"%> <%@ page import="javax.naming.*, java.util.Properties" %> <%@ page import="test.DispInfoRemote" %> <% Hashtable<String, String> jndiProperties = new Hashtable<String, String>(); jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); %> <%! DispInfoRemote diw = null; %> <% try { Context ctx = new InitialContext(jndiProperties); final String appName = ""; final String moduleName = "TestEjb"; final String distinctName = ""; final String beanName = "DispInfo"; final String className = DispInfoRemote.class.getName(); Object obj = ctx.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + className); diw = (DispInfoRemote)obj; diw.setID(session.getId()); out.print(session.getId()); diw.setTime(Long.toString(session.getCreationTime())); } catch (NamingException e) { e.printStackTrace(); } %> <html> <head><title>JBossEap</title></head> <body> <h1><font color="red">JBossEap</font></h1> <table align="centre" border="1"> <tr> <td>Session ID</td> <td><%= this.diw.getID() %></td> </tr> <tr> <td>Created on</td> <td><%= this.diw.getTime() %></td> </tr> <tr> <td>"{jboss.home.dir}"</td> <td><%= System.getProperty("jboss.home.dir") %></td> </tr> <tr> <td>"{jboss.server.base.dir}"</td> <td><%= System.getProperty("jboss.server.base.dir") %></td> </tr> <tr> <td>"{jboss.domain.base.dir}"</td> <td><%= System.getProperty("jboss.domain.base.dir") %></td> </tr> <tr> <td>"{jboss.node.name}"</td> <td><%= System.getProperty("jboss.node.name") %></td> </tr> <tr> <td>"{jboss.server.name}"</td> <td><%= System.getProperty("jboss.server.name") %></td> </tr> <% List<String> nodesInfo = this.diw.getNodesInfo(); %> <tr> <td>Cluster Node Count</td> <td><%= nodesInfo.size() %> </td> </tr> <% for (int i=0; i<nodesInfo.size(); i++) { %> <tr> <td> Node <%= i+1%> </td> <td><%= nodesInfo.get(i) %> </td> </tr> <% }%> </table> </body> </html>
四、测试结果
此处仅仅是为测试,为图省事将上述三项放入一个工程,并打包成一个cluster.war,分别部署到JBoss EAP的单实例模式和域模式下进行测试。
在standalone模式下的页面截图如下:
可以看到,此时的jboss.domain.base.name的值为null,而jboss.node.name和jboss.server.name为节点的hostname,且Cluster只有一个节点,节点名等同于jboss.server.name,至于SocketAddress,缺省情况下使用standalone.xml时其值为null,而使用standalone-ha.xml或standalone-full-ha.xml时为:/IP:55200。
在domain模式下的页面截图为:
可以看到,此时jboss.domain.base.name的值已是${JBOSS_HOME}/domain,而jboss.node.name和jboss.server.name的值也发生改变,与在domain.xml里的配置一致;Cluster所有节点的信息也全部列出,SocketAddress也始终能获取到。
五、总结
通过上述方法,3个需求均得到解决,应用系统也得以修改后在域模式和集群环境下正确运行。
吐个槽:网上能获得的JBoss EAP有效资料比较少,尤其是在不能google的情况下。其中有不少还是关于6.x版的陈旧资料,不一定适合与新的7.x版。