package sun.net.spi.nameservice.dns; /* * A name service provider based on JNDI-DNS. */ public final class DNSNameService implements NameService { // List of domains specified by property private LinkedList<String> domainList = null; // JNDI-DNS URL for name servers specified via property private String nameProviderUrl = null; // Per-thread soft cache of the last temporary context private static ThreadLocal<SoftReference<ThreadContext>> contextRef = new ThreadLocal<>(); // Simple class to encapsulate the temporary context private static class ThreadContext { private DirContext dirCtxt; private List<String> nsList; ... } }
看一下构造函数:
public DNSNameService() throws Exception { // default domain String domain = AccessController.doPrivileged( new GetPropertyAction("sun.net.spi.nameservice.domain")); if (domain != null && domain.length() > 0) { domainList = new LinkedList<String>(); domainList.add(domain); } // name servers String nameservers = AccessController.doPrivileged( new GetPropertyAction("sun.net.spi.nameservice.nameservers")); if (nameservers != null && nameservers.length() > 0) { nameProviderUrl = createProviderURL(nameservers); if (nameProviderUrl.length() == 0) { throw new RuntimeException("malformed nameservers property"); } } else { // no property specified so check host DNS resolver configured // with at least one nameserver in dotted notation. // List<String> nsList = ResolverConfiguration.open().nameservers(); if (nsList.isEmpty()) { throw new RuntimeException("no nameservers provided"); } boolean found = false; for (String addr: nsList) { if (IPAddressUtil.isIPv4LiteralAddress(addr) || IPAddressUtil.isIPv6LiteralAddress(addr)) { found = true; break; } } if (!found) { throw new RuntimeException("bad nameserver configuration"); } } }
可以看到它主要是解析下面两个配置项,得到nameserver:
sun.net.spi.nameservice.domain=<domainname>
sun.net.spi.nameservice.nameservers=<server1_ipaddr,server2_ipaddr ...>
如果 sun.net.spi.nameservice.nameservers 没有配置,那么会使用 ResolverConfiguration 得到系统配置的nameserver:
List<String> nsList = ResolverConfiguration.open().nameservers();
ResolverConfiguration的实现逻辑是加载/etc/resolv.conf配置文件中的nameserver。具体参见:。这里就不赘述。
得到NameServer,DNS的解析就很简单了,对NameServer分别执行DNS查询就可以了。具体代码大家可以参见 DNSNameService。
NOTE 从代码可以看出,系统配置的nameserver和通过SystemProperty配置的nameserver是或的关系,所以如果配置了sun.net.spi.nameservice.nameservers,那么相当于绕过了系统配置的nameserver了。
前面说过,非默认的NameService是需要通过相应的NameServiceDescriptor传教的,所以DNSNameService也需要有一个对应的NameServiceDescriptor,就是DNSNameServiceDescriptor:
package sun.net.spi.nameservice.dns; import sun.net.spi.nameservice.*; public final class DNSNameServiceDescriptor implements NameServiceDescriptor { /** * Create a new instance of the corresponding name service. */ public NameService createNameService() throws Exception { return new DNSNameService(); } /** * Returns this service provider's name * */ public String getProviderName() { return "sun"; } /** * Returns this name service type * "dns" "nis" etc */ public String getType() { return "dns"; } }
可以看到DNSNameService的type为dns,name为sun。所以在配置的时候应该配置为dns,sun。
但是NameServiceDescriptor本身是怎么加载的呢?回到上面的代码:
Iterator<NameServiceDescriptor> itr = ServiceLoader.load(NameServiceDescriptor.class).iterator();
原来是是通过。这个类是专门用来加载service-provider的。这个类有非常详细的JavaDoc。其中有一段说明怎么告诉ServiceLoader加载自定义的ServiceProvider: