Guia Java Enterprise Edition - Java EE

Java CDI: Criando beans com o CDI Producer

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (6)  (0)

Veja neste artigo como usar o CDI Producer para criar beans em seus projetos Java.

Motivação

Em contextos em que se está empregando o padrão injeção de dependência em Java, na maioria das vezes o CDI sabe exatamente como criar um objeto a partir da anotação @Inject. No entanto, há casos em que é necessário “ensiná-lo” como criar determinado objeto que demanda certas peculiaridades. Neste artigo veremos como proceder nessas situações utilizando a anotação @Produces, capaz de auxiliar o CDI na construção de um bean.

Como funciona o @Produces

Em casos nos quais a criação de um bean requer a execução de procedimentos adicionais, além da chamada padrão ao seu construtor, para que o CDI consiga criá-lo de maneira correta, ele procura no classpath do projeto todos os métodos e propriedades que possuem a anotação @Produces e que retornem o tipo de objeto que ele precisa. Para compreender seu funcionamento, tomemos como exemplo um bean chamado Person, cujo código é apresentado a seguir:

package br.com.devmedia;

public class Person {}

Podemos injetar esse bean em uma classe Service, que está sendo gerenciada pelo CDI. Para isso, utilizamos a anotação @Inject, como mostrado na Listagem 1.

package br.com.devmedia;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
@Named
@RequestScoped
public class Service {
    @Inject
    private Person person;
}
Listagem 1. Classe Service injetando a classe Person

Nesse caso, quando o objeto do tipo Person for injetado, o CDI saberá que deve chamar o construtor dessa classe. Porém, podem haver situações em que se torna necessário criar esse bean de uma forma diferente, por exemplo, a partir da chamada a um web service. Em situações como essa, precisamos criar um produtor (Producer) capaz de criar um objeto Person conforme desejamos, como mostra a Listagem 2.

package br.com.devmedia;
import javax.enterprise.inject.Produces;
public class PersonProducer {
    
    @Produces
    public Person createPerson(){
        return callWebService();
    }
}
Listagem 2. Criando um Producer para a classe Person

Nesse exemplo, a classe PersonProducer abstrai a lógica de criação do objeto Person, que aqui simula a chamada a um web service. Perceba que o método createPerson(), independentemente da sua lógica, sempre deverá retornar um objeto do tipo Person e também possuir a anotação @Produces. Essas duas características são suficientes para o CDI entender qual método ele deve chamar a fim de criar um objeto do tipo Person.

Criando um Producer para um EntityManager

Agora que já compreendemos como o CDI trabalha para criar instâncias de objetos injetados dinamicamente, veremos um novo exemplo que ilustra um caso muito comum em projetos Java: a criação de um EntityManager proveniente do JPA através de um CDI Producer. O CDI, por si só, não sabe como criar um EntityManager, o que significa que usar apenas o @Inject não resolveria, pois ele sempre retornaria um objeto

Para simular essa situação, temos na Listagem 3 um exemplo de injeção do EntityManager em uma classe DAO, responsável por realizar as operações direto na base de dados.

package br.com.devmedia;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
@Named
@RequestScoped
public class DAO {
    @Inject
    private EntityManager em;
    public void save(Object o){
        em.persist(o);
    }
}
Listagem 3. Injetando o EntityManager no DAO

Ao chamar o método save(), teremos uma NullPointerException, pois o objeto em terá valor nulo, uma vez que o CDI não sabe como criar uma instância de EntityManager. Para solucionar esse problema, precisaremos criar um Producer, semelhante ao que fizemos na Listagem 2. Na Listagem 4 podemos ver o código da classe EntityManagerProducer, solução para o nosso problema.

01 package br.com.devmedia;
02
03 import javax.enterprise.inject.Disposes;
04 import javax.enterprise.inject.Produces;
05 import javax.persistence.EntityManager;
06 import javax.persistence.EntityManagerFactory;
07 import javax.persistence.Persistence;
08 import java.io.Serializable;
09
10 public class EntityManagerProducer implements Serializable {
11
12    private static final long serialVersionUID = 1L;
13    private static EntityManagerFactory emf =
14 Persistence.createEntityManagerFactory("persistenceUnit");
15
16    @Produces
17    public EntityManager createEntityManager() {
18        return emf.createEntityManager();
19    }
20
21    public void close(@Disposes EntityManager em) {
22        if (em.isOpen()) {
23            em.close();
24        }
25    }
26
27    public EntityManagerFactory getEmf() {
28        return emf;
29    }
30
31    public void setEmf(EntityManagerFactory emf) {
32        this.emf = emf;
33    }
34 }
Listagem 4. Criando um Producer para o EntityManager

Linha 13: Criamos um EntityManagerFactory apontando para nosso persistenceUnit, contido dentro do arquivo persistence.xml. Esse objeto servirá para criar o EntityManager;

Linha 16: A partir daqui começamos a produzir o EntityManager. Perceba que o método retorna um objeto desse tipo e possui a anotação @Produces. Portanto, ele será chamado pelo CDI quando necessário;

Linha 21: A anotação @Disposes faz o inverso da @Produces, ou seja, destrói a instância da classe injetada. Assim, quando o EntityManager for destruído, o método close() da classe EntityManagerProducer será chamado, fechando a conexão com o banco de dados através do método em.close().

A partir dessa implementação, quando o CDI precisar criar um EntityManager, ele irá produzi-lo e destruí-lo de acordo com a lógica implementada na classe EntityManagerProducer.

Saber como o CDI funciona é fundamental para que se obtenha os resultados esperados quando for necessário utilizar a injeção de dependências, garantindo que os objetos sejam criados corretamente pelo framework.

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?