赞
踩
因工作需要频繁变更hosts, 故须自己实现一个动态管理器, 市面上其实已经有了类似的软件,比如switchhosts!
但因为不好集成其他功能(如远程连接KVM),所以还是决定自己开发一套。
使用之前强烈建议先阅读本文了解原理:
Java实现实时生效hosts文件修改
使用java
实现的话, alibaba
实际上已经开源了一个叫java-dns-cache-manipulator的项目, 使用起来非常简单, 但是未使用java17
进行测试过。
由于与网络相关, 我们同时引入okhttp
和java-dns-cache-manipulator
的最新版本:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dns-cache-manipulator</artifactId>
<version>RELEASE</version>
</dependency>
我有一个NAS
,可以通过http://192.168.31.6:5000
进行访问, 我希望动态修改域名nas.y4d.com
映射到192.168.31.6
。
dns-cache.properties
nas.y4d.com=192.168.31.66
DnsCache.kt
fun main() {
DnsCacheManipulator.loadDnsCacheConfig()
val okHttpClient = OkHttpClient()
val request =
Request.Builder().get().header("Accept-Language", "zh-CN,zh;q=0.9").url("http://nas.y4d.com:5000").build()
val response = okHttpClient.newCall(request).execute()
println(response.body.string())
}
此时如果直接使用java17
运行会报错:
VM options
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens
用法:
--add-opens <source-module>/<package>=<target-module>(,<target-module>)*
其中<source-module>
和<target-module>
是模块名称,<package>
是包的名称。
该--add-opens
选项可以多次使用,但对于源模块和包名称的任何特定组合最多使用一次。每个实例的作用是将指定包的限定打开从源模块> 添加到目标模块。opens
本质上是模块声明中子句的命令行形式,或者是Module::addOpens
方法的无限制形式的调用。因此,只要目标模块读取源模块,目标模块中的代码就能够使用核心反射 API 来访问源模块的命名包中的所有类型(公共类型和其他类型)。
参考: https://openjdk.org/jeps/261#Breaking-encapsulation
如果对于新的域名映射仅限于java
程序进行访问时, 上面方案是没有问题的, 但有时我们需要借助外部程序进行访问, 比如浏览器, 那么上述方案就行不通了, 因此我们还是需要对全局的hosts
文件进行修改来达到全局dns
配置的目的.
package com.y4d.host; import java.awt.*; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.Security; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; import java.util.concurrent.TimeUnit; public class Hosts { private static final Path HOSTS_FILE_PATH = Paths.get(getHostFile()); private static final String UPDATE_COMMENT = "# __UPDATE_BY_JAVA__"; private static final Path BACKUP = Paths.get(HOSTS_FILE_PATH + ".bak"); static { try { Runtime.getRuntime().addShutdownHook(new Thread(Hosts::rollback)); if (!Files.exists(HOSTS_FILE_PATH)) { Files.createFile(HOSTS_FILE_PATH); } boolean isOriginHosts = Files.readAllLines(HOSTS_FILE_PATH).stream().noneMatch(UPDATE_COMMENT::equals); if (isOriginHosts) { Files.deleteIfExists(BACKUP); printHosts("backup"); Files.copy(HOSTS_FILE_PATH, BACKUP); } } catch (IOException e) { // 备份失败则退出程序 throw new RuntimeException(e); } } /** * 获取host文件路径 * * @return 文件路径 */ public static String getHostFile() { String fileName; // 判断系统 if ("linux".equalsIgnoreCase(System.getProperty("os.name"))) { fileName = "/etc/hosts"; } else { fileName = System.getenv("windir") + "\\system32\\drivers\\etc\\hosts"; } return fileName; } private static void rollback() { try { Files.deleteIfExists(HOSTS_FILE_PATH); Files.copy(BACKUP, HOSTS_FILE_PATH); flushDns(); } catch (IOException e) { throw new RuntimeException(e); } } private static void printHosts(String name) throws IOException { System.out.println("option: " + name); Files.readAllLines(HOSTS_FILE_PATH).forEach(System.out::println); } private static boolean update(Properties hosts) { LinkedHashMap<String, String> map = new LinkedHashMap<>(); hosts.forEach((k, v) -> map.put(String.valueOf(k), String.valueOf(v))); return update(map); } /** * 更新hosts * * @param hosts 这里key表示domain, value表示ip, 因为hosts可以对一个ip配置多个域名, 而java中map不允许存在重复, 所以入参这里有调换 * @return */ private static boolean update(Map<String, String> hosts) { Security.setProperty("networkaddress.cache.ttl", "0"); Security.setProperty("networkaddress.cache.negative.ttl", "0"); StringBuilder sb = new StringBuilder(UPDATE_COMMENT); hosts.forEach((k, v) -> { if (v == null || v.isEmpty()) { return; } sb.append(System.lineSeparator()); String line = String.join(" ", v, k); sb.append(line); }); try { Path path = Files.writeString(HOSTS_FILE_PATH, sb.toString()); flushDns(); printHosts("update"); return path.equals(HOSTS_FILE_PATH); } catch (IOException e) { e.printStackTrace(); System.err.println("更新hosts失败"); // 更新失败则回退 rollback(); } return false; } private static void flushDns() throws IOException { Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", "ipconfig /flushdns"}); } public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException { HashMap<String, String> hosts = new HashMap<>(); String domain1 = "y.nas.xyz"; String domain2 = "yw.nas.xyz"; String ip = "192.168.31.66"; hosts.put(domain1, ip); hosts.put(domain2, ip); update(hosts); Desktop.getDesktop().browse(new URI("http://" + domain1 + ":5000")); Desktop.getDesktop().browse(new URI("http://" + domain2 + ":5000")); TimeUnit.SECONDS.sleep(5); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。