UFG - Instituto de Informática Especialização em Desenvolvimento de Aplicações Web com Interfaces Ricas EJB 3.0 Prof.: Fabrízzio A A M N Soares [email protected] Aula 9 – Recursos, Injeção de Dependência JNDI A JNDI ou Java Naming and Directory Interface é uma API para acesso a serviços de diretórios. Ela permite que aplicações cliente descubram e obtenham dados ou objetos através de um nome. Assim como todas as APIs Java, ela é independente de plataforma. JNDI Adicionalmente, ela especifica uma interface de serviço (SPI), que permite que softwares de serviço de diretório suportem o seu framework. A solução de diretório pode ser baseada em rede, arquivos ou base de dados, sendo apenas uma questão de escolha do fornecedor do produto. JNDI A API JNDI é utilizada em aplicações Java que acessam recursos externos, como base de dados, filas ou tópicos JMS e componentes JavaEE. Os administradores do sistema gravam objetos administrados num serviço de diretório disponibilizado pelo servidor de aplicações (normalmente); A aplicação busca estes objetos através da JNDI (lookup) JNDI API disponibiliza: um mecanismo para ligar um objeto a um nome; uma interface padronizada de busca de objetos no serviço de diretório; uma interface de eventos que permite que um usuário saiba quando uma entrada (nome + objeto) foi modificada; extensões que suportam as capacidades do padrão LDAP. JNDI A SPI (Service Provider Interface) permite que a JNDI suporte praticamente qualquer tipo de serviço de diretório incluíndo: LDAP DNS NIS RMI CORBA serviço de nomes Sistema de arquivos JNDI A especificação JNDI foi lançada em 10 de março de 1997 pela Sun Microsystems. A versão atual da JNDI é 1.2. Lookup Básico A JNDI organiza os nomes em uma hierarquia. Um nome pode ser qualquer string, como “org.mydomain.ejb.MyBean”. Um nome também pode ser um objeto que suporte a interface Name, porém os objetos são normalmente nomeados através de strings. Lookup Básico Cada nome na hierarquia JNDI corresponde a um objeto (ou uma referência deste objeto) gravado no serviço de diretório. A JNDI define um contexto que especifica onde procurar pelo objeto. O contexto inicial é tipicamente utilizado como ponto de partida. Lookup Básico O contexto inicial é análogo a raiz, ou topo, de uma árvore de diretórios ou sistema de arquivos. Através do objeto de contexto (Context) é realizada a busca (lookup) pelo objeto de nome org.mydomain.ejb.MyBean. Um exemplo de criação de um contexto inicial num trecho de programa em Java: Lookup Básico Hashtable args = new Hashtable(); args.put( Context.INITIAL_CONTEXT_FACTORY, "com.jndiprovider.TheirContextFactory"); args.put( Context.PROVIDER_URL, "http://jndiprovider-database"); Context ic = new InitialContext( args ); Object obj = ic.lookup( "org.mydomain.ejb.MyBean" ) Aplicação do JNDI Conexão de banco de dados ao modo convencional: Class.forName("org.apache.derby.jdbc.ClientDriver"); Connection cn = DriverManager.getConnection( "jdbc:derby://localhost:1527/MeuBanco;user=APP;password=app"); PreparedStatement ps = cn.prepareCall( "insert into cliente (codigo, nome, idade, sexo) values(?,?,?,?)"); ... ps.executeUpdate(); ps.close(); cn.close(); Aplicação do JNDI Conexão de banco de dados ao modo JNDI: InitialContext ic = new InitialContext(); DataSource ds = (DataSource) ic.lookup("jdbc/DataSource"); Connection cn = ds.getConnection(); PreparedStatement ps = cn.prepareCall( "insert into cliente (codigo, nome, idade, sexo) values(?,?,?,?)"); ... ps.executeUpdate(); ps.close(); cn.close(); Injeção de Dependência Injeção de dependência (Dependency Injection, em inglês) é um padrão de desenvolvimento de programas de computadores utilizado quando é necessário manter baixo o nível de acoplamento entre diferentes módulos de um sistema. Injeção de Dependência Nesta solução as dependências entre os módulos não são definidas programaticamente, mas sim pela configuração de uma infraestrutura de software (container) que é responsável por “injetar” em cada componente suas dependências declaradas. Injeção de Dependência Se você se preocupa em desacoplar suas classes e camadas, com certeza já precisou descobrir uma maneira de passar um objeto construído, que vou chamar de objeto de serviço (OS), a um outro objeto que vai utilizálo, que vou chamar de objeto de aplicação (OA). Injeção de Dependência Da mesma forma, se preocupou em gerar interfaces ou classes abstratas para o OS, gerando uma interface de serviço (IS) para permitir a inversão de controle, e facilitar tarefas como testes, além de facilitar o polimorfismo. Injeção de Dependência com JNDI @Resource(name = "jdbc/MeuBanco") private javax.sql.DataSource ds; Injeção de Dependência com JNDI Connection cn = ds.getConnection(); PreparedStatement ps = cn.prepareCall( "insert into cliente (codigo, nome, idade, sexo) values(?,?,?,?)"); ... ps.executeUpdate(); ps.close(); cn.close(); Pool de Conexões A idéia por trás de um pool de conexões é otimizar o acesso aos dados através de uma utilização racional das conexões feitas com uma fonte de dados. Afinal uma conexão a uma fonte de dados é consome muito recursos e precisa ser olhada com cuidado. Pool de Conexões A técnica do Connection pooling permite a uma aplicação reusar conexões que existem em um pool a invés de repetidamente fechar e criar novas conexões. Isto pode aumentar significativamente o desempenho e a escalabilidade das aplicações pois permite que um menor número de conexões atenda as requisições por conexões de uma aplicação visto que todas as conexões já estão prontas e criadas no pool a espera de serem utilizadas. Pool de Conexões Geralmente se cria um pool de conexão para cada string de conexão onde um algoritimo associa itens no pool baseado exatamente na string de conexão; quando pool é criado são criados objetos de conexão e incluídos ao pool para satisfazer o requisito mínimo de tamanho do pool especificado. Pool de Conexões Quando uma conexão é requisitada por uma aplicação e o tamanho máximo do pool foi alcançado, a requisição é enfileirada e fica aguardando até que uma conexão seja liberada para uso. A liberação de uma conexão ocorre quando ela é fechada ou liberada, neste momento ela é realocada ao pool para ser utilizada novamente. O pool de conexões gerencia as conexões que expiraram e/ou que foram liberadas e fechadas. Pool de Conexões O objeto conexão usado deverá ser fechado tão logo quanto possível para que retorne ao pool. Geralmente se faz isto usando os métodos Close() ou Dispose() do objeto Connection. Se uma conexão não for liberada ou fechada ela não pode retornar ao pool.