Java context lookup java comp env

Использование JNDI в Java

Java-университет

Использование JNDI в Java - 1

Привет! Сегодня мы познакомимся с тобой с JNDI. Узнаем, что это такое, для чего оно нужно, как работает, как нам с ним работать. А затем напишем Spring Boot юнит тест, внутри которого будем играться с этим самым JNDI.

Введение. Службы имен и каталогов

JNDI

Использование JNDI в Java - 2

JNDI, или же Java Naming and Directory Interface, представляет собой Java API для доступа к службам имен и каталогов. JNDI — это API, которое предоставляет единообразный механизм взаимодействия Java-программы с различными службами имен и каталогов. “Под капотом” интеграция между JNDI и любой конкретной службой осуществляется с помощью интерфейса поставщика услуг (Service Provider Interface, SPI). SPI позволяет прозрачно подключать различные службы именования и каталогов, что позволяет Java-приложению использовать JNDI API для доступа к подключенным службам. Рисунок ниже иллюстрирует архитектуру JNDI:

JNDI. Смысл простыми словами

  1. В конечном итоге нам нужно получить Java-объект.
  2. Мы получим этот объект из некоторой регистратуры.
  3. В этой регистратуре есть куча объектов.
  4. Каждый объект в этой регистратуре обладает уникальным именем.
  5. Чтобы получить некоторый объект из регистратуры, мы должны в своем запросе передать имя. Как бы сказать: «Дайте мне, пожалуйста, то, что у вас лежит под таким то именем».
  6. Мы можем не только считывать объекты по их имени из регистратуры, но и сохранять в данной регистратуре объекты под определенными именами (как-то ведь они туда попадают).

JNDI API

  • Lightweight Directory Access Protocol (LDAP);
  • Common Object Request Broker Architecture (CORBA);
  • Common Object Services (COS) name service;
  • Java Remote Method Invocation (RMI) Registry;
  • Domain Name Service (DNS).
  • javax.naming;
  • javax.naming.directory;
  • javax.naming.ldap;
  • javax.naming.event;
  • javax.naming.spi.
Читайте также:  Javascript object type text

Интерфейс Name

С помощью интерфейса Name можно управлять именами компонентов, а также синтаксисом имен в JNDI. В JNDI все операции с именами и каталогами выполняются относительно контекста. Абсолютных корней нет. Поэтому JNDI определяет InitialContext, который обеспечивает отправную точку для именования и операций с каталогами. После получения доступа к начальному контексту, его можно использовать для поиска объектов и других контекстов.

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

В коде выше мы определили некоторое имя, под которым находится некоторый объект (возможно, и не находится, но мы рассчитываем на это). Наша конечная цель — получить ссылку на этот объект и использовать её в нашей программе. Итак, имя состоит из нескольких частей (или токенов), разделенных слэшем. Такие токены называют контекстами (context). Самый первый — просто context, все последующие — sub-context (далее по тексту — подконтекст). Контексты проще понимать, если рассматривать их как аналогию каталогов или директорий, или просто обычных папок. Корневой контекст — корневая папка. Подконтекст — вложенная папка. Мы можем увидеть все составные части (контекст и подконтексты) данного имени, выполнив следующий код:

 Enumeration elements = objectName.getAll(); while(elements.hasMoreElements())

Вывод демонстрирует, что токены в имени отделяются друг от друга слэшем (впрочем, мы это упоминали). Каждый токен имени имеет свой индекс. Индексация токенов начинается с 0. Нулевым индексом обладает корневой контекст, следующий контекст имеет индекс 1, следующий 2, и т.д. Мы можем получить имя подконтекста по его индексу:

 System.out.println(objectName.get(1)); // -> env 
 objectName.add("sub-context"); // Добавит sub-context в конец objectName.add(0, "context"); // Добавит context в налачо 

Интерфейс Context

  • Object lookup(String name)
  • Object lookup(Name name)
  • void bind(Name name, Object obj)
  • void bind(String name, Object obj)
  • void unbind(Name name)
  • void unbind(String name)
Читайте также:  See error message php

InitialContext

  • Получить InitialContext .
  • Использовать InitialContext для извлечения объектов по имени из JNDI tree.
 InitialContext context = new InitialContext(); 

Если же это не так, получить контекст становится немного сложнее. Порой бывает необходимо передать список пропертей окружения для инициализации контекста:

 Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); Context ctx = new InitialContext(env); 

Пример выше демонстрирует один из возможных способов инициализации контекста и иной смысловой нагрузки в себе не несет. Детально погружаться в код не нужно.

Пример использования JNDI внутри SpringBoot unit теста

Выше мы говорили о том, что для взаимодействия JNDI со службой имен и каталогов необходимо иметь под рукой SPI (Service Provider Interface), с помощью которого будет осуществляться интеграция между Джавой и службой имен. Стандартная JDK поставляется с несколькими различными SPI (выше мы их перечисляли), каждый из которых не вызывает большого интереса для демонстрационных целей. Поднять JNDI и Java приложение внутри какого-нибудь контейнера в какой-то мере интересно. Однако автор этой статьи — человек ленивый, поэтому для демонстрации работы JNDI избрал путь наименьшего сопротивления: запустить JNDI внутри юнит-теста SpringBoot приложения и получить доступ к контексту JNDI с помощью небольшого хака от Spring Framework. Итак, наш план:

  • Напишем пустой Spring Boot проект.
  • Внутри этого проекта создадим юнит-тест.
  • Внутри теста продемонстрируем работу с JNDI:
    • получим доступ к контексту;
    • привяжем (bind) некоторый объект под некоторым именем в JNDI;
    • получим объект по его имени (lookup);
    • проверим, что объект не null.

Начнем по порядку. File->New->Project.Использование JNDI в Java - 3Далее выберем пункт Spring Initializr: Использование JNDI в Java - 4Заполним метаданные о проекте: Использование JNDI в Java - 5После чего выберем необходимы компоненты Spring Framework. Мы будем привязывать какие-нибудь DataSource-объекты, поэтому нам нужны компоненты для работы с БД:

  • JDBC API;
  • H2 DDatabase.

Использование JNDI в Java - 6Определим расположение в файловой системе: Использование JNDI в Java - 7И проект создан. На самом деле за нас автоматически был сгенерирован один юнит тест, которым мы и воспользуемся для демонстрационных целей. Ниже — структура проекта и нужный нам тест: Использование JNDI в Java - 8Приступим к написанию кода внутри теста contextLoads. Небольшой хак от спринга, речь о котором шла выше — это класс SimpleNamingContextBuilder . Данный класс предназначен для того, чтобы легко поднимать JNDI внутри юнит-тестов или же stand-alone приложений. Напишем код для получения контекста:

 final SimpleNamingContextBuilder simpleNamingContextBuilder = new SimpleNamingContextBuilder(); simpleNamingContextBuilder.activate(); final InitialContext context = new InitialContext(); 

Первые две строки кода позволят нам в дальнейшем простым образом инициализировать контекст JNDI. Без них при создании экземпляра InitialContext будет выброшено исключение: javax.naming.NoInitialContextException . Дисклеймер. Класс SimpleNamingContextBuilder является Deprecated классом. И данный пример призван показать, как можно поработать с JNDI. Это не лучшие практики по использованию JNDI внутри юнит-тестов. Это можно сказать костыль для построения контекста и демонстрации привязки и получения объектов из JNDI. Получив контест, мы можем извлекать из него объекты или же искать объекты в контексте. Пока что в JNDI объектов нет, поэтому логично будет положить туда что-нибудь. Например, DriverManagerDataSource :

 context.bind("java:comp/env/jdbc/datasource", new DriverManagerDataSource("jdbc:h2:mem:mydb")); 

В данной строке мы привязали объект класса DriverManagerDataSource к имени java:comp/env/jdbc/datasource . Далее мы можем получить объект из контекста по имени. Нам ничего другого не остается, кроме как получить объект, который мы положили только что, потому что других объектов в контексте нет =(

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

Теперь проверим, что наш DataSource имеет коннекшн (коннекшн, connection или соединение — это Java-класс, который предназначен для работы с базой данных):

 assert ds.getConnection() != null; System.out.println(ds.getConnection()); 
 conn1: url=jdbc:h2:mem:mydb user= 
  • simpleNamingContextBuilder.activate()
  • new InitialContext()
  • context.bind(. )
  • context.lookup(. )
 @SpringBootTest class JndiExampleApplicationTests < @Test void contextLoads() < try < final SimpleNamingContextBuilder simpleNamingContextBuilder = new SimpleNamingContextBuilder(); simpleNamingContextBuilder.activate(); final InitialContext context = new InitialContext(); context.bind("java:comp/env/jdbc/datasource", new DriverManagerDataSource("jdbc:h2:mem:mydb")); final DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/datasource"); assert ds.getConnection() != null; System.out.println(ds.getConnection()); >catch (SQLException | NamingException e) < e.printStackTrace(); >> > 
 o.s.m.jndi.SimpleNamingContextBuilder : Activating simple JNDI environment o.s.mock.jndi.SimpleNamingContext : Static JNDI binding: [java:comp/env/jdbc/datasource] = [org.springframework.jdbc.datasource.DriverManagerDataSource@4925f4f5] conn1: url=jdbc:h2:mem:mydb user= 

Заключение

Сегодня мы разбирали JNDI. Узнали о том что такое службы имен и каталогов, и что JNDI — это Java API , которое позволяет единообразно взаимодействовать с разными службами из Java программы. А именно с помощью JNDI мы можем записывать объекты в JNDI tree под некоторым именем и получать эти самые объекты по имени. В качестве бонусного задания можно запустить пример работы JNDI. Привязать в контекст какой-нибудь другой объект, а затем считать этот объект по имени.

Источник

Оцените статью