1 / 40

Spring Framework IoC - Inversão de Controle

Spring Framework IoC - Inversão de Controle. Jobson Ronan {jrjs@cin.ufpe.br}. Motivação. Desenvolver uma aplicação sempre impõe desafios Muitos deles já foram solucionados por outros esforçados “guerreiros” Criaram padrões... Padrões de projeto... Design patterns.

kyna
Download Presentation

Spring Framework IoC - Inversão de Controle

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Spring Framework IoC - Inversão de Controle Jobson Ronan {jrjs@cin.ufpe.br}

  2. Motivação • Desenvolver uma aplicação sempre impõe desafios • Muitos deles já foram solucionados por outros esforçados “guerreiros” • Criaram padrões... Padrões de projeto... Design patterns

  3. Alguns padrões muito comuns • Facade • Singleton • Factory • Abstract Factory • Command • Adapter • Decorator • Service Locator • Prototype • ...

  4. Design e Manutenibilidade • Sistemas manuteníveis • Evoluem bem com mudanças e iterações • Chave do segredo: Gerenciar dependências • Outros aspectos importantes • Design por contrato • Definição limpa do contrato das classes/interfaces • Contrato: O que faz, como se comporta • Não como está implementado! • Testes unitários • Escrever testes que verificam o contrato da classe/interface • Separação de interesses • Escrever uma classe/interface para cada interesse

  5. Dependência • É quando se prende um componente a outro por: • Herança • Composição • Instanciação • Instanciação por factory • Parâmetro de método • Uso de métodos ou atributos estáticos

  6. Princípios de desenvolvimento ágil • Quando uma Componente possui uma dependência, sua implementação pode precisar mudar quando • Os requisitos mudarem, ou... • Quando sua dependência mudar • Abstrações tendem a ser estáveis • Interfaces estão normalmente pouco sujeitas a serem alteradas • Componentes concretos tendem a ser instáveis • Classes concretas normalmente estão mais sujeitas a terem sua implementação alterada

  7. public classUserManager { privateUserDao userDao; } UserManager UserDao UserManager depende de UserDao Dependência por Composição • Composição cria um fraco acoplamento • Quando o comportamento ou a interface da dependência (UserDao) muda, apenas o dependente precisa se adaptar • Não Possui os efeitos colaterais de herança <<use>>

  8. Dependência por Instanciação WebServerProbe depende de Socket WebServerProbe public class WebServerProbe { public boolean isRunning() { Socket socket = new Socket(); ... <<use>> Socket

  9. Dependência por factory UserManager UserManager depende de UserDaoFactory (UserManager também depende de UserDao) public class UserManager { public Collection getUsers() { UserDAO userDAO = UserDAOFactory.newInstance(); ... <<use>> UserDaoFactory <<use>> <<create>> UserDao

  10. Dependência por parâmetro de metodo UserManager depende de Usuário • Mesmo acoplamento fraco obtido por composicao UserManager public class UserManager { public void saveUser(User user) { ... <<use>> User

  11. Dependência por uso de método estático WebServerProbe depende de Arrays WebServerProbe public class WebServerProbe { private Collection ports; public void setPorts(Integer[] ports) { this.ports = java.util.Arrays.asList(ports); ... <<use>> Arrays

  12. Dependências • Algumas formas de dependência são piores que outras • Herança: Quando novos métodos são adicionados e usados, os componentes não recebem nenhum aviso para sobrescreve-los • Prefira Composição • Classes, métodos e atributos estáticos (ex: Singletons): dependências ficam escondidas nos componentes dependentes, tornando difícil a alteração dos dependentes quando componentes estáticos são alterados • Usar inversão de controle

  13. Dependências • Dependências não são um mal • Claro que sempre existirão dependências. • O objetivo é • Minimizar o número de dependências no seu modelo • Depender apenas de interfaces • Deve-se primar por • Componentes fracamente acoplados • Depender de interfaces e não de classes, o máximo possível • Quanto menos sua aplicação estiver sujeita a mudanças, mais estável e manutenível estará

  14. “Fracamente acoplados” • Acoplamento forte • Instanciação de classes concretas dentro da lógica de negócio • Uso de métodos estáticos • Herança • Acoplamento fraco • Usando Factories e ServiceLocator • Usando inversão de controle InputStream is = new FileInputStream(...); InputStream is = StreamUtils.getConfigFileInputStream(); InputStream is = new ConfigFactory().createInputStream();

  15. Inversão de controle • ...Mas primeiro, sem IoC

  16. Implementação sem IoC • O próprio componente precisa obter suas dependências • Ex: JNDI, EJB Stub, JDBC Connection, arquivos de propriedades, etc. • Desacoplável por: • Codificar por interfaces • Obter esses objetos usando um Factory ou um ServiceLocator • Efetuar-se chamadas a esses objetos, potencialmente para obter outras dependências • Ex: JNDI, JDBC Connection Pool, etc. • Encadeia dependências

  17. Conseqüências • Código cheio de código específico de obtenção a dependências • Instanciação cria acoplamento • Código ligado a um determinado ambiente (container) (EJB Container, Servlet Container, Rich client, ...) • Dificulta a implementação de testes unitários

  18. Código específico de obtenção a dependências • As vezes, mais código para isso que para a implementação da lógica de negócio • Solução clássica: encapsular > Service locator, Factory • Problema: Escrever os Factories • Problema: Singletons are evil • Dependências não muito claras, atravessam todo o código • Dificultam unit testing • Dificultam Refactories

  19. Codificação por interface desacopla, mas... • A instanciação ainda usa uma implementação concreta (=> acoplamento) • Solução clássica: usar uma Factory • Problema: • forte acoplamento com a Factory • Torna difícil a manutenção • Torna difícil a implementação de Testes Unitários

  20. Código ligado a um determinado ambiente • Código de recuperação de dependências dentro da lógica de negócio • Ambiente/container variados • Standalone Java Application • Swing/SWT Java Application • Dentro de um container EJB • Dentro de um servlet container • Exemplo: Obtenção de um objeto Connection (JDBC) • standalone: usando java.sql.DriverManager • standalone com pool: usando Apache Commons DBCP • Tomcat: usando InitialContext e DataSource • ...

  21. Dificulta a implementação de testes unitários • Porque o “como” de obter uma dependência está codificado dentro da classe que se quer testar • Ex: Usando um Factory, como você pode mudar seu comportamento de acordo com um teste unitário? • Agora... Como testar MyLogic sem EJB e precisando de um EJB container? class MyLogic { public void doSomething() { // use the InitialContext (JNDI) Service Locator // to retrieve the “BusinessLogic” object InitialContext ctx = new InitialContext(); BusinessLogic partner = (BusinessLogic) ctx.lookup(“my/business/logic/impl”); // now perform the actual logic: partner.doYourOwnBusiness(); } }

  22. Inversão de controle • ...E agora com IoC

  23. Inversão de controle • Um meio de por os componentes juntos • Define-se • Interfaces e implementações • Dependências entre classes e interfaces (transformando-as em “colaboradores”) • O Container de Inversão de controle • Cria o dependente e a dependência, e injeta esta ultima no dependente • Possibilita selecionar que implementação de dependência injetar em cada dependente (por configuração, código, automática)

  24. Inversão de controle

  25. Inversão de controle

  26. Inversão de controle • Arquitetura do container leve • Usa POJOs • Sem necessidade de deploy em um container pesado • Aumenta testabilidade • Não é intrusiva • Não depende de nenhuma API especifica do container • Sem interfaces para implementar, sem classes para herdar, exceto as suas

  27. IoC - Princípios • “Hollywood principle” • “Don´t call me, i´ll call you” • Sem IoC, componentes lógicos tem o controle sobre suas dependências e,por conseguinte,devem obtê-las • Com IoC, a lógica dos componentes não tem controle sobre suas dependências e não as obtém • Um container de IoC irá injetar as dependências nos objetos (Dependency Injection)

  28. Principais vantagens • Efetivamente desacopla componentes lógico de suas dependências • Remove o código de obtenção de dependências dos dependentes (Agora é trabalho do container). • Melhora o design do modelo • Aumenta a flexibilidade e o reuso de componentes • Testes unitários ficam mais fáceis • Não depende de ambientes específicos

  29. Exemplos • Sem inversão de controle class MyLogic { private BusinessServiceInterface businessService = null; protected final BusinessServiceInterface getBusinessService() { if (businessService == null) { // retrieve JNDI InitialContext Context ctx = new InitialContext(); Context env = (Context) ctx.lookup(“java:comp/env”); Object obj = env.lookup(“ejb/BusinessServiceHome”); // retrieve EJB stub BusinessServiceHome businessServiceHome = (BusinessServiceHome) PortableRemoteObject.narrow( env, BusinessServiceHome.class); businessService = businessServiceHome.create(); } return businessService; } public void doYourThing() { getBusinessService().doYourBusiness(); } }

  30. Exemplos • Sem inversão de controle • Tenta testar isso! • Terá que re-implementar quando BusinessService não for mais um EJB • Terá que re-implementar quando não estiver em um EJB container (Sem JNDI) • Terá que re-implementar quando não quiser mais um cache do Stub

  31. Exemplos • Sem IoC, com ServiceLocator: • Estratégia de ciclo de vida centralizado para BusinessServiceInterface • Dependência centralizada com o container EJB • Testes unitários ainda difíceis (precisa alterar o comportamento de MyService) • Se diferentes classes precisarem de objetos BusinessServiceInterface de diferentes fontes? Como cuidar disso? • Você terá um não manutenível número de Services Locators, ou catastróficos efeitos colaterais ao alterar a implementação de MyService protected final BusinessServiceInterface getBusinessService(){ if (businessService == null) { businessService = MyServices.getBusinessService(); } return businessService; }

  32. Exemplos • Com IoC • Sem dependência em como o BusinessService é obtido • Sem código de obtenção dedependêcia, apenas um atributo e um setter • Depende apenas da interface BusinessServiceInterface class MyLogic { // businessService will be set by the IoC container: private BusinessServiceInterface businessService; // we'll use setter-based injection (explained later): public void setBusinessService(BusinessServiceInterface businessService) { this.businessService = businessService; } public void doYourThing() { // perform call on businessService businessService.doYourBusiness(); } }

  33. Exemplos • Sem inversão de controle

  34. Exemplos • Sem IoC, com ServiceLocator

  35. Exemplos • Com IoC

  36. Mas como funciona?? class MyMain { public static void main(String[] args) { // initialize the IoC container (here it's Spring): XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource(“beans.xml”)); // retrieve MyLogic: MyLogic myLogic = (MyLogic) xmlBeanFactory.getBean(“myLogic”); // call the method: myLogic.doYourThing(); } } <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans ...> <!-- this is beans.xml --> <beans> <bean id=”theBusinessSvc” class=”foo.BusinessServiceMock”/> <bean id=”myLogic” class=”foo.MyLogic”> <property name=”businessService”> <bean ref=”theBusinessSvc”/> </property> </bean> </beans>

  37. Conclusões • O princípio da inversão de controle pode ser aplicado elegantemente com o Spring • Isto irá reduzir em grande quantidade a quantidade de padrões de projeto aplicados, simplificando o design do modelo • Isto está mudando a forma de como desenvolver aplicações “Precisamos de novos Design Patterns,os que conheciamos não são mais necessários.” Jobson Ronan

  38. Tipos de injeção de dependência • Tipo 1: Interface-based injection • Tipo 2: Setter-based injection • Tipo 2: Contructor-based injection

  39. Exercício • Criar aplicação completa de reservas de videos • DAOs + Fachada • Não é necessário classes de cadastro • Extrair dependências possuídas pela fachada a DAOs concretos. • A fachada deve apenas conhecer a interface dos DAOs • Use o springframework para injetar as dependências

  40. Spring Framework IoC - Inversão de Controle Jobson Ronan {jrjs@cin.ufpe.br}

More Related