Nomeação de Java e visão geral da interface de diretório

Nomeação de Java e visão geral da interface de diretório

1. Introdução

A JNDI (Java Naming and Directory Interface) fornece uso consistente de serviços de nomes e/ou diretórios como uma API Java. Essa interface pode ser usada para ligar objetos, procurar ou consultar objetos, além de detectar alterações nos mesmos objetos. .

Embora o uso de JNDI inclua uma lista diversificada de serviço de nomes e serviços de diretório suportados, neste tutorial, focaremos no JDBC enquanto explora a API da JNDI.

2. Descrição JNDI

Qualquer trabalho com JNDI requer uma compreensão do serviço subjacente , bem como uma implementação acessível. Por exemplo, um serviço de conexão com o banco de dados exige propriedades específicas e tratamento de exceções.

No entanto, a abstração da JNDI desacopla a configuração da conexão do aplicativo.

Vamos explorar Name e Context, que contêm a funcionalidade principal do JNDI.

2.1. Interface Name

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

A interface Name fornece a capacidade de gerenciar os nomes e sintaxe dos componentes para nomes JNDI. O primeiro token da string representa o contexto global, depois que cada string adicionada representa o próximo sub-contexto:

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

Nossa saída se parece com:

java:comp
env
jdbc

Como podemos ver, / é o delimitador dos sub-contextos Name. Agora, vamos adicionar um sub-contexto:

objectName.add("example");

Em seguida, testamos nossa adição:

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

2.2. Interface Context

Context contém as propriedades do serviço de nomes e diretórios . Aqui, vamos usar algum código auxiliar do Spring por conveniência para criar um Context:

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

O SimpleNamingContextBuilder do Spring cria um provedor JNDI e, em seguida, ativa o construtor com o NamingManager:

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

Finalmente, JndiTemplate nos ajuda a acessar o InitialContext.

3. Ligação e Pesquisa de Objetos JNDI

Agora que vimos como usar Name e Context, vamos usar o JNDI para armazenar um JDBC DataSource:

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

3.1. Vinculando objetos JNDI

Como temos um contexto, vamos vincular o objeto a ele:

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

Em geral, os serviços devem armazenar uma referência de objeto, dados serializados ou atributos em um contexto de diretório. Tudo depende das necessidades do aplicativo.

Observe que usar JNDI dessa maneira é menos comum. Normalmente, o JNDI faz interface com dados gerenciados fora do tempo de execução do aplicativo.

No entanto, se o aplicativo já puder criar ou encontrar seu DataSource, poderá ser mais fácil conectar isso usando o Spring. Por outro lado, se algo fora do nosso aplicativo vincular objetos no JNDI, o aplicativo poderá consumi-los.

3.2. Procurando objetos JNDI

Vamos procurar nosso DataSource:

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

E então vamos testar para garantir que DataSource seja o esperado:

assertNotNull(ds.getConnection());

4. Exceções comuns de JNDI

Trabalhar com JNDI às vezes pode resultar em exceções de tempo de execução. Aqui estão alguns comuns.

4.1. NameNotFoundException

ctx.lookup("badJndiName");

Como esse nome não está vinculado nesse contexto, vemos esse rastreamento de pilha:

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)

Devemos observar que o rastreamento da pilha contém todos os objetos vinculados, o que é útil para rastrear por que a exceção ocorreu.

4.2. NoInitialContextException

Qualquer interação com o InitialContext pode gerar NoInitialContextException:

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

Devemos observar que esse uso do JNDI é válido, como o usamos anteriormente. No entanto, desta vez, não há provedor de contexto JNDI e uma exceção será lançada:

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. Papel do JNDI na arquitetura moderna de aplicativos

Embora o JNDI desempenhe menos papel em aplicativos Java leves e em contêineres , como o Spring Boot, existem outros usos. Três tecnologias Java que ainda usam JNDI são https://www..com/java-jdbc [JDBC], https://www..com/ejb-intro [EJB] e https://www..com/spring-jms [JMS]. Todos têm uma ampla variedade de usos em aplicativos corporativos Java.

Por exemplo, uma equipe separada do DevOps pode gerenciar variáveis ​​de ambiente, como nome de usuário e senha, para uma conexão sensível ao banco de dados em todos os ambientes. Um recurso JNDI pode ser criado no contêiner de aplicativo da web, com o JNDI usado como uma camada de abstração consistente que funciona em todos os ambientes.

Essa configuração permite que os desenvolvedores criem e controlem uma definição local para fins de desenvolvimento enquanto se conectam a recursos confidenciais em um ambiente de produção com o mesmo nome JNDI.

6. Conclusão

*Neste tutorial, vimos como conectar, vincular e procurar um objeto usando a interface Java Naming and Directory Interface.* Também examinamos as exceções comuns lançadas pelo JNDI.

Finalmente, vimos como o JNDI se encaixa na arquitetura moderna de aplicativos.

Como sempre, o código está disponível no GitHub.