JEP 418, Internet-Address Resolution SPI
Contexte
Parmi les nouvelles fonctionnalités du JDK 18, nous avons la mise en place d’une SPI (Service Provider Interface) pour la résolution d’adresses Internet.
Le développeur utilise la classe java.net.InetAddress
pour la résolution d’adresse Internet. Il a pour cela les méthodes suivantes à notre disposition :
-
InetAddress::getAllByName()
permet de faire une recherche par nom. Elle retourne un tableau d’adresses IP -
InetAddress::getByName()
permet de faire une recherche par nom. Elle retourne la première adresse IP de la précédente liste.
Pour une adresse Internet, nous avons les méthodes suivantes :
-
InetAddress::getCanonicalHostName()
permet de faire une résolution inverse (Adresse IP vers le nom). -
InetAddress::getHostName()
permet de faire une résolution inverse si c’est nécessaire.
Actuellement, la résolution des noms sur le réseau IP est réalisée à partir des fonctions systèmes natives afin d’interroger les serveurs DNS (Domain Name Server).
Les motivations
Les principales sont les suivantes :
-
Projet Loom : La résolution de noms utilise les appels systèmes qui bloquent le traitement. Cela va à l’encontre du principe de thread virtuel. Il faut passer par des solutions alternatives afin d’interroger les serveurs DNS.
Il est à noter qu’il est possible d’interroger ces serveurs à l’aide de l’API JNDI.
-
Nouveaux protocoles : Au delà du DNS, des nouveaux protocoles émergent comme DNS au dessus de HTTPS.
-
Personnalisation : Avoir la maitrise fine de la résolution, utiliser une bibliothèque adéquate.
-
Tests : Il est ainsi possible de "moquer" la résolution DNS pour les tests.
Comment cela marche ?
Pour cela, nous avons des nouvelles classes dans le package java.net.spi
:
-
InetAddressResolver
: C’est l’interface qui réalise concrêtement la résolution du nom. Elle est récupérer en passant par la fabrique ci-dessus. Elle définie deux méthodes :
interface InetAddressResolver {
String lookupByAddress(byte[] addr);
Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy)
}
-
InetAddressResolver.LookupPolicy
: C’est une classe qui permet de définir les caractéristiques de la résolution. Par exemple, IPV4, IPV4_FIRST, IPV6 et IPV6_FIRST -
InetAddressResolverProvider
: C’est la classe abstraite qui renvoie le résolveur sous le modèle des fabriques. Ce fournisseur est activé par le biais duServiceLoader
public abstract class InetAddressResolverProvider {
public abstract InetAddressResolver get(Configuration config);
public abstract String name();
}
-
InetAddressResolverProvider.Configuration
: C’est une interface qui permet de récupérer l’implémentation par défaut.
interface InetAddressResolverProvider.Configuration {
InetAddressResolver builtinResolver()
String lookupLocalHostName()
}
Mise en oeuvre
Pour la mise en oeuvre, nous avons définir notre fournisseur qui fera tout simplement de la délégation vis à vis du fournisseur par défaut de OpenJDK.
Pour cela nous allons commencer avec une nouvelle classe pour notre résolveur.
public class MonResolveurDNS implements InetAddressResolver { (1)
private InetAddressResolver delegate; (2)
public MonResolveurDNS(InetAddressResolver delegate) {
this.delegate = delegate;
}
@Override
public Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy) throws UnknownHostException { (3)
System.out.println("[INFO ] : Appel de la méthode 'MonResolveurDNS::lookupByName.");
return this.delegate.lookupByName(host, lookupPolicy);
}
@Override
public String lookupByAddress(byte[] addr) throws UnknownHostException { (4)
System.out.println("[INFO ] : Appel de la méthode 'MonResolveurDNS::lookupByAddress.");
return delegate.lookupByAddress(addr);
}
}
-
Nous réalisons l’interface
java.net.spi.InetAddressResolverProvider
-
Nous définissons un attribut avec le résolveur que nous souhaitons utiliser.
-
Nous écrivons le code pour la méthode
lookupByName
de l’interface -
Nous écrivons le code pour la méthode
lookupByAddress
de l’interface
Pour utiliser notre résolveur, il faut définir un fournisseur via l’interface InetAddressResolverProvider
public class MonResolveurDNSProvider extends InetAddressResolverProvider { (1)
@Override
public InetAddressResolver get(Configuration configuration) { (2)
System.out.println("[INFO ] : Le fournisseur 'MonResolveurDNSProvider' est chargé.");
return new MonResolveurDNS(configuration.builtinResolver()); (3)
}
@Override
public String name() {
return "MonResolveurDNSProvider";
}
}
-
Nous réalisons l’interface
java.net.spi.InetAddressResolverProvider
-
Principe de fabrique qui renvoie une instance
InetAddressResolver
-
A partir de l’instance configuration, nous povons récupérer le résolveur par défaut.
Comme indiqué précédemment, c’est le ServiceLoader
qui est utilisé pour récupérer le ou les fournisseurs.
Pour cela, il est nécessaire de définir un fichier texte avec les règles suivantes :
-
Fichier présent dans le répertoire META-INF/services
-
Fichier ayant le nom de l’interface en tant que nom du fichier. Dans notre cas, c’est :
java.net.spi.InetAddressResolverProvider
-
Fichier contenant le nom complet de la classe du fournisseur
Ayant suivi ces 3 étapes, le fournisseur est opérationnelle.
Si vous écrivez le programme suivant :
public static void main (String [] args) throws UnknownHostException {
InetAddress adr = InetAddress.getByName("www.edf.fr");
System.out.println(" - " + adr.getHostName() + " -> " + adr.getHostAddress());
adr = InetAddress.getByName("www.wikipedia.fr");
System.out.println(" - " + adr.getHostName() + " -> " + adr.getHostAddress());
}
Voici la sortie correspondant à lancement du programme :
[INFO ] : Le fournisseur 'MonResolveurDNSProvider' est chargé.
[INFO ] : Appel de la méthode 'MonResolveurDNS::lookupByName'.
- www.edf.fr -> 23.72.9.40
[INFO ] : Appel de la méthode 'MonResolveurDNS::lookupByName'.
- www.wikipedia.fr -> 51.254.200.228
Moteur de recherche
"Eduquer, ce n'est pas remplir des vases mais c'est d'allumer des feux." - Michel Montaigne
Billets récents
- Eclipse plante systématiquement sous Debian (et autres distribution Linux)
- JEP 463, Implicitly Declared Classes and Instance Main Methods (Second Preview)
- Debian - Montée de version de Debian 11 (Bullseye) à Debian 12 (Bookworm)
- JEP 451, Prepare to Disallow the Dynamic Loading of Agents
- JEP 444, Virtual Threads