背景
在企业应用部署监控过程中 ,往往需要通过一些唯一标示来更快的定位有问题的项目或者项目运行的实例.可以实现
- 唯一标识,同一机器可以可以部署同一个应用多个实例.
- 不受重启的影响,实例标识能够沿用到应用的整个生命周期.避免标识爆炸.
获取运行 IP
如下可以获取运行的 ip 地址,获取一次即可缓存,无需每次获取.
private static final String LOCALHOST_IP = "127.0.0.1";
private static final String EMPTY_IP = "0.0.0.0";
private static final Pattern IP_PATTERN = Pattern.compile("[0-9]{1,3}(\\.[0-9]{1,3}){3,}");
/**
* 获取本机ip;
*
* @return ip;
* @throws IOException io异常
*/
public static String getHostIp() throws IOException {
InetAddress address = getHostAddress();
return address == null ? null : address.getHostAddress();
}
/**
* 获取hostAddress; 默认是127.0.0.1
*
* @return hostAddress;
* @throws IOException if can't get address
*/
public static InetAddress getHostAddress() throws IOException {
InetAddress localAddress;
localAddress = InetAddress.getLocalHost();
if (isValidHostAddress(localAddress)) {
return localAddress;
}
Enumeration<NetworkInterface> interfaces;
interfaces = NetworkInterface.getNetworkInterfaces();
if (interfaces == null) {
return localAddress;
}
while (interfaces.hasMoreElements()) {
NetworkInterface network = interfaces.nextElement();
Enumeration<InetAddress> addresses = network.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (isValidHostAddress(address)) {
return address;
}
}
}
return localAddress;
}
private static boolean isValidHostAddress(InetAddress address) {
if (address == null || address.isLoopbackAddress()) {
return false;
}
String name = address.getHostAddress();
return (name != null && !EMPTY_IP.equals(name) && !LOCALHOST_IP.equals(name) && IP_PATTERN.matcher(name)
.matches());
}
复制代码
获取运行端口
这里以 tomcat 为例.之所以能从 MBean中获取到数据,是因为 Tomcat 在启动过程中将相关的数据注册到了 MBeanServer
中.
public static int getTomcatPort() throws Exception {
MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> objectNames = beanServer.queryNames(new ObjectName("*:type=Connector,*"),
Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));
String port = objectNames.iterator().next().getKeyProperty("port");
return Integer.valueOf(port);
}
复制代码
创建唯一的 HashCode
获取当前文件所在路径的绝对路径的hash值,比如当前文件为AppUtils.class
,保证无论以什么样的方式启动,值不会改变,除非改了部署路径.
private String getUniqueCode(){
URL resource = Thread.currentThread().getContextClassLoader().getResource(AppUtils.class.getName().replace(".", "/") + ".class");
return String.valueOf(Math.abs(resource.toString().hashCode()));
}
复制代码
示例
Web服务使用: IP+端口
对于应用有暴露端口的情况可以使用IP 和端口的形式,即使同一机器部署多个应用,也可以轻松区分开. 比如: 10.11.12.13:8080
10.11.12.13:8081
其他服务使用: IP+ HashCode
比如: 10.11.12.13:212134566
10.11.12.13:123134586
总结
有了上面的描述,对应任何 Java 应用来说,都可以找到对于他的唯一编号且不会随意改变.
public static String getInstanceCode() {
String ip = getHostIp();
Integer port = getTomcatPort();
if (port != null) {
return ip + ":" + port;
}
String uniqueCode = getUniqueCode();
return ip + ":" + uniqueCode;
}
复制代码