Answers:
根据Byron的回答,您不能使用标志或调用来设置networkaddress.cache.ttl
或将networkaddress.cache.negative.ttl
其设置为系统属性,因为它们不是系统属性-它们是安全性属性。-D
System.setProperty
如果要使用System属性触发此行为(因此可以使用-D
flag或call System.setProperty
),则需要设置以下System属性:
-Dsun.net.inetaddr.ttl=0
此系统属性将启用所需的效果。
但请注意:如果-D
在启动JVM进程时不使用该标志,而是选择从代码中调用它:
java.security.Security.setProperty("networkaddress.cache.ttl" , "0")
必须先执行此代码,然后JVM中的任何其他代码才尝试执行网络操作。
这很重要,因为例如,如果您调用Security.setProperty
.war文件并将该.war部署到Tomcat,则将无法正常工作:Tomcat在执行.war的代码之前就使用Java网络堆栈对其进行了初始化。由于这种“竞争条件”,通常-D
在启动JVM进程时使用该标志更为方便。
如果您不使用-Dsun.net.inetaddr.ttl=0
或调用Security.setProperty
,则需要$JRE_HOME/lib/security/java.security
在该文件中编辑和设置那些安全属性,例如
networkaddress.cache.ttl = 0
networkaddress.cache.negative.ttl = 0
但是请注意围绕这些属性的注释中的安全警告。仅当您有足够的信心确定自己不会受到DNS欺骗攻击的影响时,才执行此操作。
Java具有一些非常奇怪的dns缓存行为。最好的选择是关闭dns缓存或将其设置为较低的数字(例如5秒)。
networkaddress.cache.ttl(默认值:-1)
指示从名称服务成功查找名称的缓存策略。该值被指定为整数,以指示缓存成功查找的秒数。值-1表示“永远缓存”。networkaddress.cache.negative.ttl(默认值:10)
指示从名称服务查找名称失败的缓存策略。该值被指定为整数,以指示为不成功的查询而缓存故障的秒数。值为0表示“从不缓存”。值-1表示“永远缓存”。
System.getSecurityManager()
。Java 8文档:docs.oracle.com/javase/8/docs/api/java/lang/…–
这显然已在较新的版本(SE 6和7)中得到修复。在使用tcpdump观察端口53活动时,运行以下代码段时,我遇到了30秒的最大缓存时间。
/**
* http://stackoverflow.com/questions/1256556/any-way-to-make-java-honor-the-dns-caching-timeout-ttl
*
* Result: Java 6 distributed with Ubuntu 12.04 and Java 7 u15 downloaded from Oracle have
* an expiry time for dns lookups of approx. 30 seconds.
*/
import java.util.*;
import java.text.*;
import java.security.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
public class Test {
final static String hostname = "www.google.com";
public static void main(String[] args) {
// only required for Java SE 5 and lower:
//Security.setProperty("networkaddress.cache.ttl", "30");
System.out.println(Security.getProperty("networkaddress.cache.ttl"));
System.out.println(System.getProperty("networkaddress.cache.ttl"));
System.out.println(Security.getProperty("networkaddress.cache.negative.ttl"));
System.out.println(System.getProperty("networkaddress.cache.negative.ttl"));
while(true) {
int i = 0;
try {
makeRequest();
InetAddress inetAddress = InetAddress.getLocalHost();
System.out.println(new Date());
inetAddress = InetAddress.getByName(hostname);
displayStuff(hostname, inetAddress);
} catch (UnknownHostException e) {
e.printStackTrace();
}
try {
Thread.sleep(5L*1000L);
} catch(Exception ex) {}
i++;
}
}
public static void displayStuff(String whichHost, InetAddress inetAddress) {
System.out.println("Which Host:" + whichHost);
System.out.println("Canonical Host Name:" + inetAddress.getCanonicalHostName());
System.out.println("Host Name:" + inetAddress.getHostName());
System.out.println("Host Address:" + inetAddress.getHostAddress());
}
public static void makeRequest() {
try {
URL url = new URL("http://"+hostname+"/");
URLConnection conn = url.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
InputStreamReader ird = new InputStreamReader(is);
BufferedReader rd = new BufferedReader(ird);
String res;
while((res = rd.readLine()) != null) {
System.out.println(res);
break;
}
rd.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
为了扩展Byron的答案,我相信您需要编辑目录java.security
中的%JRE_HOME%\lib\security
文件以实现此更改。
这是相关的部分:
#
# The Java-level namelookup cache policy for successful lookups:
#
# any negative value: caching forever
# any positive value: the number of seconds to cache an address for
# zero: do not cache
#
# default value is forever (FOREVER). For security reasons, this
# caching is made forever when a security manager is set. When a security
# manager is not set, the default behavior is to cache for 30 seconds.
#
# NOTE: setting this to anything other than the default value can have
# serious security implications. Do not set it unless
# you are sure you are not exposed to DNS spoofing attack.
#
#networkaddress.cache.ttl=-1
文档的java.security
文件在这里。
总结其他答案,<jre-path>/lib/security/java.security
您可以设置属性的值networkaddress.cache.ttl
来调整DNS查找的缓存方式。请注意,这不是系统属性,而是安全属性。我可以使用以下方法进行设置:
java.security.Security.setProperty("networkaddress.cache.ttl", "<value>");
这也可以由系统属性设置,-Dsun.net.inetaddr.ttl
但是如果在其他位置设置,则不会覆盖安全属性。
我还想补充一点,如果像我以前那样在WebSphere中看到Web服务的此问题,设置networkaddress.cache.ttl
将是不够的。您需要将系统属性设置disableWSAddressCaching
为true
。与生存时间属性不同,可以将其设置为JVM参数或通过来设置System.setProperty
。
IBM已经在WebSphere处理DNS缓存怎样一个相当详细的具体位置。上面相关的部分是:
要禁用Web服务的地址缓存,您需要将其他JVM定制属性disableWSAddressCaching设置为true。使用此属性可以禁用Web服务的地址缓存。如果您的系统通常在许多客户端线程上运行,并且在wsAddrCache缓存上遇到锁争用,则可以将此自定义属性设置为true,以防止对Web服务数据进行缓存。
根据官方的oracle java属性,此属性sun.net.inetaddr.ttl
是Sun特定于实现的属性,“将来的版本可能不支持”。“首选方法是使用安全属性” networkaddress.cache.ttl
。
java.security.Security
(至少在jdk7中)