Nesse post vamos falar sobre CDI 1.0, que está dentro da do JavaEE 6.
CDI é a especificação Java para injeção de dependência. Como toda nova especificação, CDI é orientada a anotações e tenta não ser intrusiva nos seus Beans. Se você quiser aprender o básico ou ver outros tutoriais/artigos como esse, sugiro que acesse o site do JDF (JBoss Developser Framework) e esse overview.
Para os mais avançadinhos, sim, CDI remove a necessidade de usar o DI SPRING!
Lembrando que embora tenha alguma teoria, a série de posts do "aprendendo-*" foca muito em parte prática, logo, configure o Eclipse para receber o JBoss AS 7!
Sobre Injeção de dependência e Inversão de controle
Você sabe que quando programa em Java você tem que instanciar as coisas. Por mais inocente que essa ação pareça, isso pode se tornar um problema com o tempo, pois quem instância uma classe fica ligado a esse "elo de instanciação", ou seja, se acoplam. Claro que alguém deveria inventar algo para melhorar isso e o fizeram! A injeção de depêndencia ou, como alguns chamam, Inversão de Controle foi a solução sugerida.
A forma proposta de "desacoplar" foi através da idéia de que basicamente você não vai mais instanciar as coisas, mas sim um "container"(daí a idéia de inversão de controle). Por exemplo, se sua classe X depende da classe Y e deve ter isso instanciada, você não vai usar o new, mas sim informar o container, ele vai injetar essa dependência(daí o nome Injeção de Dependência).
Obviamente mágicas não existem, então você tem que informar o container de alguma forma que está fazendo isso. Alguns usam XML, outros anotações e outros usam simplesmente código Java.
Rod Johnson foi o primeiro a trazer isso para a plataforma Java com o famoso framework Spring que, inicialmente, usava XML e posteriormente passou a usar anotações. No entanto, recentemente isso foi incluido no Java nativamente através da especificação do CDI, onde até alguns pontos foram melhorados significando que você pode jogar fora o Spring e adotar JavaEE. CDI também traz o conceito de injeção dependendo do contexto que seu código foi chamado, mas hoje vamos ficar só com o DI do CDI :).
Blah, blah, blah, chega de histórinha da turma da mônica e vamos para o código *-*.
Um projeto WEB Simples
Vamos criar um projeto simples e inútil para mostrar o funcionamento básico do CDI.
A idéia é simples, vamos usar uma página JSP e um servlet. Esse servlet vai usar uma classe de serviço que só sabe cumprimentar as pessoas.
Nosso primeiro passo é criar um projeto no Eclipse, logo em seguida criar um arquivo XML chamado beans.xml, que não faz nada, mas ativa CDI na sua aplicação. Com ele, o container(no nosso caso o JBoss) sabe que deve injetar coisas, sem ele, suas anotações de CDI são ignoradas. Então, criamos um arquivo beans.xml no diretório WEB-INF com o seguinte conteúdo:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> </beans>
Legal, agora é hora de criar classe que faz o cumprimento, olha abaixo a nossa classe:
Ótimo, agora podemos usar ela dentro de um servlet:
public class DizedorOla{ public String dizerOla(String nome) { if (nome == null || nome.isEmpty()) { return "Por gentileza, informe um nome"; } else { return "Olá " + nome + "!"; } } }
Ótimo, agora podemos usar ela dentro de um servlet:
import java.io.IOException; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.wsiqueir.diversao.cdi.model.DizedorOla; @WebServlet("/servletCDI") public class SimplesServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Inject private DizedorOla dizedorOla; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String nome = request.getParameter("nome"); request.getSession().setAttribute("mensagem", dizedorOla.dizerOla(nome)); response.sendRedirect("index.jsp"); } }Olhem! Uma anotação nova ali. A anotação @Inject diz que aquilo deve ser injetado e que eu não vou instanciar. Sem ela, o nosso servlet apresentaria "NullPointerException". Também percebam que eu direcionando o servlet para um JSP, segue o código do mesmo:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Testando CDI</title> </head> <body> <% String mensagem = (String) request.getSession().getAttribute( "mensagem"); if (mensagem != null) { %> <h2> <%=mensagem%> </h2> <% } %> <form action="./servletCDI" method="post"> <label>Seu nome:</label> <input name="nome" type="text" /> <input type="submit" value="Enviar para o servidor!"> </form> </body> </html>
Se você executar esse código e acessar a página JSP, vai ver que isso vai funcionar sem NullPointerException pela mágica do JSP. Ó!!!!! Mas isso não é tão empolgante, fica mais legal agora. Digamos que você quer possibilitar a injeção de uma classe concreta em um servlet. Isso o meu amigo new pode fazer sem muitos problemas. Mas CDI é bem mais do que isso. Você também pode injetar classes concretas onde a variável é do tipo de uma interface, ajudando na implementação do padrão de projeto estratégia.
Para isso, colocamos o método dizerOla em uma interface:
E criamos uma classe que implementa essa interface:
Agora, se quisermos que o novo comportamente seja tomado no nosso Servlet, simplesmente temos que usar a anotação @Informal sobre o campo injetado! Simples, fácil e muito útil.
Para isso, colocamos o método dizerOla em uma interface:
public interface DizedorOla { public String dizerOla(String nome); }
E criamos uma classe que implementa essa interface:
import javax.enterprise.inject.Default; @Default public class DizedorOlaFormal implements DizedorOla { @Override public String dizerOla(String nome) { if (nome == null || nome.isEmpty()) { return "Por gentileza, informe um nome"; } else { return "Olá " + nome + "!"; } } }Observe que estamos usando uma anotação @Default na declaração da classe. Ela simplesmente diz que se usarmos o @Inject e não "falarmos" mais nada para o container, ele vai injetar uma instância dessa classe! No servlet não mudamos nada, não vale a pena colocar o código aqui de novo :). Bem, esse é o padrão estratégia, logo podemos adicionar outras implementações para a interface DizedoraOla e permitir um novo comportamento na geração dessa mensagem lá no servlet. E se eu te disse que eu consigo fazer isso só adicionando uma anotação no servlet? Seja a seguinte classe para dizer olá de uma forma diferente:)
import org.wsiqueir.diversao.cdi.qualifiers.Informal; @Informal public class DizedorOlaInformal implements DizedorOla { @Override public String dizerOla(String nome) { if (nome == null || nome.isEmpty()) { return "Fala um nome, cara."; } else { return "E aí " + nome + ", sussa?"; } } }Veja que criamos uma anotação e anotamos a nossa classe com ela. Veja o código dela:
import org.wsiqueir.diversao.cdi.qualifiers.Informal; @Informal public class DizedorOlaInformal implements DizedorOla { @Override public String dizerOla(String nome) { if (nome == null || nome.isEmpty()) { return "Fala um nome, cara."; } else { return "E aí " + nome + ", sussa?"; } } }
//... @Inject @Informal private DizedorOla dizedorOla; //...Isso é o que chamamos de qualificador, pois ele qualifica e identifica uma classe concreta pra ser injetada em um atributo de um tipo de sua interface
Conclusão
Mostramos a injeção de dependência usando CDI. Claro que não é só isso, temos muito mais para aprender, mas vocês podem ir além lendo a especificação ou varrendo mais tutoriais pela internet.
Muito bom William!
ResponderExcluirUm dúvida, há algum caso que precisa ser configurado no XML ou é sempre essa mamata com anotações?
Acho que sim. O beans.xml fica lá para quem quiser usar, mas tudo que vi até agora só envolvia anotações!
ResponderExcluirPrimeiramente Parabens pela iniciativa, muito legal você estar defendendo o JEE com tanta garra!
ResponderExcluirRealmente o JEE parece que ficou melhor para se trabalhar, incorporando as várias funções de frameworks que foram surgindo ao longo do tempo. Mas, como a maioria dos desenvolvedores trabalham para um cliente ou empresa que não visa melhorias de desenvolvimento e sim produtos novos cada vez mais rapido, é impossível modificar o que já foi feito anteriormente. Então acaba que todos preferem trabalhar com o Spring, que já tem o ambiente todo montando e todo o código suportado por ele, do que mudar a tecnologia e se adequar ao JEE, que na visão das empresas é perda de tempo. Infelizmente =/...
Salva a exceção que sem sombra de dúvidas, para empresas que estão começando ou projetos que estão se iniciando agora, vale a pena começar com JEE, eliminando os vários frameworks que são utilizados hoje com o objetivo de aumentar a produtividade e simplesmente ficar com o combo Maven + JEE (:
Abraços,
Eclis Rodrigues de Castilho
Desenvolvedor Java.
primeiramente parabens e foi muito util...
ResponderExcluir