Java DNS查询内部实现(6)

A service provider is identified by placing a provider-configuration file in the resource directory META-INF/services. The file's name is the fully-qualified binary name of the service's type. The file contains a list of fully-qualified binary names of concrete provider classes, one per line. Space and tab characters surrounding each name, as well as blank lines, are ignored. The comment character is '#' ('\u0023', NUMBER SIGN); on each line all characters following the first comment character are ignored. The file must be encoded in UTF-8.

Example Suppose we have a service type com.example.CodecSet which is intended to represent sets of encoder/decoder pairs for some protocol. In this case it is an abstract class with two abstract methods:

public abstract Encoder getEncoder(String encodingName); public abstract Decoder getDecoder(String encodingName);

Each method returns an appropriate object or null if the provider does not support the given encoding. Typical providers support more than one encoding. If com.example.impl.StandardCodecs is an implementation of the CodecSet service then its jar file also contains a file named META-INF/services/com.example.CodecSet This file contains the single line:

com.example.impl.StandardCodecs # Standard codecs

The CodecSet class creates and saves a single service instance at initialization:

private static ServiceLoader<CodecSet> codecSetLoader = ServiceLoader.load(CodecSet.class);

To locate an encoder for a given encoding name it defines a static factory method which iterates through the known and available providers, returning only when it has located a suitable encoder or has run out of providers.

 

public static Encoder getEncoder(String encodingName) { for (CodecSet cp : codecSetLoader) { Encoder enc = cp.getEncoder(encodingName); if (enc != null) return enc; } return null; }

 

A getDecoder method is defined similarly.

所以对于DNSNameServiceDescriptor,在sun/net/spi/nameservice/dns/META-INF/services目录下有一个名称为sun.net.spi.nameservice.NameServiceDescriptor的文件:

# dns service provider descriptor sun.net.spi.nameservice.dns.DNSNameServiceDescriptor

这种机制后来广泛用于Spring的自定义便签(Creating a Custom Spring 3 XML Namespace),估计是受这个影响。

实际应用

知道这个有什么用呢?比如说我们想让我们的应用走谷歌的公共DNS服务器:8.8.8.8。但是我们又不想让用户去修改系统配置,这对用户是个负担,而且我们不希望影响到其他应用。怎么处理呢?只需要在应用启动之前简单配置一下:

System.setProperty("sun.net.spi.nameservice.provider.1", "dns,sun"); System.setProperty("sun.net.spi.nameservice.nameservers", "8.8.8.8"); System.setProperty("sun.net.spi.nameservice.provider.2", "default");

再比如,如果你只想针对某些域名做特殊的解析,那么你可以自定义一个NameServiceProvider,实现对应的NameServiceDescriptor,还有相应的META-INF说明。然后在应用启动的时候配置一下:

System.setProperty("sun.net.spi.nameservice.provider.1", "dns,yourProviderName"); System.setProperty("sun.net.spi.nameservice.provider.2", "default");

参考文章

DNS: Java Glossary 深入浅出的一篇介绍性文章,强烈推荐。

Understanding host name resolution and DNS behavior in Java

Networking Properties

Local Managed DNS (Java) 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/2502f6543a00bb6143a79c23ee2f39fb.html