DNS move JDK DNS resolution out of DnsServerAddresses static initialization

Motivation:
DnsServerAddresses loads the default DNS servers used for DNS resolution in a static initialization block. This is subject to blocking and may cause unexpected delays. We can move this initialization to DefaultDnsServerAddressStreamProvider where it is more expected to load the JDK's default configuration.

Modifications:
- Move all the static initialization from DnsServerAddresses to DefaultDnsServerAddressStreamProvider
- Deprecate static methods in DnsServerAddresses which have moved to DefaultDnsServerAddressStreamProvider
- Remove usage of deprecated methods in DnsServerAddresses

Result:
Usage of JDK's blocking DNS resolver is not required to use resolver-dns.
This commit is contained in:
Scott Mitchell 2017-03-31 13:52:46 -07:00
parent 08646afc1e
commit 155983f1a1
6 changed files with 112 additions and 64 deletions

View File

@ -15,23 +15,115 @@
*/
package io.netty.resolver.dns;
import io.netty.util.internal.SocketUtils;
import io.netty.util.internal.UnstableApi;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import static io.netty.resolver.dns.DnsServerAddresses.defaultAddresses;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static io.netty.resolver.dns.DnsServerAddresses.sequential;
/**
* A {@link DnsServerAddressStreamProvider} which will use predefined default DNS servers to use for DNS resolution.
* These defaults do not respect your host's machines defaults.
* <p>
* This may use the JDK's blocking DNS resolution to bootstrap the default DNS server addresses.
*/
@UnstableApi
public final class DefaultDnsServerAddressStreamProvider implements DnsServerAddressStreamProvider {
private static final InternalLogger logger =
InternalLoggerFactory.getInstance(DefaultDnsServerAddressStreamProvider.class);
public static final DefaultDnsServerAddressStreamProvider INSTANCE = new DefaultDnsServerAddressStreamProvider();
private static final List<InetSocketAddress> DEFAULT_NAME_SERVER_LIST;
private static final InetSocketAddress[] DEFAULT_NAME_SERVER_ARRAY;
private static final DnsServerAddresses DEFAULT_NAME_SERVERS;
static final int DNS_PORT = 53;
static {
final List<InetSocketAddress> defaultNameServers = new ArrayList<InetSocketAddress>(2);
try {
Class<?> configClass = Class.forName("sun.net.dns.ResolverConfiguration");
Method open = configClass.getMethod("open");
Method nameservers = configClass.getMethod("nameservers");
Object instance = open.invoke(null);
@SuppressWarnings("unchecked")
final List<String> list = (List<String>) nameservers.invoke(instance);
for (String a: list) {
if (a != null) {
defaultNameServers.add(new InetSocketAddress(SocketUtils.addressByName(a), DNS_PORT));
}
}
} catch (Exception ignore) {
// Failed to get the system name server list.
// Will add the default name servers afterwards.
}
if (!defaultNameServers.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug(
"Default DNS servers: {} (sun.net.dns.ResolverConfiguration)", defaultNameServers);
}
} else {
Collections.addAll(
defaultNameServers,
SocketUtils.socketAddress("8.8.8.8", DNS_PORT),
SocketUtils.socketAddress("8.8.4.4", DNS_PORT));
if (logger.isWarnEnabled()) {
logger.warn(
"Default DNS servers: {} (Google Public DNS as a fallback)", defaultNameServers);
}
}
DEFAULT_NAME_SERVER_LIST = Collections.unmodifiableList(defaultNameServers);
DEFAULT_NAME_SERVER_ARRAY = defaultNameServers.toArray(new InetSocketAddress[defaultNameServers.size()]);
DEFAULT_NAME_SERVERS = sequential(DEFAULT_NAME_SERVER_ARRAY);
}
private DefaultDnsServerAddressStreamProvider() {
}
@Override
public DnsServerAddressStream nameServerAddressStream(String hostname) {
return defaultAddresses().stream();
return DEFAULT_NAME_SERVERS.stream();
}
/**
* Returns the list of the system DNS server addresses. If it failed to retrieve the list of the system DNS server
* addresses from the environment, it will return {@code "8.8.8.8"} and {@code "8.8.4.4"}, the addresses of the
* Google public DNS servers.
*/
public static List<InetSocketAddress> defaultAddressList() {
return DEFAULT_NAME_SERVER_LIST;
}
/**
* Returns the {@link DnsServerAddresses} that yields the system DNS server addresses sequentially. If it failed to
* retrieve the list of the system DNS server addresses from the environment, it will use {@code "8.8.8.8"} and
* {@code "8.8.4.4"}, the addresses of the Google public DNS servers.
* <p>
* This method has the same effect with the following code:
* <pre>
* DnsServerAddresses.sequential(DnsServerAddresses.defaultAddressList());
* </pre>
* </p>
*/
public static DnsServerAddresses defaultAddresses() {
return DEFAULT_NAME_SERVERS;
}
/**
* Get the array form of {@link #defaultAddressList()}.
* @return The array form of {@link #defaultAddressList()}.
*/
static InetSocketAddress[] defaultAddressArray() {
return DEFAULT_NAME_SERVER_ARRAY.clone();
}
}

View File

@ -62,6 +62,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider.DNS_PORT;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import static io.netty.util.internal.ObjectUtil.checkPositive;
import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
@ -288,7 +289,7 @@ public class DnsNameResolver extends InetNameResolver {
// Only here to override in unit tests.
int dnsRedirectPort(@SuppressWarnings("unused") InetAddress server) {
return DnsServerAddresses.DNS_PORT;
return DNS_PORT;
}
/**

View File

@ -16,84 +16,36 @@
package io.netty.resolver.dns;
import io.netty.util.internal.SocketUtils;
import io.netty.util.internal.UnstableApi;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider.defaultAddressArray;
/**
* Provides an infinite sequence of DNS server addresses to {@link DnsNameResolver}.
*/
@UnstableApi
@SuppressWarnings("IteratorNextCanNotThrowNoSuchElementException")
public abstract class DnsServerAddresses {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(DnsServerAddresses.class);
private static final List<InetSocketAddress> DEFAULT_NAME_SERVER_LIST;
private static final InetSocketAddress[] DEFAULT_NAME_SERVER_ARRAY;
private static final DnsServerAddresses DEFAULT_NAME_SERVERS;
static final int DNS_PORT = 53;
static {
final List<InetSocketAddress> defaultNameServers = new ArrayList<InetSocketAddress>(2);
try {
Class<?> configClass = Class.forName("sun.net.dns.ResolverConfiguration");
Method open = configClass.getMethod("open");
Method nameservers = configClass.getMethod("nameservers");
Object instance = open.invoke(null);
@SuppressWarnings("unchecked")
final List<String> list = (List<String>) nameservers.invoke(instance);
for (String a: list) {
if (a != null) {
defaultNameServers.add(new InetSocketAddress(SocketUtils.addressByName(a), DNS_PORT));
}
}
} catch (Exception ignore) {
// Failed to get the system name server list.
// Will add the default name servers afterwards.
}
if (!defaultNameServers.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug(
"Default DNS servers: {} (sun.net.dns.ResolverConfiguration)", defaultNameServers);
}
} else {
Collections.addAll(
defaultNameServers,
SocketUtils.socketAddress("8.8.8.8", DNS_PORT),
SocketUtils.socketAddress("8.8.4.4", DNS_PORT));
if (logger.isWarnEnabled()) {
logger.warn(
"Default DNS servers: {} (Google Public DNS as a fallback)", defaultNameServers);
}
}
DEFAULT_NAME_SERVER_LIST = Collections.unmodifiableList(defaultNameServers);
DEFAULT_NAME_SERVER_ARRAY = defaultNameServers.toArray(new InetSocketAddress[defaultNameServers.size()]);
DEFAULT_NAME_SERVERS = sequential(DEFAULT_NAME_SERVER_ARRAY);
}
/**
* @deprecated Use {@link DefaultDnsServerAddressStreamProvider#defaultAddressList()}.
* <p>
* Returns the list of the system DNS server addresses. If it failed to retrieve the list of the system DNS server
* addresses from the environment, it will return {@code "8.8.8.8"} and {@code "8.8.4.4"}, the addresses of the
* Google public DNS servers.
*/
@Deprecated
public static List<InetSocketAddress> defaultAddressList() {
return DEFAULT_NAME_SERVER_LIST;
return DefaultDnsServerAddressStreamProvider.defaultAddressList();
}
/**
* @deprecated Use {@link DefaultDnsServerAddressStreamProvider#defaultAddresses()}.
* <p>
* Returns the {@link DnsServerAddresses} that yields the system DNS server addresses sequentially. If it failed to
* retrieve the list of the system DNS server addresses from the environment, it will use {@code "8.8.8.8"} and
* {@code "8.8.4.4"}, the addresses of the Google public DNS servers.
@ -104,8 +56,9 @@ public abstract class DnsServerAddresses {
* </pre>
* </p>
*/
@Deprecated
public static DnsServerAddresses defaultAddresses() {
return DEFAULT_NAME_SERVERS;
return DefaultDnsServerAddressStreamProvider.defaultAddresses();
}
/**
@ -254,7 +207,7 @@ public abstract class DnsServerAddresses {
}
if (list.isEmpty()) {
return DEFAULT_NAME_SERVER_ARRAY;
return defaultAddressArray();
}
return list.toArray(new InetSocketAddress[list.size()]);

View File

@ -31,7 +31,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static io.netty.resolver.dns.DnsServerAddresses.DNS_PORT;
import static io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider.DNS_PORT;
import static io.netty.util.internal.StringUtil.indexOfNonWhiteSpace;
/**

View File

@ -69,6 +69,7 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider.DNS_PORT;
import static io.netty.resolver.dns.DnsServerAddresses.sequential;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasSize;
@ -774,7 +775,7 @@ public class DnsNameResolverTest {
@Override
int dnsRedirectPort(InetAddress server) {
return server.equals(dnsServerAuthority.localAddress().getAddress()) ?
dnsServerAuthority.localAddress().getPort() : DnsServerAddresses.DNS_PORT;
dnsServerAuthority.localAddress().getPort() : DNS_PORT;
}
};

View File

@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;
import static io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider.defaultAddressList;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
@ -35,7 +36,7 @@ public class DnsServerAddressesTest {
@Test
public void testDefaultAddresses() {
assertThat(DnsServerAddresses.defaultAddressList().size(), is(greaterThan(0)));
assertThat(defaultAddressList().size(), is(greaterThan(0)));
}
@Test