在Java8中,如何在不在环境中硬编码的情况下获取主机名?
我们刚刚在AmazonLinux上升级到Java8。我们使用的是Spring 4.3.8.0版本。过去,我们可以通过在应用程序上下文文件中设置bean来获取机器主机名,如下所示在Java8中,如何在不在环境中硬编码的情况下获取主机名?,java,linux,spring,java-8,hostname,Java,Linux,Spring,Java 8,Hostname,我们刚刚在AmazonLinux上升级到Java8。我们使用的是Spring 4.3.8.0版本。过去,我们可以通过在应用程序上下文文件中设置bean来获取机器主机名,如下所示 <bean id="localhostInetAddress" class="java.net.InetAddress" factory-method="getLocalHost" /> <bean id="hostname" factory-bean="localhostInetAddress" fa
<bean id="localhostInetAddress" class="java.net.InetAddress" factory-method="getLocalHost" />
<bean id="hostname" factory-bean="localhostInetAddress" factory-method="getHostName" />
在Java8之前,它通常包含在命令行上运行的“hostname”值,即
[myuser@machine1 ~]$ hostname
machine1.mydomain.org
如何重新配置bean,使其获得命令行列出的主机名?我不想在任何地方硬编码任何内容。来自:
JDK中也有类似的错误
据我所知,他们改变了默认的解决过程
它们支持/etc/nsswitch.conf中的配置,其中主机是为/etc/hosts配置的,为名称解析提供了主要优先级
通常/etc/hosts有127.0.0.1 localhost的记录,该记录提供了主机localhost的名称
您可以尝试
InetAddress.getCanonicalHostName()
getCanonicalHostName()的JavaDocs说
获取此IP地址的完全限定域名。尽力而为方法,这意味着我们可能无法根据基础系统配置返回FQDN
您确实有三个不同复杂性和信息价值的选项:
比如java-Dmy.hostname=
hostname
如127.0.0.1可能会解析为localhost或localhost.localdomain。或者,您可以使用Java运行时运行hostname linux命令,代码应如下所示:
String cmdResult="";
Runtime r = Runtime.getRuntime();
Process p = r.exec("hostname");
BufferedReader in = new BufferedReader(new
InputStreamReader(p.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
cmdResult += inputLine;
}
in.close();
我相信Java仍然调用本机的
gethostname()
,但无法解释为什么会失败
对于Linux,您可以尝试以下替代方法:
String hostname = new String(Files.readAllBytes(Paths.get("/proc/sys/kernel/hostname")), StandardCharsets.US_ASCII);
由于我的评论在流中丢失,请尝试
<bean id="hostname" class="com.amazonaws.util.EC2MetadataUtils" factory-method="getLocalHostName()">
请查看结果是否不符合您的需要。我最好在.properties文件中为类似主机名的内容定义一个属性
hostname=myserver.mydomain.com
并在应用程序中使用它。这条路不需要编码。它还避免了对操作系统配置的依赖,这些配置可以在不引起注意的情况下进行更改。Java8中的InetAddress对主机名的解析有很大的影响。该错误在8u20版本中被报告,并从那时起被修复。请检查您是否不在此版本上。如果不是,则使用
InetAddress.getLocalHost().getHostName()
将获得主机名
我还建议在AWS实例上设置一个
hostname
检查主机名hostname
命令给出了正确的结果,则使用执行该命令并读取输入流以获得响应
PS:您可以使用
InetAddress.getLocalHost().isLoopbackAddress()
检查地址是否为环回地址,然后使用回退方法。中有一个类似的问题
较新的调用涉及localhosts/etc/nsswitch.conf配置文件。对于这台机器,该文件告诉这些
调用以在引用其他命名服务之前查找文件
因为/etc/hosts文件包含此文件的显式映射
主机名/IP组合,即返回的内容
在旧的JDK中,gethostbyname实际上忽略了本地
计算机设置并立即委托给命名服务
您始终可以使用该类进行以下操作:
Process hostname = Runtime.getRuntime().exec("hostname");
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(hostname.getInputStream()));
String s;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
但这并不是你所能推荐的那样你有运行安全管理器吗?From:“如果不允许该操作,则返回表示环回地址的InetAddress。”您还可以尝试使用
getCanonicalHostName()
来获取fqn,而不是getHostName()
您是指Java 8的安全管理器吗?我的意思是,如果存在某种Linux安全管理器,那么无论Java版本如何,它都不允许您所说的操作,对吗?我想,文档中特别提到Java端安全管理器,但当然,操作系统端的限制也会影响结果。但目前还不清楚Java API是否能保证这种情况下的特定行为……我之所以这样问,是因为它可能不会是操作系统,否则我以前对Java 8之前版本的调用就不会起作用。你知道我希望Java端安全管理器在哪里吗?@Holger嗯,我在代码中看到的注释实际上是exec(hostname)
。。。它们还声明在Amazon上InetAddress.getLocalHost()
返回(有时)环回设备,即localhost
。我可能需要ping这些行的作者以了解实际发生的情况。如果我更改/etc/hosts文件,不会影响Linux系统上的其他内容吗?如果答案是“是”或“可能”,我更愿意使用一个与我的Java webapp/app容器隔离的解决方案。嘿,如果你的建议与Holger在评论中的建议相同,我尝试了taht,但没有成功。我的开发环境是一台Mac High Sierra机器。在那种环境下,上面的方法还能工作吗?当然不能,因为信息是从EC2 rest服务检索的。但是您肯定有一个spring测试配置文件,您可以在其中设置字符串值。我不希望域被硬编码。它已经存在于系统中。为什么我不能从这里开始呢?您的主机名配置是基于环境变量的。JVM 8+版本
Process hostname = Runtime.getRuntime().exec("hostname");
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(hostname.getInputStream()));
String s;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}