1. 소개
JNDI (Java Naming and Directory Interface) 는 이름 지정 및 / 또는 디렉토리 서비스를 Java API로 일관되게 사용합니다. 이 인터페이스는 개체 바인딩, 개체 조회 또는 쿼리 및 동일한 개체의 변경 사항 감지에 사용할 수 있습니다.
JNDI 사용법에는 지원되는 이름 지정 및 디렉토리 서비스의 다양한 목록이 포함되어 있지만이 튜토리얼에서는 JNDI의 API를 탐색하는 동안 JDBC에 중점을 둘 것입니다.
2. JNDI 설명
JNDI이있는 모든 작업은 필요 기본 서비스에 대한 이해 뿐만 아니라 접근 구현을. 예를 들어, 데이터베이스 연결 서비스는 특정 속성 및 예외 처리를 요청합니다.
그러나 JNDI의 추상화는 애플리케이션에서 연결 구성을 분리합니다.
JNDI의 핵심 기능이 포함 된 Name 및 Context를 살펴 보겠습니다 .
2.1. 이름 인터페이스
Name objectName = new CompositeName("java:comp/env/jdbc");
이름 인터페이스는 JNDI 이름에 대한 구성 요소 이름과 구문을 관리 할 수있는 기능을 제공합니다. 문자열의 첫 번째 토큰은 전역 컨텍스트를 나타내고 추가 된 각 문자열은 다음 하위 컨텍스트를 나타냅니다.
Enumeration elements = objectName.getAll(); while(elements.hasMoreElements()) { System.out.println(elements.nextElement()); }
출력은 다음과 같습니다.
java:comp env jdbc
보시다시피 / 는 이름 하위 컨텍스트 의 구분 기호입니다 . 이제 하위 컨텍스트를 추가해 보겠습니다.
objectName.add("example");
그런 다음 추가를 테스트합니다.
assertEquals("example", objectName.get(objectName.size() - 1));
2.2. 컨텍스트 인터페이스
컨텍스트 에는 이름 지정 및 디렉터리 서비스에 대한 속성이 포함 됩니다. 여기에서는 편의를 위해 Context 를 빌드하기 위해 Spring의 일부 도우미 코드를 사용합시다 .
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); builder.activate();
Spring의 SimpleNamingContextBuilder 는 JNDI 공급자를 생성 한 다음 NamingManager 를 사용하여 빌더를 활성화합니다 .
JndiTemplate jndiTemplate = new JndiTemplate(); ctx = (InitialContext) jndiTemplate.getContext();
마지막으로, JndiTemplate 은 우리가 InitialContext에 접근하도록 도와줍니다 .
3. JNDI 개체 바인딩 및 조회
Name 과 Context 를 사용하는 방법을 살펴 보았 으므로 JNDI를 사용하여 JDBC DataSource 를 저장해 보겠습니다 .
ds = new DriverManagerDataSource("jdbc:h2:mem:mydb");
3.1. JNDI 객체 바인딩
컨텍스트가 있으므로 객체를 여기에 바인딩 해 보겠습니다.
ctx.bind("java:comp/env/jdbc/datasource", ds);
일반적으로 서비스는 디렉터리 컨텍스트에 개체 참조, 직렬화 된 데이터 또는 특성을 저장해야합니다. 그것은 모두 응용 프로그램의 요구에 달려 있습니다.
이 방법으로 JNDI를 사용하는 것은 덜 일반적입니다. 일반적으로 JNDI는 애플리케이션 런타임 외부에서 관리되는 데이터와 인터페이스합니다.
그러나 애플리케이션이 이미 DataSource를 만들거나 찾을 수 있다면 Spring을 사용하여 연결하는 것이 더 쉬울 수 있습니다. 대조적으로, JNDI에서 우리의 애플리케이션 바인딩 된 객체 밖에있는 것이 있다면, 애플리케이션은 그것들을 소비 할 수 있습니다.
3.2. JNDI 객체 조회
DataSource를 살펴 보겠습니다 .
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
그런 다음 DataSource 가 예상대로 인지 테스트 해 보겠습니다 .
assertNotNull(ds.getConnection());
4. 일반적인 JNDI 예외
JNDI로 작업하면 때때로 런타임 예외가 발생할 수 있습니다. 다음은 몇 가지 일반적인 것입니다.
4.1. NameNotFoundException
ctx.lookup("badJndiName");
이 이름은이 컨텍스트에서 바인딩되지 않으므로 다음 스택 추적을 볼 수 있습니다.
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)
스택 추적에는 바인딩 된 모든 개체가 포함되어 있으므로 예외가 발생한 이유를 추적하는 데 유용합니다.
4.2. NoInitialContextException
InitialContext 와의 모든 상호 작용은 NoInitialContextException 을 throw 할 수 있습니다 .
assertThrows(NoInitialContextException.class, () -> { JndiTemplate jndiTemplate = new JndiTemplate(); InitialContext ctx = (InitialContext) jndiTemplate.getContext(); ctx.lookup("java:comp/env/jdbc/datasource"); }).printStackTrace();
이 JNDI 사용은 이전에 사용한 것처럼 유효합니다. 그러나 이번에는 JNDI 컨텍스트 공급자가 없으며 예외가 발생합니다.
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. 최신 애플리케이션 아키텍처에서 JNDI의 역할
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
이 튜토리얼에서는 Java Naming 및 Directory Interface를 사용하여 객체를 연결, 바인딩 및 조회하는 것을 보았습니다. 또한 JNDI에서 발생하는 일반적인 예외를 살펴 보았습니다.
마지막으로 JNDI가 최신 애플리케이션 아키텍처에 어떻게 적용되는지 살펴 보았습니다.
항상 그렇듯이 코드는 GitHub에서 사용할 수 있습니다.