Übersicht über die Java-Namens- und Verzeichnisschnittstelle

1. Einleitung

Die Java Naming and Directory Interface (JNDI) bietet eine konsistente Verwendung von Namens- und / oder Verzeichnisdiensten als Java-API. Diese Schnittstelle kann zum Binden von Objekten, zum Nachschlagen oder Abfragen von Objekten sowie zum Erkennen von Änderungen an denselben Objekten verwendet werden.

Während die Verwendung von JNDI eine vielfältige Liste unterstützter Namens- und Verzeichnisdienste enthält, konzentrieren wir uns in diesem Lernprogramm auf JDBC, während wir die JNDI-API untersuchen.

2. JNDI-Beschreibung

Jede Arbeit mit JNDI erfordert ein Verständnis des zugrunde liegenden Dienstes sowie eine zugängliche Implementierung. Ein Datenbankverbindungsdienst fordert beispielsweise bestimmte Eigenschaften und die Ausnahmebehandlung an.

Die Abstraktion von JNDI entkoppelt jedoch die Verbindungskonfiguration von der Anwendung.

Lassen Sie uns Name und Kontext untersuchen , die die Kernfunktionalität von JNDI enthalten.

2.1. Name Schnittstelle

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

Die Namensschnittstelle bietet die Möglichkeit, die Komponentennamen und die Syntax für JNDI-Namen zu verwalten. Das erste Token der Zeichenfolge stellt den globalen Kontext dar. Danach stellt jede hinzugefügte Zeichenfolge den nächsten Unterkontext dar:

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

Unsere Ausgabe sieht aus wie:

java:comp env jdbc

Wie wir sehen können, / ist das Trennzeichen für Namensunter Kontexten. Fügen wir nun einen Unterkontext hinzu:

objectName.add("example");

Dann testen wir unseren Zusatz:

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

2.2. Context - Interface

Der Kontext enthält die Eigenschaften für den Namens- und Verzeichnisdienst . Verwenden wir hier einen Hilfecode aus Spring, um einen Kontext zu erstellen :

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

Der SimpleNamingContextBuilder von Spring erstellt einen JNDI-Provider und aktiviert dann den Builder mit dem NamingManager :

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

Schließlich hilft uns JndiTemplate beim Zugriff auf den InitialContext .

3. JNDI-Objektbindung und -suche

Nachdem wir nun gesehen haben, wie Name und Kontext verwendet werden , verwenden wir JNDI zum Speichern einer JDBC- Datenquelle :

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

3.1. JNDI-Objekte binden

Da wir einen Kontext haben, binden wir das Objekt daran:

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

Im Allgemeinen sollten Dienste eine Objektreferenz, serialisierte Daten oder Attribute in einem Verzeichniskontext speichern. Es hängt alles von den Anforderungen der Anwendung ab.

Beachten Sie, dass die Verwendung von JNDI auf diese Weise weniger häufig ist. In der Regel ist JNDI mit Daten verbunden, die außerhalb der Anwendungslaufzeit verwaltet werden.

Wenn die Anwendung ihre DataSource jedoch bereits erstellen oder finden kann , ist es möglicherweise einfacher, diese mit Spring zu verkabeln. Wenn dagegen etwas außerhalb unserer Anwendung Objekte in JNDI bindet, kann die Anwendung diese verwenden.

3.2. Nachschlagen von JNDI-Objekten

Schauen wir uns unsere DataSource an :

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

Testen Sie anschließend, ob DataSource den Erwartungen entspricht:

assertNotNull(ds.getConnection());

4. Häufige JNDI-Ausnahmen

Die Arbeit mit JNDI kann manchmal zu Laufzeitausnahmen führen. Hier sind einige gebräuchliche.

4.1. NameNotFoundException

ctx.lookup("badJndiName");

Da dieser Name in diesem Zusammenhang nicht gebunden ist, sehen wir diesen Stack-Trace:

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)

Wir sollten beachten, dass der Stack-Trace alle gebundenen Objekte enthält. Dies ist hilfreich, um herauszufinden, warum die Ausnahme aufgetreten ist.

4.2. NoInitialContextException

Jede Interaktion mit dem InitialContext kann eine NoInitialContextException auslösen :

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

Wir sollten beachten, dass diese Verwendung von JNDI gültig ist, wie wir es früher verwendet haben. Diesmal gibt es jedoch keinen JNDI-Kontextanbieter, und es wird eine Ausnahme ausgelöst:

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. Rolle von JNDI in der modernen Anwendungsarchitektur

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

In diesem Tutorial haben wir gesehen, wie Sie ein Objekt mithilfe der Java-Namens- und Verzeichnisschnittstelle verbinden, binden und nachschlagen. Wir haben uns auch die allgemeinen Ausnahmen von JNDI angesehen.

Schließlich haben wir uns angesehen, wie JNDI in die moderne Anwendungsarchitektur passt.

Wie immer ist der Code auf GitHub verfügbar.