Programação para Web II

Fagno Alves Fonseca <fagno.fonseca@ifto.edu.br> Mestre em Modelagem Computacional de Sistemas – UFT.

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.

Classe PessoDao com CDI
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().

Produces
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.

Controller PessoaController
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();
    }


}

3. Referências