Primeiras aulas do curso CDI 1.2: Use uma das principais especificações do JavaEE.

CDI 1.2: Use uma das principais especificações do JavaEE.

Configurando projeto para utilização do CDI - Subindo o projeto

CDI

Seja bem-vindo ao curso de CDI da Alura.

Neste curso vamos ver alguns recursos bem peculiares e alguns um pouco mais avançados.

do CDI.

Na plataforma da Alura, temos um curso introdutório de JSF no qual abordamos como utilizar o CDI.

Nós iremos utilizar como base o projeto do JSF com CDI. Nosso objetivo é configurar o projeto para utilizar o CDI e, em seguida, criar uma biblioteca construída por nós, e que poderá ser reutilizada em outros projetos que utilizem a plataforma Java EE.

Apesar de utilizar como base o projeto de um outro curso, o projeto atual está um pouco diferente. Agora estamos utilizando o Maven para fazer o gerenciamento do _build_. Em vez de adicionar de forma manual todos os jars dentro do _classpath_, vamos utilizar o Maven para baixar os jars e adicioná-los dentro do _classpath_.

Se você não conhece o Maven, sugerimos que você faça antes nosso curso de Maven. E voltar depois para este curso, já com um entendimento do que é o Maven e o que a ferramenta nos possibilita fazer.

A mesma recomendação serve para o JSF. Vamos falar de algumas coisas específicas do JSF, utilizando o CDI, mas é interessante que você já conheça um pouco do JSF.

Vamos começar importando o nosso projeto. Como citado anteriormente, vamos utilizar um projeto Maven. Descompactamos o projeto em algum diretório do sistema, e temos o diretório livraria, que dentro dele possui o arquivo pom.xml do Maven. Agora podemos simplesmente importar o projeto no Eclipse.

Pasta com projeto

Projeto com o pom.xml

Clique com o botão direito na área branca à esquerda do Eclipse. Em seguida, escolha a opção Import > Import.... Você também pode realizar esse mesmo passo usando o menu File > Import....

Import Eclipse

Na próxima tela, escolha a opção "Existing Maven Project" - você pode pesquisar pela palavra "maven" na caixa de busca, assim será mais fácil encontrar a opção.

Existing Maven Project

Na próxima tela, clique em "Browse..." para selecionar o diretório onde o projeto foi descompactado. Selecione o diretório livraria.

Perceba que ao selecionar uma pasta que possui o projeto Maven, o Eclipse lista o arquivo pom.xml em "Projects". Para finalizar clique em "Finish".

Select Project

Diretório Livraria

Finish

A primeira vez que você importar o projeto, talvez tenha que esperar um pouco, pois o Maven baixará todas as dependências do repositório central. Depois que ele fizer isto pela primeira vez, é feito um "cache" local, que sempre reutilizará as dependências locais que já foram baixadas.

Entendendo as dependências do projeto

Após a finalização da importação do projeto, vamos dar uma olhada nas dependências que o nosso projeto possui, abrindo o arquivo pom.xml.

Estrutura do projeto

No seguinte trecho de código, é possível ver que estamos utilizando a versão 8 do Java.

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Na seguinte linha, que é possível encontrar logo no início do arquivo, indica que será gerado um pacote .war.

<packaging>war</packaging>

O projeto utiliza o Hibernate. Em seguida temos duas dependências que são referentes ao JSF - já que este é utilizado pela aplicação.

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>4.1.8.Final</version>
</dependency>

<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-api</artifactId>
    <version>2.2.13</version>
</dependency>

<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-impl</artifactId>
    <version>2.2.13</version>
</dependency>

A próxima dependência é o driver do MySQL, para que seja possível se conectar com o banco de dados.

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.22</version>
</dependency>

A dependência do hibernate-validator está inclusa porque o projeto utiliza algumas coisas da Bean Validation.

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.3.0.Final</version>
</dependency>

E por fim, duas dependências referentes ao PrimeFaces: O PrimeFaces em si e seus temas.

<dependency>
    <groupId>org.primefaces.themes</groupId>
    <artifactId>all-themes</artifactId>
    <version>1.0.10</version>
</dependency>

<dependency>
    <groupId>org.primefaces</groupId>
    <artifactId>primefaces</artifactId>
    <version>5.3</version>
</dependency>

O PrimeFaces pede que seja adicionado seu repositório para obter a dependência do tema. Portanto, no seguinte trecho de código, temos adicionada a configuração do repositório.

<repositories>
    <repository>
        <id>prime-repo</id>
        <name>PrimeFaces Maven Repository</name>
        <url>http://repository.primefaces.org</url>
        <layout>default</layout>
    </repository>
</repositories>

Para finalizar, último a tag finalName define o nome do artefato gerado, que nesse caso será livraria.war. E foi também adicionado um plugin do Maven para gerar os nossos wars.

<build>
    <finalName>livraria</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.6</version>
        </plugin>
    </plugins>
</build>

Ao expandir a pasta Java Resources > src/main/java, podemos ver os pacotes e classes da aplicação. Os beans estão relacionados com nossas views, os arquivos .xhtml. Temos também os DAOs, os modelos e classes utilitárias.

Estrutura das classes

Configurando o Servlet Container

Agora que conseguimos importar nossas aplicação, vamos precisar de alguém para rodar a aplicação Web. Nesse momento não vamos utilizar um servidor de aplicação, mas um Servlet Container, o Tomcat. Após fazer o Download do Tomcat, descompacte em um diretório de sua preferência.

No Eclipse, na aba Servers, clique na mensagem "No servers are available. Click this link to create a new server...".

Server Tab

Na tela que irá parecer, Selecione Apache > Tomcat v8.0 Server e clique em "Next".

Tomcat v8

Na próxima tela, clique em "Browser" e selecione o diretório do Tomcat. Feito isso, clique em "Finish".

Browser Tomcat

Diretório Tomcat

Finish Tomcat

Na aba Servers, já é possível ver o Tomcat configurado.

Serves Tomcat

Configurando o banco de dados

Resta um último passo. Nossa aplicação se comunicará com o banco de dados. Se você olhar dentro do diretório src/main/resources > META-INF, existe o arquivo persistence.xml. O persistence.xml é o arquivo de configuração para que a aplicação possa se comunicar com o banco de dados.

Devido a seguinte linha do persistence.xml, nossa aplicação espera que exista um banco de dados chamado livrariadb. Vamos criar essa banco de dados agora.

<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/livrariadb" />

Segundo nossa configuração, o banco de dados MySQL não possui senha:

<property name="javax.persistence.jdbc.password" value="" />

Vamos nos conectar a servidor do MySQL:

$ mysql -u root

E em seguida, já conectados, vamos criar o banco de dados:

> create database livrariadb;

Create database

Ao acessarmos o banco, e listarmos as tabelas, vamos ver que não existe nenhuma tabela porque acabamos de criar o banco.

> use livrariadb;
Database changed

> show tables;
Empty set (0,00 sec)

Para iniciarmos com alguns dados e não seja preciso que esses dados tenham que ser cadastrados manualmente, vamos importar um script. Saia do mysql utilizando o comando exit.

> exit

Vamos utilizar o comando cd e navegar até o diretório onde se encontra o arquivo import.sql. Dentro desse arquivo existem vários comandos SQL que desejamos que o MySQL execute.

Navegando até o diretório do arquivo

Podemos ver o conteúdo do arquivo utilizando o comando cat. O arquivo possui comandos para excluir as tabelas caso existam e em seguida criá-las. Também são inseridos alguns dados no banco. Você pode verificar o conteúdo completo na sua máquina ao executar o comando cat, ou abrindo o arquivo no seu editor de textos preferido.

$ cat import.sql 

DROP TABLE IF EXISTS `Autor`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `Autor` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(255) DEFAULT NULL,
  `nome` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `Autor`
--

LOCK TABLES `Autor` WRITE;
/*!40000 ALTER TABLE `Autor` DISABLE KEYS */;
INSERT INTO `Autor` VALUES (1,'sergio.lopes@caelum.com.br','Sergio Lopes'),(2,'nico.steppat@caelum.com.br','Nico Steppat'),(3,'aniche@teste.com.br','Mauricio Aniche'),(4,'flavio.almeida@caelum.com.br','Flavio Almeida'),(5,'paulo.silveira@caelum.com.br','Paulo Silveira');
/*!40000 ALTER TABLE `Autor` ENABLE KEYS */;
UNLOCK TABLES;

/* restante do arquivo... */

Queremos que o script seja executado dentro do banco de dados livraria. Para importar, utilizamos o comando mysql, fornecendo os dados de login, o nome do banco no qual desejamos executar o script e o caminho para o script.

$ mysql -u root livrariadb < import.sql

Após digitar o comando, pressione "Enter". Pode demorar alguns segundos. Vamos logar novamente no MySQL para conferir se os dados foram importados.

Vamos utilizar o comando use livrariadb para selecionar o banco de dados e em seguida o comando show tables para listar as tabelas.

$ mysql -u root livrariadb

> use livrariadb;

> show tables;
+----------------------+
| Tables_in_livrariadb |
+----------------------+
| Autor                |
| Livro                |
| Livro_Autor          |
| Usuario              |
+----------------------+
4 rows in set (0,00 sec)

Agora vamos fazer um querie para verificar se foi inserido o usuário admin com a senha 12345 na tabela Usuario .

> select * from Usuario;
+----+---------------------+-------+
| id | email               | senha |
+----+---------------------+-------+
|  1 | admin@caelum.com.br | 12345 |
+----+---------------------+-------+
1 row in set (0,00 sec)

Pronto! Podemos ver que um registro já foi inserido. Temos nosso banco de dados totalmente populado. Desta forma, não precisamos ficar nos preocupando em cadastrar as informações manualmente.

Fazendo deploy do projeto

Agora que configuramos o Tomcat e banco de dados, vamos subir nossa aplicação.

No Eclipse, na aba Servers, clique com o botão direito no Tomcat e escolha a opção "Add and Remove".

Add and Remove...

Na tela que irá aparecer, selecione o projeto e clique no botão "Add". Em seguida, clique em "Finish".

Add

Clique no botão destacado na imagem seguinte, para iniciar o Tomcat.

Start Tomcat

Não recebemos nenhuma mensagem de erro no Console, então aparentemente, tudo ok.

Tomcat OK

Para conferir a aplicação, basta acessar http://localhost:8080/livraria/login.xhtml no seu navegador.

Página de Login

Para verificar de onde vem o Login, se você expandir a pasta Deployed Resources > webapp, poderá ver que lá se encontram os arquivos que podemos acessar.

Arquivos xhtml

Se você tentar acessar a página dos livros, será direcionado para a página de login. Existe uma regra na classe Autorizador (pacote br.com.alura.livraria.util) que indica quando você não possui um usuário logado, então, a aplicação redirecionará para a página de login.

Você pode efetuar o login utilizando os dados que buscamos anteriormente no banco:

usuário: admin@caelum.com.br, senha: 12345.

Após o login temos acesso à página de livros.

Página livro

O intuito desta aula era preparar todo o ambiente. Agora que está tudo configurado e funcionando, mais adiante começaremos a utilizar o CDI. Até lá!

Configurando projeto para utilização do CDI - Introdução ao CDI

Agora que já temos nosso projeto funcionando, vamos entender o que é o CDI e como ele pode nos ajudar.

O CDI é uma especificação do Java EE de contexto e injeção de dependências (Contexts and Dependency Injection). O CDI gerencia as nossas dependências e as injeta quando são necessárias em algum ponto do nosso código.

Agora vamos ver por que precisamos ter essa injeção de dependências no projeto. Vamos tomar como exemplo a classe DAO e dar uma olhada no método adicona().

Se observarmos o método adiciona() do ponto de vista de suas responsabilidades, veremos que o método faz muitas coisas. A primeira linha de código ria um EntityManager e, em seguida, é aberta uma transação. Depois o objeto é salvo de fato no banco chamando o método persist(). Em seguida, a transação é fechada para depois o fechar o EntityManager com a chamada do close().

public void adiciona(T t) {

    // consegue a entity manager
    EntityManager em = new JPAUtil().getEntityManager();

    // abre transacao
    em.getTransaction().begin();

    // persiste o objeto
    em.persist(t);

    // commita a transacao
    em.getTransaction().commit();

    // fecha a entity manager
    em.close();
}

Qual é o problema de um método possuir várias responsabilidades dentro dele? O problema é que não temos um método coeso. Ou seja, o fato de que possua várias responsabilidades faz com que ele conheça várias classes. No caso do método adiciona(), ele conhece a classe JPAUtil, e dentro dentro do EntityManager - que deveria conhecer apenas o método persist(), já que a intenção deste é persistir um dado -, ele conhece métodos que gerenciam transações, por exemplo.

Por que não é legal conhecer essas classes e esses vários métodos? Vamos utilizar como exemplo o método getEntityManager da classe JPAUtil.

public EntityManager getEntityManager() {
    return emf.createEntityManager();
}

Imagine que criamos uma funcionalidade na qual o método EntityManager agora recebe uma String que irá no dizer para qual banco ele irá gerar o EntityManager. Vamos adicionar um novo parâmetro no método, chamado db e é do tipo String. Dentro do método teríamos que implementar uma lógica em que dada a String, ele criaria o EntityManager para um banco específico. No nosso caso basta apenas que o método receba a String.

public EntityManager getEntityManager(String db) {
    return emf.createEntityManager();
}

A partir do momento que passamos a receber uma String, o DAO irá parar de compilar. O método getEntityManager() espera receber uma String agora, mas não antes, e por esse motivo não havíamos fornecido qualquer argumento. Por isso é que temos um problema que o método adiciona() (e os outros métodos do DAO) conheçam detalhes demais da classe JPAUtil.

DAO sem compilar

Esse é um problema de acoplamento: estamos muito acoplados à classe JPAUtil, e qualquer alteração que se faça nela, refletirá na classe DAO. Será que apenas a classe DAO parou de funcionar? Se olharmos no nosso projeto, temos a classe UsuarioDao, que também não funciona mais por ter a seguinte linha de código.

EntityManager em = new JPAUtil().getEntityManager();

A classe UsuarioDAO conhece detalhes da classe JPAUtil e qualquer alteração na assinatura dos métodos ou construtor dessa classe irá refletir também na classe UsuarioDao.

O que fazer para resolver esse problema? Uma das formas que temos é simples: quando paramos para pensar na responsabilidade da nossa classe DAO, ela não precisa criar um EntityManager, mas sim do objeto pronto para que ela possa utilizar. Então, se precisamos de um objeto, podemos pedir o objeto pronto por meio do construtor.

Vamos remover a criação do EntityManager do método adiciona:

public void adiciona(T t) {

    // criação do EntityManager removida

    // abre transacao
    em.getTransaction().begin();

    // restante do código
}

Agora vamos adicionar um parâmetro a mais no nosso construtor que será justamente o EntityManager. Além disso vamos atribuir o valor da variável para um atributo da classe. Dessa forma o método adiciona() agora irá utilizar esse atributo (em):

private final Class<T> classe;
private EntityManager em;

public DAO(Class<T> classe, EntityManager em) {
    this.classe = classe;
    this.em = em;
}

Após essa mudança, o método adiciona() já não precisa mais conhecer detalhes da classe JPAUtil. Ainda temos alguns problemas, pois ainda sabemos como criar uma transação e commitar a transação, por exemplo. Mas agora não precisamos mais conhecer a classe JPAUtil, que cria esse EntityManager. Apenas queremos o objeto pronto para utilizarmos.

Porém quando salvamos o arquivo DAO.java com essas alterações, quebramos outras classes. Se olharmos nossos beans, quebramos o AutorBean, o LivroBeans, e o VendasBean. E por quê? Mais uma vez temos problemas de acoplamento.

Beans quebrados

Se verificarmos a classe AutorBean, na seguinte linha de código no método carregarAutorPelaId:

this.autor = new DAO<Autor>(Autor.class).buscaPorId(autorId);

Está sendo instanciado um objeto da classe DAO. Precisamos agora suprir essa dependência que o construtor da classe DAO espera receber. Precisamos injetar essa dependência.

this.autor = new DAO<Autor>(Autor.class, manager).buscaPorId(autorId);

Isso que fizemos, de receber a dependência de uma classe pelo construtor em vez de criá-las, chama-se inversão de controle. Nós invertemos o controle da criação do objeto. A gerencia da criação do objeto não é mais responsabilidade da classe que necessita dele. A classe apenas espera o objeto pronto.

Do outro lado, temos alguém que está injetando a dependência da inversão que fizemos. Como invertemos o controle no DAO, no AutorBean, por exemplo precisamos passar essa dependência.

É justamente nessa parte que o CDI irá no ajudar. Vamos declarar que precisamos de uma informação e o CDI põe a informação pra gente. Ainda temos problema no AutorBean, pois vimos que instanciar a classe não é muito interessante porque geramos um acoplamento com a nossa classe, já que estamos instanciando.

A classe DAO é utilizada em AutorBean nos métodos carregarAutorPelaId() e gravar(). Talvez seja interessante declarar como uma dependência também, já que precisamos da classe DAO pronta para executarmos as tarefas.

public void carregarAutorPelaId() {
    this.autor = dao.buscaPorId(autorId);
}

public String gravar() {
    System.out.println("Gravando autor " + this.autor.getNome());

    if(this.autor.getId() == null) {
        new dao.adiciona(this.autor);
    } else {
        new dao.atualiza(this.autor);
    }

    this.autor = new Autor();

    return "livro?faces-redirect=true";
}

public void remover(Autor autor) {
    System.out.println("Removendo autor " + autor.getNome());
    dao.remove(autor);
}

public List<Autor> getAutores() {
    return dao.listaTodos();
}

Seria necessário adicionar um construtor na classe AutorBean, bem como adicionar um atributo que irá receber a referência passada no construtor:

private DAO<Autor> dao;

public AutorBean(DAO<Autor> dao) {
    this.dao = dao;
}

A classe AutorBean agora compila. Então recebemos a dependência do DAO e utilizamos em várias partes da classe. E não precisamos criar a dependência. O CDI vai fazer essa ponte, onde declaramos a dependência e ele irá injetar a dependência para nós.

Na próxima aula vamos ver como configurar o CDI no nosso projeto.

Configurando projeto para utilização do CDI - Configurando o CDI

Adicionando a dependência do Weld

Antes de começarmos a falar sobre as configurações, vamos deixar claro que as alterações feitas na aula anterior foram desfeitas para essa aula.

Agora que já vimos a ideia por trás do CDI, vamos ver como configurá-lo em nosso projeto. Vamos declarar a dependência do CDI no arquivo pom.xml e um jar será baixado e inserido dentro do nosso projeto.

O CDI é uma especificação, e por isso precisamos de alguém que implemente essa especificação para que seja possível utilizá-lo. A implementação de referência do CDI é o Weld. Portanto, vamos procurar a dependência do Weld para o Maven e assim adicionarmos no arquivo pom.xml.

Para isso, podemos fazer uma simples busca no Google, pesquisando por "weld maven". O primeiro link da pesquisa deve ser do site www.mvnrepository.com. Ao clicarmos no link, veremos algumas dependências disponíveis.

Pesquisando Weld

O Weld pode funcionar tanto em ambiente Web (Java EE)) como em ambiente "não Web", como Desktop (Java SE). No nosso caso, como se trata de um ambiente Web, utilizaremos a dependência do org.jboss.weld.servlet

Group - Weld

Ao acessar o org.jboss.weld.servlet, podemos ver algumas formas de baixar o Weld. Aqui vamos utilizar o Weld Servlet (Uber Jar). Um Uber Jar é um jar mais "inchado", em que o Weld colocou dentro desse jar todas as suas outras dependências. Desta forma, baixamos um único jar e já temos tudo que é preciso para rodar.

Weld Uber Jar

Após clicar em Weld Servlet (Uber Jar), vamos ver uma página com várias versões dessa dependência. A versão que iremos utilizar neste curso será a 2.3.5.Final - a última versão estável no momento que o curso foi gravado. Vamos clicar no link da versão 2.3.5.Final e veremos o conteúdo que devemos adicionar no arquivo pom.xml.

Dependência Weld

Vamos adicionar o conteúdo referente à dependência no arquivo pom.xml, dentro da tag dependencies.

Pode ser que demore um pouco para baixar a dependência, caso ela já não esteja em seu repositório local.

Dependência pom

<dependencies>
    <!-- outras dependencias -->

    <dependency>
        <groupId>org.primefaces</groupId>
        <artifactId>primefaces</artifactId>
        <version>5.3</version>
    </dependency>

    <dependency>
        <groupId>org.jboss.weld.servlet</groupId>
        <artifactId>weld-servlet</artifactId>
        <version>2.3.5.Final</version>
    </dependency>
</dependencies>

O arquivo beans.xml

Após a conclusão do Download da dependência do Weld, temos que realizar algumas configurações. A especificação do CDI pede que tenhamos um arquivo chamado beans.xml dentro do diretório WEB-INF.

Dentro de Deplyed Resources > webapp > WEB-INF será criado um novo arquivo .xml. Vamos selecionar a pasta WEB-INF e utilizar o atalho "Ctrl + N" do Eclipse. Na tela que irá aparecer, basta digitar "xml" no campo de busca.

XML file

O nome do arquivo deve ser beans.xml. Feito isso, vamos clicar em "Finish".

Nome do arquivo

Este é o arquivo de configuração para que seja possível rodar o CDI. Vamos abrir o arquivo e clicar na tab "Source", do Eclipse, para que seja possível ver o código do arquivo. O arquivo deve ter o seguinte conteúdo:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
     version="1.2" bean-discovery-mode="all">

</beans>

Temos a tag <beans> no beans.xml, onde são definidos os namespaces que serão necessários. Temos também o trecho version="1.2" que indica a versão do CDI utilizada. Encontraremos ainda o bean-discovery-mode="all", que se não for declarado, não terá o valor all por padrão. O discovery-mode é a estratégia que o CDI utilizará para encontrar as nossas classes e saber se elas podem ou não ser injetadas. Existem três estratégias:

O valor padrão do bean-discovery-mode é annoted.

Configurações do Servlet Container

Essa é a única configuração que é solicitada pela especificação para que comecemos a utilizar o CDI dentro do nosso projeto. Mas isso ocorre apenas em um projeto Java EE, quando estamos utilizando um servidor de aplicação. Nem mesmo seria necessária a dependência no pom.xml porque o servidor já possui uma implementação do CDI.

Mas como estamos utilizando um Servlet Container, precisaremos ensinar para o Tomcat nos casos em que ele cria um objeto que o CDI precisará ou quando deve ser iniciado o CDI, por exemplo. Então vamos fazer essas configurações.

Para o CDI funcionar, é preciso que exista um objeto do tipo BeanManager. Este irá abrir um contexto, localizar uma dependência (candidato a ser injetado), disparar um evento e diversas outras coisas. É um objeto muito importante para o CDI. O CDI pede na especificação que esse objeto esteja acessível via JNDI, que é uma outra especificação.

Na JNDI, temos um nome e é a partir dele, que ela irá pegar no container, e depois, será devolvido o objeto. Então o que vamos ensinar agora para o Tomcat é como criar o objeto. Em seguida, no arquivo web.xml, vamos indicar que o nome BeanManager está associado àquele tipo específico. Quando alguém pedir por um BeanManager, será devolvido um objeto desse tipo.

O primeiro passo é selecionar o diretório webapp e criar um outro diretório chamado META-INF. Após selecionar o diretório vamos utilizar o atalho "Ctrl + N" e pesquisar por folder na tela mostrada.

Folder

META-INF

Dentro do diretório META-INF, vamos criar agora o arquivo de configuração do Tomcat chamado context.xml.

Dentro deste arquivo, vamos declarar que dado um tipo, qual será o objeto utilizado para gerar esse tipo. Então se precisamos de um BeanManager, vamos declarar quem cria esse BeanManager para nós. O arquivo context.xml ficará com o seguinte conteúdo:

<Context>
    <Resource name="BeanManager" 
       auth="Container"
       type="javax.enterprise.inject.spi.BeanManager"
       factory="org.jboss.weld.resources.ManagerObjectFactory"/>
</Context>

Temos um recurso (Resource) chamado BeanManager e sempre que for preciso um objeto do tipo javax.enterprise.inject.spi.BeanManager será utilizado o org.jboss.weld.resources.ManagerObjectFactory para criar esse tipo.

Vamos salvar o arquivo e em seguida realizar a configuração no arquivo web.xml. Vamos criar um listener, alguém que irá ficar ouvindo quando subir o contexto - e também será o responsável por subir o CDI.

Antes do fechamento da tag </web-app>, vamos declarar o listener e em seguida que BeanManager estará associado ao tipo que configuramos no context.xml. O arquivo ficará com o seguinte conteúdo:

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:web="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <!-- restante do conteudo -->


    <listener>
        <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
    </listener>

    <resource-env-ref>
        <resource-env-ref-name>BeanManager</resource-env-ref-name>
        <resource-env-ref-type>
            javax.enterprise.inject.spi.BeanManager
        </resource-env-ref-type>
    </resource-env-ref>
</web-app>

Na tag <resource-env-ref>, estamos indicando que quando precisarmos de um recurso com o nome BeanManager, vamos devolver um objeto do tipo javax.enterprise.inject.spi.BeanManager. E lá no arquivo context.xml definimos que quem cria um objeto do tipo javax.enterprise.inject.spi.BeanManager é o org.jboss.weld.resources.ManagerObjectFactory.

Após fazer essas alterações já é possível subir a nossa aplicação. Vamos iniciar o Tomcat e acompanhar o console.Ao acessar a aba Console do Eclipse, é possível ver a mensagens indicando que o Weld foi inicializado com sucesso:

...
INFO: WELD-ENV-001008: Initialize Weld using ServletContainerInitializer
dez 08, 2016 10:00:56 AM org.jboss.weld.bootstrap.WeldStartup <clinit>
INFO: WELD-000900: 2.3.5 (Final)
dez 08, 2016 10:00:57 AM org.jboss.weld.bootstrap.WeldStartup startContainer
INFO: WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
dez 08, 2016 10:00:58 AM org.jboss.weld.environment.tomcat.TomcatContainer initialize
INFO: WELD-ENV-001100: Tomcat 7+ detected, CDI injection will be available in Servlets, Filters and Listeners.
dez 08, 2016 10:00:58 AM org.jboss.weld.environment.servlet.Listener contextInitialized
INFO: WELD-ENV-001006: org.jboss.weld.environment.servlet.EnhancedListener used for ServletContext notifications
dez 08, 2016 10:00:58 AM com.sun.faces.config.ConfigureListener contextInitialized
...

Utilizando o CDI

Agora vamos acessar http://localhost:8080/livraria/login.xhtml e realizar o login. O login vai verificar se existe um usuário no banco de dados com a senha que foi fornecida. Caso existe seremos direcionados para a página de livros.

Login

Agora que verificamos que tudo continua funcionando, vamos começar a utilizar o CDI dentro do nosso projeto.

Quem está criando os nossos beans é o JSF, utilizando a anotação @ManagedBean. Por exemplo:

@ManagedBean
public class AutorBean implements Serializable {

Por esse motivo, não vamos conseguir injetar dependências, pois o JSF não sabe fazer essa tarefa. Precisamos que o CDI crie os nossos beans e que, a partir dele, comece a injetar as dependências.

Quando definimos a anotação @ManagedBean em uma classe, o bean estará acessível via Expression Language(EL) com o nome da classe com a primeiro letra minúscula (Ex.: AutorBean ficará disponível como autorBean).

Se olharmos dentro de autor.xhtml, temos o seguinte trecho de código, nas primeiras linhas do arquivo:

<f:viewParam name="autorId" value="#{autorBean.autorId}" />

Temos o nome da classe com a primeira letra em minúsculo. Precisamos trocar a anotação para que o CDI crie o objeto, ao mesmo tempo que é necessário que continue sendo possível acessar o bean na view via Expression Language(EL). Outro ponto é quando definimos um @ManagedBean, o escopo padrão dele será de request.

Para deixar objeto acessível por meio de EL ao mesmo tempo em que o objeto é criado pelo CDI, utilizamos a anotação @Named.

@Named
public class AutorBean implements Serializable {

Porém o escopo padrão do CDI não é request. O escopo padrão é chamado @Dependent. O @Dependent é um escopo que irá depender de quem criou. Alguém precisa definir o escopo para a classe.

Vamos utilizar como exemplo a classe DAO. No DAO não vamos ter um escopo explícito (então é o padrão @Dependent), então se for definido que no AutorBean que é necessário injetar um DAO e o AutorBean tiver um escopo de request, o DAO também terá um escopo de request. O DAO irá assumir o escopo de quem está solicitando a injeção dele.

No caso queremos manter o escopo de request. Por isso, vamos utilizar também a anotação @RequestScoped:

@Named
@RequestScoped
public class AutorBean implements Serializable {

Tome cuidado com o import, pois temos duas opções. Escolha a opção do pacote javax.enterprise.context. Por fim, na classe, utilize o atalho Ctrl + Shit + O do Eclipse, para organizar os imports da classe.

Vamos fazer essa mesma alteração nas demais classes do sistema:

@Named
@RequestScoped
public class LoginBean implements Serializable {

A classe Tema bean é um pouco diferente e possui escopo de sessão.

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class TemaBean implements Serializable {

Queremos manter a classe com escopo de sessão, e o CDI tem uma escopo para isso, que também se chamado SessionScoped. O mesmo nome da anotação do JSF. Por isso, vamos trocar o import:

import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named
@SessionScoped
public class TemaBean implements Serializable {

Vamos agora realizar as alterações no LivroBean. O LivroBean é um pouco diferente, pois possui um ViewScoped, que é um escopo pré-definido pelo JSF, e não temos esse mesmo escopo pré-definido pelo CDI.

@ManagedBean
@ViewScoped
public class LivroBean implements Serializable {

Para que seja possível utilizar o ViewScoped no CDI, o JSF criou uma forma de integrar as duas especificações. Mais uma vez é necessário trocar o import: em vez de escolher o escopo vindo de javax.faces.bean, vamos utilizar o escopo vindo de javax.faces.view.

import javax.faces.view.ViewScoped;
import javax.inject.Named;

// outros imports

@Named
@ViewScoped
public class LivroBean implements Serializable {

No VendasBean vamos fazer as mesmas alterações realizadas no LivroBean:

import javax.faces.view.ViewScoped;
import javax.inject.Named;

// outros imports

@Named
@ViewScoped
public class VendasBean implements Serializable {

Pronto! Conseguimos migrar nossos beans para serem gerenciados pelo CDI. Vamos subir nossa aplicação e verificar se tudo continua funcionando. Ao subir o servidor e atualizar a página de livros (http://localhost:8080/livraria/livro.xhtml), podemos ver que tudo está funcionando como esperado.

Vamos baixar o código-fonte das dependências do nosso projeto. Para isso clique com o botão direito no projeto e escolha a opção "Maven > Download Sources". Pode levar um tempo para baixar tudo.

Downlaod sources

Na classe TemaBean, segure a tecla "Ctrl" e clique em @SessionScoped. Dessa forma vamos navegar até o código da anotação. No código existe a seguinte linha de código:

@NormalScope(passivating = true)

Alguns escopos do CDI, geralmente escopos maiores que sessão, possuem o valor de passivating = true. No que isso implica? Por esse objeto ficar em memória por muito tempo, o CDI pode serializar o objeto no disco caso ele não esteja sendo utilizado. Quando a aplicação precisar novamente do objeto ele será devolvido para a memória principal. Dessa forma é possível diminuir o uso da memória principal

Para que seja possível fazer esse processo, é necessário que as nossas classes implementem a interface Serializable.

public class TemaBean implements Serializable {

Pronto! Conseguimos migrar nossa aplicação para utilizar as anotações relacionadas ao CDI em vez das anotações relacionadas ao JSF. Agora já é possível utilizar a injeção de dependências em nosso sistema.

Além dos escopos @Dependent, @RequestScoped e @SessionScoped, temos também o @ApplicationScoped e o @ConversationScoped.

Sobre o curso CDI 1.2: Use uma das principais especificações do JavaEE.

O curso CDI 1.2: Use uma das principais especificações do JavaEE. possui 232 minutos de vídeos, em um total de 58 atividades. Gostou? Conheça nossos outros cursos de Java em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Java acessando integralmente esse e outros cursos, comece hoje!

  • 1017 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

Premium

  • 1017 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$75
à vista R$900
Matricule-se

Premium Plus

  • 1017 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$100
à vista R$1.200
Matricule-se

Max

  • 1017 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$120
à vista R$1.440
Matricule-se
Procurando planos para empresas?
Acesso por 1 ano
Estude 24h/dia onde e quando quiser
Novos cursos toda semana