Spring Framework IoC - Inversão de Controle Jobson Ronan {[email protected]}

40
Spring Framework IoC - Inversão de Controle Jobson Ronan {[email protected]}

Transcript of Spring Framework IoC - Inversão de Controle Jobson Ronan {[email protected]}

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

Spring FrameworkIoC - Inversão de Controle

Jobson Ronan {[email protected]}

Page 2: 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

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

Alguns padrões muito comuns

Facade Singleton Factory Abstract Factory Command Adapter Decorator Service Locator Prototype ...

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

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

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

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

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

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

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

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

public class UserManager { private UserDao userDao;}

UserManager depende de UserDao

UserManager

UserDao

<<use>>

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

Dependência por Instanciação

WebServerProbe depende de Socket

public class WebServerProbe { public boolean isRunning() { Socket socket = new Socket();...

WebServerProbe

Socket

<<use>>

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

Dependência por factory

UserManager depende de UserDaoFactory(UserManager também depende de UserDao)

public class UserManager { public Collection getUsers() { UserDAO userDAO = UserDAOFactory.newInstance();...

UserManager

UserDao

<<use>> UserDaoFactory

<<use>>

<<create>>

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

Dependência por parâmetro de metodo

UserManager depende de Usuário

Mesmo acoplamento fraco obtido por composicao

public class UserManager { public void saveUser(User user) {...

UserManager

User

<<use>>

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

Dependência por uso de método estático

WebServerProbe depende de Arrays

public class WebServerProbe { private Collection ports; public void setPorts(Integer[] ports) { this.ports = java.util.Arrays.asList(ports);...

WebServerProbe

Arrays

<<use>>

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

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

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

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á

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

“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();

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

Inversão de controle

...Mas primeiro, sem IoC

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

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

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

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

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

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

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

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

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

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 ...

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

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(); }}

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

Inversão de controle

...E agora com IoC

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

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)

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

Inversão de controle

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

Inversão de controle

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

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

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

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)

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

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

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

Exemplos

Sem inversão de controleclass 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(); }}

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

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

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

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;}

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

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(); }}

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

Exemplos

Sem inversão de controle

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

Exemplos

Sem IoC, com ServiceLocator

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

Exemplos

Com IoC

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

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>

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

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

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

Tipos de injeção de dependência

Tipo 1: Interface-based injection Tipo 2: Setter-based injection Tipo 2: Contructor-based injection

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

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

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

Spring FrameworkIoC - Inversão de Controle

Jobson Ronan {[email protected]}