Programação para Web II
1. Injeção de dependências e Contexto - CDI
CDI, acrônimo de Contexts and Dependency Injection, é uma especificação do Java EE responsável por fazer o controle da injeção de dependências nas aplicações.
O CDI define contextos para especificar e gerenciar os ciclos de vida do bean gerenciado e usa injeção de dependência para satisfazer as dependências declaradas de uma maneira segura e dinâmica. Injeção de dependência é tornar disponível a instância de uma classe quando for necessário. Desta forma, passamos a responsabilidade de criar instâncias para o container.
Para injetar uma dependência você deve usar a anotação @Inject. Esta anotação indica que queremos injeção de dependências nos pontos em que for utilizada.
2. Utilizando CDI em seu projeto web
Iremos complementar o exemplo utilizado no capítulo anterior 'JPA e Hibernate'. Vamos alterar o projeto para que o mesmo utilize CDI.
Vamos iniciar efetuando as alterações na classe 'PessoaDao'. Observe que usamos a anotação @Inject do pacote 'javax.inject.Inject' para que o container faça a injeção de um EntityManager. Observe que não estamos utilizando a classe 'JpaUtil' conforme era feito no exemplo anterior.
package com.mycompany.projetoexemplo.model.dao;
import javax.persistence.EntityManager;
import javax.inject.Inject;
@Dependent
public class PessoaDao {
@Inject
EntityManager manager;
}
2.1. Escopos de componentes
No exemplo acima é utilizado a anotação @Dependent, que indica como os componentes serão criados, para que o nosso container possa fazer isso quando necessário.
O @Dependent é o escopo dependente, ou seja, uma instância será criada para cada objeto que precisar dessa dependência. Este escopo descreve a mesma situação que ocorre quando criamos objetos. Quando esse objeto morrer, a instância do componente morre junto.
Outros escopos são descritos:
@RequestScoped: o escopo de requisição indica que cada requisição terá uma instância diferente desse componente, que será compartilhada entre todos os objetos que dependerem desse componente. Ao final da requi- sição o objeto é destruído.
@SessionScoped: o escopo de sessão indica que cada instância será criada por usuário.
@ConversationScoped: o escopo de conversação é um escopo intermediário entre o escopo de requisição e o de sessão. Você pode definir o início e o fim do escopo explicitamente, recebendo como dependência uma Conversation.
@ApplicationScoped: o escopo de aplicação indica que apenas uma instância do componente será criada na aplicação.
2.2. Criando o Produces
Vamos alterar a classe JpaUtil do capítulo anterior 'JPA e Hibernate', para que o CDI consiga injetar o EntityManager. O próprio servidor vai gerenciar a implementação, no entanto, precisamos informar ao CDI como fazer isso.
Na classe JpaUtil, definimos um método para criar um EntityManagerFactory. A @ApplicationScoped indica que esta instância será criada uma única vez, conforme descrito no tópico anterior.
Toda vez que o @Inject é utilizado, o CDI vai procurar por alguma classe que atenda essa implementação.
Quando a aplicação necessitar do EntityManager, o servidor vai procurar por algum método que esteja anotado com @Produces para retornar uma instância dessa dependência. Observe que os métodos factory() e manager() possuem a anotação @Produces. Deste modo, quando for requisitado uma dependência de EntityManager o CDI vai entender que necessita criar um EntityManagerFactoty e vai instanciar a classe e executar o método factoty().
package com.mycompany.model.util;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
* @Dependent: escopo dependente, ou seja, uma instância será criada para cada objeto que precisar dessa dependência.
*/
@Dependent
public class JpaUtil{
/**
* Método para criar um EntityManagerFactory
* @return um EntityManagerFactory quando for necessário uma instância do de EntityManagerFactory.
*/
@ApplicationScoped
@Produces
public EntityManagerFactory factory() {
return Persistence.createEntityManagerFactory("aulawebii");
}
/**
* Método para criar um EntityManager
* @param factory o CDI já sabe que, se tiver que executar esse método, precisa passar os parâmetros
* @return EntityManager quando for necessário uma instância do de EntityManager na anotação @Inject.
*/
@Produces
public EntityManager manager(EntityManagerFactory factory) {
return factory.createEntityManager();
}
/**
* Como o EntityManagerFactory é @ApplicationScoped, será fechado apenas uma vez, quando o servidor estiver sendo parado. Já o EntityManager será
* fechado várias vezes, sempre que alguém terminar de usá-lo.
* @param factory
*/
public void close(@Disposes EntityManagerFactory factory) {
factory.close();
}
/**
* O método deve será chamado quando acabarmos de usar o manager, ou seja, quando a instância do manager puder ser jogada fora. Conseguimos fazer
* isso com o callback @Disposes do CDI.
*/
public void close(@Disposes EntityManager manager) {
manager.close();
}
}
Outros dois métodos close() são definidos na classe com parâmetros diferentes, ou seja, callback @Disposes. A anotação @Disposes indica quando a instância do EntityManagerFactory e EntityManager pode ser encerrada.
Como o EntityManagerFactory é @ApplicationScoped, será fechado apenas uma vez, quando o servidor estiver sendo parado. Já o EntityManager será fechado várias vezes, sempre que alguém terminar de usá-lo.
2.3. Controller
Nosso controller terá uma instância de 'PessoaDao' anotado com o @Inject. Observe que o servidor vai instânciar essa classe conforme o escopo @dependent definido na classe PessoaDao.
package com.mycompany.projetoexemplo.controller;
import br.com.caelum.vraptor.Controller;
import com.mycompany.projetoexemplo.dao.PessoaDao;
import com.mycompany.projetoexemplo.model.Pessoa;
import java.util.List;
import javax.inject.Inject;
/**
*
* @author fagno
*/
@Controller
public class PessoasController{
@Inject
PessoaDAO dao;
public List<Pessoa> lista(){
return dao.pessoas();
}
}