Présentation de l'interface de nommage et d'annuaire Java

1. Introduction

L'interface de nommage et d'annuaire Java (JNDI) permet une utilisation cohérente des services de dénomination et / ou d'annuaire en tant qu'API Java. Cette interface peut être utilisée pour lier des objets, rechercher ou interroger des objets, ainsi que pour détecter des modifications sur les mêmes objets.

Bien que l'utilisation de JNDI inclut une liste variée de services de noms et d'annuaires pris en charge, dans ce didacticiel, nous nous concentrerons sur JDBC tout en explorant l'API de JNDI.

2. Description JNDI

Tout travail avec JNDI nécessite une compréhension du service sous-jacent ainsi qu'une implémentation accessible. Par exemple, un service de connexion à une base de données appelle des propriétés spécifiques et une gestion des exceptions.

Cependant, l'abstraction de JNDI dissocie la configuration de connexion de l'application.

Explorons le nom et le contexte , qui contiennent les fonctionnalités de base de JNDI.

2.1. Interface de nom

Name objectName = new CompositeName("java:comp/env/jdbc");

L' interface Nom permet de gérer les noms de composants et la syntaxe des noms JNDI. Le premier jeton de la chaîne représente le contexte global, après quoi chaque chaîne ajoutée représente le sous-contexte suivant:

Enumeration elements = objectName.getAll(); while(elements.hasMoreElements()) { System.out.println(elements.nextElement()); }

Notre sortie ressemble à:

java:comp env jdbc

Comme nous pouvons le voir, / est le délimiteur des sous-contextes Name . Maintenant, ajoutons un sous-contexte:

objectName.add("example");

Ensuite, nous testons notre ajout:

assertEquals("example", objectName.get(objectName.size() - 1));

2.2. Interface contextuelle

Le contexte contient les propriétés du service de dénomination et d'annuaire . Ici, utilisons du code d'assistance de Spring pour plus de commodité pour créer un contexte :

SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); builder.activate();

SimpleNamingContextBuilder de Spring crée un fournisseur JNDI, puis active le générateur avec le NamingManager :

JndiTemplate jndiTemplate = new JndiTemplate(); ctx = (InitialContext) jndiTemplate.getContext();

Enfin, JndiTemplate nous aide à accéder à InitialContext .

3. Liaison et recherche d'objets JNDI

Maintenant que nous avons vu comment utiliser le nom et le contexte , utilisons JNDI pour stocker une source de données JDBC :

ds = new DriverManagerDataSource("jdbc:h2:mem:mydb");

3.1. Liaison d'objets JNDI

Comme nous avons un contexte, lions l'objet à celui-ci:

ctx.bind("java:comp/env/jdbc/datasource", ds);

En général, les services doivent stocker une référence d'objet, des données sérialisées ou des attributs dans un contexte d'annuaire. Tout dépend des besoins de l'application.

Notez que l'utilisation de JNDI de cette manière est moins courante. En règle générale, JNDI s'interface avec des données gérées en dehors de l'exécution de l'application.

Cependant, si l'application peut déjà créer ou trouver sa DataSource , il peut être plus facile de la câbler à l'aide de Spring. En revanche, si quelque chose en dehors de notre application est lié à des objets dans JNDI, l'application peut les consommer.

3.2. Recherche d'objets JNDI

Regardons notre DataSource :

DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");

Et puis testons pour nous assurer que DataSource est comme prévu:

assertNotNull(ds.getConnection());

4. Exceptions JNDI courantes

L'utilisation de JNDI peut parfois entraîner des exceptions d'exécution. Voici quelques exemples courants.

4.1. NameNotFoundException

ctx.lookup("badJndiName");

Puisque ce nom n'est pas lié dans ce contexte, nous voyons cette trace de pile:

javax.naming.NameNotFoundException: Name [badJndiName] not bound; 0 bindings: [] at org.springframework.mock.jndi.SimpleNamingContext.lookup(SimpleNamingContext.java:140) at java.naming/javax.naming.InitialContext.lookup(InitialContext.java:409)

Nous devons noter que la trace de la pile contient tous les objets liés, ce qui est utile pour savoir pourquoi l'exception s'est produite.

4.2. NoInitialContextException

Toute interaction avec InitialContext peut lever NoInitialContextException :

assertThrows(NoInitialContextException.class, () -> { JndiTemplate jndiTemplate = new JndiTemplate(); InitialContext ctx = (InitialContext) jndiTemplate.getContext(); ctx.lookup("java:comp/env/jdbc/datasource"); }).printStackTrace();

Il faut noter que cette utilisation de JNDI est valide, comme nous l'avons utilisé précédemment. Cependant, cette fois, il n'y a pas de fournisseur de contexte JNDI et une exception sera levée:

javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or in an application resource file: java.naming.factory.initial at java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:685)

5. Rôle de JNDI dans l'architecture d'application moderne

While JNDI plays less of a role in lightweight, containerized Java applications such as Spring Boot, there are other uses. Three Java technologies that still use JNDI are JDBC, EJB, and JMS. All have a wide array of uses across Java enterprise applications.

For example, a separate DevOps team may manage environment variables such as username and password for a sensitive database connection in all environments. A JNDI resource can be created in the web application container, with JNDI used as a layer of consistent abstraction that works in all environments.

This setup allows developers to create and control a local definition for development purposes while connecting to sensitive resources in a production environment through the same JNDI name.

6. Conclusion

Dans ce didacticiel, nous avons vu la connexion, la liaison et la recherche d'un objet à l'aide de l'interface de nommage et d'annuaire Java. Nous avons également examiné les exceptions courantes lancées par JNDI.

Enfin, nous avons examiné comment JNDI s'intègre dans l'architecture d'application moderne.

Comme toujours, le code est disponible sur sur GitHub.