我们的服务是部署在weblogic上的,最近遇到一个需求,需要在代码中获取weblogic部署当前服务的IP地址和端口。
后来搜到一段代码,亲测有效:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | public static String getIpAndPort(){ try { InitialContext initialContext = new InitialContext(); MBeanServer tMBeanServer; MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); tMBeanServer = (MBeanServer) initialContext.lookup( "java:comp/env/jmx/runtime" ); ObjectName tObjectName = new ObjectName( "com.bea:Name=RuntimeService,Type=weblogic.management.mbeanservers.runtime.RuntimeServiceMBean" ); ObjectName serverrt = (ObjectName) tMBeanServer.getAttribute(tObjectName, "ServerRuntime" ); String port = String.valueOf(tMBeanServer.getAttribute(serverrt, "ListenPort" )); String listenAddr = (String) tMBeanServer.getAttribute(serverrt, "ListenAddress" ); String[] tempAddr = listenAddr.split( "/" ); if (tempAddr.length == 1 ) { listenAddr = tempAddr[ 0 ]; } else if (tempAddr[tempAddr.length - 1 ].trim().length() != 0 ) { listenAddr = tempAddr[tempAddr.length - 1 ]; } else if (tempAddr.length > 2 ) { listenAddr = tempAddr[tempAddr.length - 2 ]; } StringBuilder sBuilder = new StringBuilder(listenAddr); sBuilder.append( ":" ); sBuilder.append(port); System.out.print(sBuilder); return sBuilder.toString(); } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (MalformedObjectNameException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstanceNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (AttributeNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ReflectionException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (MBeanException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null ; } |
可要理解这段代码后面的原理和思路,真是费劲了,需要了解以下知识:
JMX
JNDI
RMI
EJB
总结成一句话就是,通过web应用通过weblogic提供的JNDI访问weblogic的JMX中的对象。JNDI后台用的技术就是EJB,而EJB是RMI在java语言上的实现。上述几个概念的具体含义,读者可以自行查询,网上资料很多。
下面回归正题,先从思路上详细分析下标题中的内容如何实现。
作为服务端代码,最后都是生成一个war放到服务器上去运行的。那从代码本身的程序来说,是肯定无法知道自己会被放到什么类型的web容器中、自己可以被访问的IP地址和端口号的。那谁知道的呢?只有web容器知道。换句话说,从这次要解决的问题上看,只有weblogic自己知道在其内部部署的应用被放到了哪个IP下,端口是多少。也就是说,解决这个问题的关键是,我们的服务程序如何去“问”weblogic容器,自己的IP和端口是多少。
好的,我们继续来想这个问题。能不能从weblogic容器中获取到服务的IP和端口号,取决于weblogic愿不愿意把这些信息开放给你,换句话说,取决于weblogic是否对外开放了可以获取其内部服务IP和端口的通道。
目前来看,必然是提供了的,查了weblogic的官网,发现了这样一段说明:
文章的链接地址为(oracle的官方文档):
https://docs.oracle.com/cd/E13222_01/wls/docs81/jmx/overview.html
只要获取到weblogic的MBeanServer,然后从MBeanServer中取出对应的ObjectName的属性,就可以获取到IP和端口了。这里面提到了JMX和RMI的概念,不清楚的,可以从上文找博文链接查看。
有一点是比较好理解的,就是weblogic必定会把自己处在runtime的服务信息写入到MBeanServer,然后我们通过MBeanServer把这些信息拿出来就行了。至于为什么要有MBeanServer,又是和JMX相关,这里就不再赘述。现在的关键问题是,我们的本地程序,如何访问到weblogic的MBeanServer?答案是通过InitialContext的lookup函数,而lookup函数最终的访问方式是JNDI。也就是说,我们最终是通过weblogic对外提供的JNDI访问到weblogic的MBeanServer的。MBeanServer在两个程序(weblogic和服务程序)之间的传递是通过EJB的。
拿到weblogic的MBeanServer之后,如何获取程序的IP的端口呢?这个当然要看weblogic是怎么设置进去的。按照设置进去的规则取出来就可以了。那如何知道weblogic的设置规则呢?我们继续看weblogic的文档。
原文链接:
https://docs.oracle.com/cd/E13222_01/wls/docs90/jmx/understandWLS.html
发现了什么问题,红框中的文字,不就是刚才样例代码中的文字吗?再来看下面这段代码,通过本地程序访问Runtime MBean Server
If the classes for the JMX client are located in a J2EE module, such as an EJB or Web application, then the JNDI name for the Runtime MBeanServer is:
java:comp/env/jmx/runtime
翻译下,如果JMX客户端(EJB或者Web程序)在J2EE本地,那么通过JNDI访问Runtime MBean Server的名称为java:comp/env/jmx/runtime。
Runtime MBean Server是MBeanServer的一种,通过下面的说明可以看到:
所以可以把Runtime MBean Server赋值给MBeanServer.
好,下一步,我们继续来调查,从Runtime MBean Server中如何取到端口和IP。通过以下代码获取RuntimeServerMBean的ServerRuntime属性。
1 2 3 | ObjectName tObjectName = new ObjectName( "com.bea:Name=RuntimeService,Type=weblogic.management.mbeanservers.runtime.RuntimeServiceMBean" ); ObjectName serverrt = (ObjectName) tMBeanServer.getAttribute(tObjectName, "ServerRuntime" ); |
点开ServerRuntime属性,看看它还有什么二级属性,果然:
ListenPort和ListenAddress就是ServerRuntime的二级属性。通过以下代码获取到:
1 2 | String port = String.valueOf(tMBeanServer.getAttribute(serverrt, "ListenPort" )); String listenAddr = (String) tMBeanServer.getAttribute(serverrt, "ListenAddress" ); |
至此,所有代码解析完毕。
但是仔细想想,这段代码其实是有瑕疵的。换句话说,健壮性还不够。如果我们用的web容器不是weblogic怎么办?那代码岂不是就不管用了。所以我建议,完善下这段代码,增加对web容器的判断。其他web容器中如果获取IP和端口,还请读者自己探索。先通过下面的函数判断下当前的web容器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public static String getServerName() { String serverName = null ; if (ServerDetector.isWebLogic()) { serverName = "WebLogic" ; } else if (ServerDetector.isTomcat()) { serverName = "Tomcat" ; } else if (ServerDetector.isWebSphere()) { serverName = "WebSphere" ; } else if (ServerDetector.isSupportsComet()) { serverName = "SupportsComet" ; } else if (ServerDetector.isResin()) { serverName = "Resin" ; } else if (ServerDetector.isOC4J()) { serverName = "OC4J" ; } else if (ServerDetector.isJOnAS()) { serverName = "JOnAS" ; } else if (ServerDetector.isJetty()) { serverName = "Jetty" ; } else if (ServerDetector.isJBoss()) { serverName = "JBoss" ; } else if (ServerDetector.isGeronimo()) { serverName = "Geronimo" ; } else if (ServerDetector.isGlassfish()) { serverName = "Glassfish" ; } else if (ServerDetector.isGlassfish2()) { serverName = "Glassfish2" ; } else if (ServerDetector.isGlassfish3()) { serverName = "Glassfish3" ; } return serverName; } |
ServerDetector需要对应jar包,利用maven引入的配置为:
1 2 3 4 5 6 7 | < dependency > < groupId >com.liferay.portal</ groupId > < artifactId >portal-kernel</ artifactId > < version >5.2.3</ version > < scope >provided</ scope > </ dependency > |
遇到问题,一定要多探索,与其看别人的博文,不如自己深入研究API,找样例代码。用一手资料。以上为个人经验,希望能给大家一个参考,也希望大家多多支持自学编程网。
- 本文固定链接: https://zxbcw.cn/post/215329/
- 转载请注明:必须在正文中标注并保留原文链接
- QQ群: PHP高手阵营官方总群(344148542)
- QQ群: Yii2.0开发(304864863)