在 Java 8 中,如何在不在我的环境中对主机名进行硬编码的情况下获取主机名?

In Java 8, how do I get my hostname without hard-coding it in my environment?

我们刚刚在亚马逊 Linux 上升级到 Java 8。我们正在使用 Spring 4.3.8.RELEASE。过去我们可以通过在我们的应用程序上下文文件中设置 bean 来获取我们的机器主机名,就像这样...

<bean id="localhostInetAddress" class="java.net.InetAddress" factory-method="getLocalHost" />
<bean id="hostname" factory-bean="localhostInetAddress" factory-method="getHostName" />

但是对于 Java 8,bean "hostname" 现在包含字符串

localhost

在Java8之前,它曾经在命令行中包含"hostname"值作为运行,即

[myuser@machine1 ~]$ hostname
machine1.mydomain.org

我如何重新配置​​我们的 bean 以便它获得命令行列出的主机名?我不想在任何地方硬编码任何东西。

来自 InetAddress java 8 is not getting the hostname :

There was similar bug fired in JDK.

What I understand is that they changed default resolution process.

They honor configuration in /etc/nsswitch.conf where hosts are configured for /etc/hosts that gives it main priority for name resolution.

Usually /etc/hosts has record for 127.0.0.1 localhost that provide name for host localhost

你可以试试InetAddress.getCanonicalHostName()

getCanonicalHostName() 的 JavaDocs 说

Gets the fully qualified domain name for this IP address. Best effort method, meaning we may not be able to return the FQDN depending on the underlying system configuration.

你真的有三个不同复杂性和信息价值的选项:

  1. 实际上 运行 hostname 命令使用 Runtime。它相当便携,几乎可以在任何地方使用。 (可能不在 IBM 的大型机上)
  2. 获取所有可用的网络接口并获取它们的主机名。 https://docs.oracle.com/javase/tutorial/networking/nifs/listing.html
  3. 将环境或系统 属性 设置为 hostname 的值。
    喜欢java -Dmy.hostname=hostname ...

可悲的是,Spring XML 并不是那么简单。

已知所有其他选项都会提供不同程度的准确度。 像 127.0.0.1 可能会解析为 localhostlocalhost.localdomain.

或者,您可以使用 Java 运行时 运行 主机名 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()">

如果结果不符合您的需要,请查看Amazon's documemtation

我可以更好地在您的 .properties 文件中为主机名定义一个 属性。

hostname=myserver.mydomain.com

并在您的应用程序中使用它。这种方式没有硬编码。它还避免了对操作系统配置的依赖,无需注意即可更改。

InetAddress in Java 8 有一个关于主机名解析的 bug。该错误已在 8u20 版中报告,此后已得到修复。请检查您是否使用此版本。如果不是,则使用 InetAddress.getLocalHost().getHostName() 将为您提供主机名。

我还建议,在 AWS 实例上设置 static hostname

  1. 更新/etc/hosts
  2. 更新/etc/hostname
  3. 运行 hostname 检查主机名
  4. 重新启动并检查持久化的主机名

这应该允许您在需要时从文件中读取主机名。

此外,如果 hostname 命令给出了正确的结果,则使用 exec method in Runtime class 执行命令并读取 InputStream 以获得响应。

PS:可以使用InetAddress.getLocalHost().isLoopbackAddress()判断地址是否为LoopbackAddress,然后使用fallback方法

OpenJDK bugs

中也有类似的问题

The newer calls respect the localhosts /etc/nsswitch.conf configuration files. In the case of this machine that file tells these calls to look in files before referencing other naming services.

Since the /etc/hosts file contains an explicit mapping for this hostname / IP combination, that is what is returned.

In the older JDK's the gethostbyname actually ignored the local machines settings and immediately delegated to the naming service.

您始终可以使用 Runtime class 来做到这一点:

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);
}

但不是很推荐see