Você está na página 1de 6

auladigital.com.

br

Inverso de Controle Injeo de Dependncia.


Mesmo no sabendo oque significa Injeo de dependncia, muito provavelmente voc j deve ter visto isso escrito em algum lugar. A grande questo : Por que eu precisaria usar isso ? Este artigo mostra alguns conceitos implementa um pequeno exemplo para tentar responder a essa pergunta. Esse assunto me faz lembrar o tempo de faculdade, onde meu ilustrssimo professor Rosvelter Coelho, que me reprovou no apenas uma, mas duas longas vezes, falando entre coisas computveis e no computveis, buracos negros e viagens no tempo, repetia seguidas vezes ( ou era eu que repetia? ) Principio de Hollywood, No venha, deixe que eu te chamo!. Eu, em todas as vezes pensava comigo, Oque eu estou fazendo aqui? Esse cara louco!. Pois , s fui entender depois, que por milagre, eu passei na bendita matria de teoria da computao. A inverso de controle trata exatamente disso, inverte o controle que voc tem de construir objetos. Exatamente assim. E agora a pergunta : Por que no posso construir meus objetos ? Vamos ento aos exemplos prticos pra responder essa pergunta. Imagina que voc tem uma classe de servios, que faz implementa as regras de negocio de um sistema de controle de despesas, e uma classe DAO que realiza as operaes no banco de dados. DespesaService.java package import public servico; dao.DespesaDAO; class DespesaService { DespesaDAO despesaDao = new DespesaDAO(); public void gravar(){ despesaDao.gravar(); } public void remover(){ despesaDao.remover(); } public void alterar(){ despesaDao.alterar(); } } Quando temos o controle de construir os objetos diretamente na classe que a depende, deixamos elas muito acopladas, ou seja, elas se conhecem demais, dessa forma fica difcil responder com certeza as questes levantadas anteriormente. Outro ponto interessante, se a partir de agora eu desejasse utilizar Hibernate em meus DAOs, sendo que atualmente eles so implementados com JDBC? Como eu faria essa modificao? Teria que mudar os mtodos anteriores para usar Hibernate, e recompilar toda a aplicao? Adotando a inverso de controle (IoC), eu posso fazer implementaes plugveis injetando as dependncias (DI) onde for necessrio. Se determinado Service depende de um DAO, ento eu vou injetar esse DAO, podendo atualmente injetar um DAO que implementa JDBC, sendo que a qualquer momento, posso injetar outro DAO que implementa Hibernate ou qualquer outra tecnologia que possa surgir, diminuindo o acoplamento entre as classes e tornando os componentes do software muito mais flexveis. Representando graficamente temos:

Note que a classe DespesaService possui o objeto despesaDAO, construindo esse objeto diretamente na classe com o operador new. Observe tambm que os mtodos dessa classe usam esse objeto em seus mtodos. Dizemos que a classe DespesaService depende da classe DespesaDAO. Em outras palavras, a classe DespesaDAO dependncia de DespesaService, pois sem a classe DAO a classe Service no conseguiria fazer o seu trabalho. Sem novidades at o momento, mas qual o problema de fazer isso? Tem alguma coisa errada? A resposta obviamente no, no tem problema nenhum, enquanto meu sistema bem pequenininho... porm, se ele for crescendo, ganhando mais funcionalidades, mais casos de uso, e o usurio ir pedindo cada vez mais coisas, fato super comum nos sistemas, no tenha dvida que eu ter problemas pela frente. O que aconteceria se agora com o sistema muito maior, com dezenas de classes Service, vrias dessas classes tendo DespesaDAO como dependncia, precisar fazer alguma modificao no DAO. Ser que essa modificao seria segura? Causaria algum problema em outra parte que usa essa dependncia?

DespesaDAO.java package public dao; class DespesaDAO { public void gravar(){ System.out .println("gravando..."); } public void remover(){ System.out .println("removendo..."); } public void alterar(){ System.out .println("alterando..."); }

Vamos aos conceitos, Inverso de Controle (IoC) um padro de projetos que retira do implementador o controle de construo de criao dos objetos. Injeo de Dependncia (DI) uma das formas de se realizar a Inverso de Controle, onde a dependncia de uma determinada classe injetada de alguma forma. Se no sou eu que crio os objetos, quem cria? Como funciona essa injeo de dependncias? A Inverso de controle j usada um algum tempo, sendo o Spring um dos frameworks que despontou na frente com Injeo de Dependncia dentre outras funcionalidades, que facilita e torna mais produtivo o desenvolvimento de software. Sendo assim, pode-se usar o Spring para injetar as dependncias na suas classes. E ento, quem cria minhas classes? o Spring! Somente ele faz isso? At pouco tempo no existia nenhuma forma oficial em Java para realizar esse trabalho, no existia um padro, somente agora com o JEE6, essas funcionalidades esto disponveis diretamente nos Servidores de Aplicao. Quer dizer que voc pode fazer sua aplicao, usando Injeo de Dependncia, e um Servidor de Aplicao JEE6 ir injetar suas dependncias. Quais so esses Servidores? Ora, o Glassfish 3 e o JbossAS 6. Tomcat faz? No, mas isso no significa que no vou poder usar Inverso de Controle nas minhas aplicaes que rodam no Tomcat. A diferena que quando eu uso JbossAS6 ou Glassfish 3, no precisa fazer absolutamente nada para ativar essas funcionalidades, o prprio continer capaz de realizar a Injeo, e no caso do Tomcat, a aplicao dever ser autocontida, ou seja, a aplicao dever fazer a Injeo por si mesma, ter que trazer consigo as bibliotecas e ser toda configurada apropriadamente.

Uma vez estabelecido as funcionalidades e distribudo em interfaces, devemos ter as implementaes. Vamos modelar uma implementao para cada interface. Temos a classe DespesaServiceNacional implementando a interface DespesaService. Essa classe tem as regras de negocio para manipular as despesas em mbito nacional, (faz abatimentos no imposto de renda, dentre outras regras). Temos tambm a classe JDBCDespesaDAO que faz a manipulao do banco de dados usando JDBC. DespesaControle representa a camada de Controle, onde recebe as solicitaes da camada de visualizao e delega para o service realizar as regras de negocio.

Hands on
Vamos implementar e ver como tudo isso funciona. Nosso exemplo ser implementado no Eclipse IDE Helios, com JBoss Tools, E JBossAS6 como servidor de aplicao. Primeiramente crie um Dynamic Web Project com o nome Financeiro. Defina o JBoss como Target runtime, Dynamic web module version 3.0.

Modelando para injetar


Um dos motivos para usar injeo de dependncias reduzir o acoplamento entre as classes. Para isso fazemos uma modelagem orientada a interfaces, todos os servios e funcionalidades do sistema sero descritos como interfaces, que tem o papel de representar contratos, apenas especifica os servios, dessa forma a modelagem fica livre de implementao. Note que DespesaService usa servicos de DespesaDAO, ( DespesaDAO dependncia de DespesaService ), mas como essa dependncia est especificada a nvel de interface ( livre de implementao ), temos um baixo acoplamento, significa que DespesaService far uso das funcionalidades de DespesaDAO, sem se importar como esses servios sero realizados. Modelo com a definio das interfaces:

Modelo com implementaes:

em Configuration, clique no boto Modify...

Marque as opes CDI (Context and Dependency Injection) DespesaService.java package public servico; interface DespesaService { public void gravar(); public void remover(); public void alterar();

DespesaDAO.java Avance at a etapa a seguir, verifique se esta marcada a opo de criao do arquivo beans.xml, ele requisito para ativar a funcionalidade de Injeo de Dependncia. package public dao; interface DespesaDAO { public void gravar(); public void remover(); publicvoidalterar();

DespesaServiceNacional.java package servico.impl; import javax.inject.Inject; import servico.DespesaService; import dao.DespesaDAO; public Escolha a opo para usar diretamente do Servidor de Aplicao: a biblioteca JSF class DespesaServiceNacional implements DespesaService{ @Inject DespesaDAO despesaDao; public void gravar(){ System. out .println("gravando nacional"); despesaDao.gravar(); } public void remover(){ System.out .println("removendo nacional"); despesaDao.remover(); } Com isso temos nosso Projeto pronto pra usar DI. O prximo passo criar as interfaces DespesaService e DespesaDAO, e seguidamente as suas implementaes (DespesaServiceNacional e JDBCDespesaDAO respectivamente). Criamos tambm a classe de controle DespesaControle que ser o ManagedBean e um xhtml para poder solicitar os servios. public void alterar(){ System.out .println("alterando nacional"); despesaDao.alterar(); } }

JDBCDespesaDAO.java package dao.jdbc; import dao.DespesaDAO; public class JDBCDespesaDAO implements DespesaDAO { public void gravar(){ System. out .println("gravando JDBC..."); } public void remover(){ System. out .println("removendo JDBC..."); } public void alterar(){ System. out .println("alterando JDBC..."); } }

DespesaControle.java package import import import import controle; javax.enterprise.context.RequestScoped; javax.inject.Inject; javax.inject.Named; servico.DespesaService;

Onde antes voc faria : JDBCDespesaDAO despesaDao = new JDBCDespesaDAO(); Temos agora: @Inject DespesaDAO despesaDao;

@RequestScoped @Named public class DespesaControle { @Inject DespesaService despesaService; public void gravar(){ despesaService.gravar(); } public void remover(){ despesaService.remover(); } public void alterar(){ despesaService.alterar(); } }

Temos na classe de controle outro ponto de injeo, onde solicitado que seja injetado um objeto que implementa a interface DespesaService(no caso DespesaServiceNacional, pois a nica implementao disponvel). Temos tambm duas anotaes novas @RequestScoped e @Named, Como definimos anteriormente a classe de controle o ManagedBean, que responsvel por receber as solicitaes da visualizao e delegar ao Service. Para que os mtodos do Controle possam ser visveis na visualizao, adicionamos a anotao @Named, semelhante a anotao JSF2 @MangedBean. A anotao @RequestScoped define o escopo do ManagedBean, que o bean tem o tempo de vida de um request.

Vamos fazer o deploy da aplicao e iniciar o servidor. A visualizao despesas.xhtml acessada pelo browser em http://localhost:8080/Financeiro/despesas.jsf e mostra apenas 3 botes que realiza o seguinte fluxo:

despesas.xhtml DespesasControle DespesaServiceNacional JDBCDespesaDAO


despesas.xhtml <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd"> <html xmlns= "http://www.w3.org/1999/xhtml" xmlns:h= "http://java.sun.com/jsf/html" xmlns:f= "http://java.sun.com/jsf/core" xmlns:ui= "http://java.sun.com/jsf/facelets"> <ui:composition> <h:form> <h:panelGrid columns= "1" > <h:commandButton action= "#{despesaControle.gravar()}" value= "gravar" /> <h:commandButton action= "#{despesaControle.alterar()}" value= "alterar" /> <h:commandButton action= "#{despesaControle.remover()}" value= "remover" /> </h:panelGrid> </h:form> </ui:composition> </html> Note que ocorreu a injeo da forma que desejamos. Nos referenciamos apenas as interfaces e o mecanismo de Injeo de Dependncia do JBossAS6 disponibilizou a implementao em seu lugar. 1.0

Ao clicar nos botes gravar, alterar e remover, temos o resultado em console:

Observe a presena da anotao @Inject, ela descreve o ponto de injeo de dependncia. Instanciamos o objeto despesaDAO, representante da interface, em momento algum foi citado a implementao, a modelagem esta livre de implementao. Esse o ponto de baixo acoplamento, conhecemos o contrato, ento solicitamos que seja executado de alguma forma essa funcionalidade. Mas oque ser injetado? Oque voc espera que seja injetado? A resposta mais obvia que seja injetado um representante da Classe JDBCDespesaDAO. exatamente oque acontece, como colocamos uma interface no ponto de injeo, a classe que implementa essa interface ser automaticamente injetada. Em outras palavras, inverte o controle que o desenvolvedor tem de criar os objetos, delegando essa atividade ao Servidor de Aplicao.

Ampliando o Sistema Um dos motivos para se usar o mecanismo de DI era a tornar plugvel os componentes do sistema, vamos ver de que forma isso acontece. Imagine ento que usaremos Hibernate no lugar do JDBC. Outra mudana seria usar agora outra regra de negocio, o nosso controle de despesas vai trabalhar em mbito internacional, e agora as regras so diferentes ( converso de moeda, tarifas internacionais, restituio de impostos, etc ). Como fazer essas modificaes sem ter que reescrever toda a aplicao? Vamos modelar novamente, acrescentando a classe DespesaServiceInternacional e a classe HbnDespesaDAO.

Criando as novas classes no eclipse temos:

HbnDespesaDAO.java package dao.hibernate; import dao.DespesaDAO; public class HbnDespesaDAO implements DespesaDAO { public void gravar(){ System. out .println("gravando Hibernate..."); } public void remover(){ System. out .println("removendo Hibernate..."); } public void alterar(){ System. out .println("alterando Hibernate..."); DespesaServiceInternacional.java package import import import servico.impl; javax.inject.Inject; servico.DespesaService; dao.DespesaDAO; } }

public class DespesaServiceInternacional implements DespesaService{ @Inject DespesaDAO despesaDao; public void gravar(){ System.out .println("gravando internacional"); despesaDao.gravar(); } public void remover(){ System.out .println("removendo internacional"); despesaDao.remover(); } public void alterar(){ System.out .println("alterando internacional"); despesaDao.alterar(); } }

Agora temos duas implementaes para a interface DespesaService e duas para DespesaDAO. E agora, oque sera injetado? Como eu escolho oque sera injetado? Antes de responder a essas questes, vamos iniciar o servidor com essas modificaes no sistema. Ao levantar a aplicao j nos deparamos com o seguinte erro:

WELD-001409 Ambiguous dependencies for type [DespesaDAO] with qualifiers [@Default] at injection point [[field] @Inject servico.impl.DespesaServiceNacional.despesaDao]. Possible dependencies [[Managed Bean [class dao.jdbc.JDBCDespesaDAO] with qualifiers [@Any @Default], Managed Bean [class dao.hibernate.HbnDespesaDAO] with qualifiers [@Any @Default]]]

Esse erro esta dizendo que existem duas implementaes para a dependncia DespesaDAO. Temos um caso de ambiguidade. Para resolver esse problema temos que escolher uma implementao. Devemos marcar todas as implementaes com a anotao @Alternative para especificar que ela uma possvel alternativa de dependncia.

@Alternative public class DespesaServiceInternacional implements DespesaService {...}

clique no boto Add... para adicionar a classe eleita para a injeo. Escolha as classes novas classes que criamos, (DespesaServiceInternacional e HbnDespesaDAO). No esquea de salvar o arquivo aps a modificao.

@Alternative public class DespesaServiceNacional implements DespesaService {...}

@Alternative public class HbnDespesaDAO implements DespesaDAO {...}

@Alternative public class JDBCDespesaDAO implements DespesaDAO {...} Feito isso, devemos definir qual vai ser a implementao a ser injetada atravs do arquivo beans.xml.

Ao inserir as classes eleitas, o arquivo beans.xml fica como listado abaixo:

<?xml version= "1.0" encoding= "UTF-8"?> <beans xmlns= "http://java.sun.com/xml/ns/javaee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd"> <alternatives> <class>servico.impl.DespesaServiceInternacional</class> <class>dao.hibernate.HbnDespesaDAO</class> </alternatives> </beans>

Abra o arquivo beans.xml

Executando novamente a aplicao temos:

Este artigo mostrou os principais conceitos de Injeo de Dependncias do JEE6, usando o JBoosAS6 e o Eclipse IDE. Foi feita uma modelagem e implementao de um sistema exemplo, onde so demonstrados os mecanismos presentes no artigo. Foi abordado pelo material a soluo de ambiguidade na injeo.

Autor: Ivan Salvadori Florianpolis-SC Fevereiro de 2011

Autorizo a cpia, distribuio e impresso citando a autoria do material.

Você também pode gostar