Post on 06-Jan-2016
description
Copyleft by Diego Tarábola e
Denise Goya 1
Inversão de Controle - IoC
Tópicos (Avançados) de Programação Orientada a Objetos
Prof. Fabio KonDCC - IME - USP
Diego Tarábola e Denise Goya
outubro/2006
Copyleft by Diego Tarábola e
Denise Goya 2
Inversão de Controle - IoC
Princípio de Hollywood: “Não nos ligue, nós ligaremos”.
Dependência de componentes.
Dependência de componentes também conhecida como colaboradores de objetos.
O objeto que exige dependência é conhecido como objeto dependente.
Arcabouço é responsável pela execução da operação.
Ocorre em tempo de execução.
Visão Geral
Copyleft by Diego Tarábola e
Denise Goya 3
public class A{ private B b; public A(){
b=new B(); }
}
Classe A precisa de uma referência para a Classe B.Classe B é uma classe concreta que tem um construtor padrão.Classe A possui uma instância de B.Nenhuma outra classe pode acessar uma instância da Classe B [Mal06].
Inversão de Controle — Motivação
1 - diagrama UML de seqüência
Cenário 1
Copyleft by Diego Tarábola e
Denise Goya 4
Objeto a possui referência para os objetos c e b.
public class A{ private B b;
public A(){ C c=new C(); b=new B(c); }}
Inversão de Controle — Motivação
2 - diagrama UML de seqüência
Cenário 2
Copyleft by Diego Tarábola e
Denise Goya 5
A precisa de uma referência para B, e não precisa saber como B é instanciado.
B pode ser uma interface, uma classe abstrata ou concreta.
Antes de instanciar a classe A, precisa de uma referência para a classe B.
public class A{ private B b; public A(){ } public setB(B b){ this.b=b; } }
Inversão de Controle — Motivação
3 - diagrama UML de seqüência
Cenário 3
Copyleft by Diego Tarábola e
Denise Goya 6
Tipos de Inversão de Controle
Inversão de Controle
Procura por Dependência
Injeção de Dependência
Contextualized Dependency
Lookup
Dependency Pull
Interface Setter Construtor
Copyleft by Diego Tarábola e
Denise Goya 7
Inversão de Controle (IoC) possui dois tipos [Har05]:
Injeção de Dependência (Dependency Injection)
Procura por Dependência (Dependency Lookup)
Injeção de Dependência sempre diz respeito a IoC, mas IoC nem sempre referencia Injeção de Dependência
Tipos de Inversão de Controle
Copyleft by Diego Tarábola e
Denise Goya 8
Procura por Dependência: um componente deve obter uma referência para uma
dependência; dois subtipos:
Dependency Pull Contextualized Dependency Lookup (CDL)
Injeção de Dependência: as dependências são literalmente injetadas (incluídas) três subtipos:
Interface – Tipo 1 Setter – Tipo 2 Constructor – Tipo 3
Tipos de Inversão de Controle
Copyleft by Diego Tarábola e
Denise Goya 9
Spring
Avalon
PicoContainer
HiveMind
Excalibur: Fortress
Resin
Copland (Ruby)
Mentawai
Contêineres de Inversão de Controle
Copyleft by Diego Tarábola e
Denise Goya 10
Procura por Dependência com Spring
public static void main(String[] args) throws Exception {
// get the bean factoryBeanFactory factory = getBeanFactory();
MessageRenderer mr = (MessageRenderer) factory.getBean("renderer");mr.render();
}
Procura por Dependência — Dependency Pull
As dependências são obtidas através de um registro assim que necessário;
Mecanismo para encontrar componentes que gerenciam o arcabouço.
Copyleft by Diego Tarábola e
Denise Goya 11
Interface do Componente para CDL com Spring
public interface ManagedComponent {
public void performLookup(Container container);
}
Procura por Dependência — Contextualized Dependency Lookup (CDL)
Semelhante ao Dependency Pull;
Procura é execuada pelo contêiner que está gerenciando o recurso e não a partir de um registro central;
CDL funciona através da implementação de uma interface.
Copyleft by Diego Tarábola e
Denise Goya 12
Obtendo dependência com o CDL
public class ContextualizedDependencyLookup implements ManagedComponent {
private Dependency dep;
public void performLookup(Container container) {this.dep = (Dependency) container.getDependency("myDependency");
}}
Procura por Dependência — Contextualized Dependency Lookup (CDL)
Executa o método performLookup() implementado pelo componente;
O componente pode procurar sua dependência utilizando a interface Container.
Copyleft by Diego Tarábola e
Denise Goya 13
Injeção de Dependência pelo Construtor com Spring
public class ConstructorInjection {
private Dependency dep;
public ConstructorInjection(Dependency dep) {this.dep = dep;
}}
Injeção de Dependência — por meio de Construtor
Dependência do componente é disponibilizada através de seu(s) construtor(es);
O argumento recebido será sua dependência.
Copyleft by Diego Tarábola e
Denise Goya 14
Injeção de Dependência através do método Setter com Spring
public class SetterInjection {
private Dependency dep;
public void setMyDependency(Dependency dep) {this.dep = dep;
}}
Injeção de Dependência — por meio de método Setter
O contêiner IoC injeta um componente de dependência através de seu método set (JavaBean);
O componente setter permite um conjunto de dependências que o contêiner de inversão de controle pode gerenciar.
Copyleft by Diego Tarábola e
Denise Goya 15
Injeção de Dependência através de Interface. Exemplo no arcabouço Avalon
public interface InjectFinder {
public void injectFinder(MovieFinder finder);}
public class MovieLister implements InjectFinder {
public void injectFinder(MovieFinder finder){this.finder = finder;
}
Injeção de Dependência — por meio de Interface [Fow06]
Componente de dependência através de uma interface;
A interface InjectFinder será definida por qualquer um que fornecer a interface MovieFinder (no exemplo abaixo).
Copyleft by Diego Tarábola e
Denise Goya 16
public class Tester {
private Container container;
private void configureContainer(){container = new Container();registerComponents(); registerInjectors(); container.start();
}}
Injeção de Dependência — por meio de Interface
Exemplo: Classe de Teste no Avalon: configura os componentes e os
injetores.
Copyleft by Diego Tarábola e
Denise Goya 17
private void registerInjectors(){
container.registerInjector(InjectFinder.class, container.lookup(“MovieFinder”));
}
Injeção de Dependência — por meio de Interface
É preciso registrar os injetores que irão injetar os componentes dependentes;
Cada interface de injeção precisa de algum código para injetar o objeto dependente;
No código abaixo, registram-se os objetos injetores no contêiner:
Copyleft by Diego Tarábola e
Denise Goya 18
Injeção versus Procura
O tipo de IoC é definido pelo contêiner adotado.
Com Dependency Pull, é necessário: registrar dependências; obter referências das dependências; interagir com as dependências obtidas.
Utilizando CDL, é preciso: que as classes implementem uma interface específica; e procure por todas dependências manualmente.
Com Injeção de Dependência, as classes precisam: permitir que as dependências sejam injetadas por meio de
construtores, métodos setters ou interfaces.
Copyleft by Diego Tarábola e
Denise Goya 19
Contêiner de Inversão de Controle
Arcabouços incluem contêineres de IoC;
Arcabouços manifestam inversão de controle em tempo de execução, por meio de retorno de chamadas [SGN04] ;
Chamadas invocam métodos hook de componentes definidos pela aplicação, sempre que ocorre algum evento;
Na ocorrência de um evento, o arcabouço chama de volta um método virtual num componente de aplicação pré-registrado;
O componente executa o processamento definido pela aplicação, em resposta ao evento;
O controle é alternado entre o arcabouço e a aplicação.
Copyleft by Diego Tarábola e
Denise Goya 20
Contêiner de Inversão de Controle
Exemplo: Recebimento de chamada telefônica [POSA 2]
Uma companhia de telefone possui um mecanismo IoC;
Um usuário: um tratador de evento, que está registrado junto à companhia, para tratar as chamadas ao número desse usuário.
Quando alguém chama pelo número daquele usuário, a rede notifica o tratador que um evento de requisição de chamada está pendente (via toque do telefone);
Assim que o telefone é tirado do gancho, existe uma reação a esta requisição (o tratador assume o controle), iniciando uma conversação entre as partes conectadas.
Copyleft by Diego Tarábola e
Denise Goya 21
Ex.: Injeção de Dependência com Spring
Bean: qualquer componente gerenciado pelo contêiner; configuração do bean:
armazena informações próprias e do bean do qual depende; representada por instâncias de classes que implementam a interface
BeanDefinition;
Interface BeanFactory: responsável por gerenciar componentes no contêiner; qualquer aplicação interage com o Spring por meio dessa
interface; a aplicação deve:
criar uma instância da classe que implemente essa interface; configurar com a informação de dependência.
Copyleft by Diego Tarábola e
Denise Goya 22
Ex.: Injeção de Dependência com Spring
arquivo de configuração para BeanDefinition: classe PropertiesBeanDefinitionReader ou
XmlBeanDefinitionReader
private static BeanFactory getBeanFactory() throws Exception {
// obtém a fábrica do bean DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// cria uma definição do leitor PropertiesBeanDefinitionReader rdr = new
PropertiesBeanDefinitionReader(factory);
// lê as opções de configuração Properties props = new Properties(); props.load(new FileInputStream("./src/conf/beans.properties")); rdr.registerBeanDefinitions(props);
return factory;
}
Copyleft by Diego Tarábola e
Denise Goya 23
Ex.: Injeção de Dependência com Spring
A informação de BeanDefinition é obtida através de um arquivo de propriedades (properties).
Uma vez criada e configurada a implementação de BeanFactory, o bean é encontrado utilizando seu nome, que está configurado no arquivo de propriedades.
public static void main(String[] args) throws Exception {
// get the bean factory BeanFactory factory = getBeanFactory();
MessageRenderer mr = (MessageRenderer) factory.getBean("renderer"); mr.render();
}
Copyleft by Diego Tarábola e
Denise Goya 24
Ex.: Injeção de Dependência com Spring
Com XmlBeanDefinitionReader, é possível gerenciar a configuração do bean utilizando XML em vez de propriedades:
XmlBeanFactory é derivada de DefaultListableBeanFactory que estende a configuração utilizando XmlBeanDefinitionReader
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource( "ch4/src/conf/beans.xml"));
Oracle oracle = (Oracle)factory.getBean("oracle");
DefaultListableBeanFactory factory = newDefaultListableBeanFactory();
XmlBeanDefinitionReader rdr = new XmlBeanDefinitionReader(factory);
rdr.loadBeanDefinitions(newFileSystemResource("src/conf/beans.xml"));
Oracle oracle = (Oracle)factory.getBean("oracle");
Copyleft by Diego Tarábola e
Denise Goya 25
Ex.: Injeção de Dependência com Spring
Configuração do bean: O ponto chave para qualquer aplicação baseada no Spring é
configurar um arquivo para sua aplicação.
Cada bean é definido com a tag <bean>, dentro de <beans>
<bean> possui dois atributos:
<id> utilizado para obter seu nome padrão
<class> especifica o tipo do bean
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
</beans>
Copyleft by Diego Tarábola e
Denise Goya 26
Ex.: Injeção de Dependência com Spring
Exemplo de configuração com XML:
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="renderer"
class="com.apress.prospring.ch2.StandardOutMessageRenderer"/>
<bean id="provider"
class="com.apress.prospring.ch2.HelloWorldMessageProvider"/>
</beans>
Copyleft by Diego Tarábola e
Denise Goya 27
Ex.: Injeção de Dependência com Spring
Lendo configuração do XML:
public class HelloWorldXml {
public static void main(String[] args) throws Exception {
// get the bean factory BeanFactory factory = getBeanFactory(); MessageRenderer mr = (MessageRenderer)factory.getBean("renderer"); MessageProvider mp = (MessageProvider)factory.getBean("provider");
mr.setMessageProvider(mp); mr.render(); }
private static BeanFactory getBeanFactory() throws Exception {
// get the bean factory XmlBeanFactory factory = new XmlBeanFactory(new
FileSystemResource("ch4/src/conf/beans.xml"));
return factory;
}
}
Copyleft by Diego Tarábola e
Denise Goya 28
Ex.: Injeção de Dependência com Spring
Usando Setter Injection
A tag <property> especifica a injeção de dependência; Para relacionar o bean “provider” a messageProvider do
bean “renderer”
A tag <ref> relaciona uma referência do bean à propriedade; Não é mais preciso utilizar o método set para injetar as
dependências.
<bean id="renderer”
class="com.apress.prospring.ch2.StandardOutMessageRenderer">
<property name="messageProvider"><ref local="provider"/>
</property>
</bean>
Copyleft by Diego Tarábola e
Denise Goya 29
Ex.: Injeção de Dependência com Spring
Configuração de Injeção de Dependência com XML:
public class HelloWorldXmlDI {
public static void main(String[] args) throws Exception {
// get the bean factory BeanFactory factory = getBeanFactory();
MessageRenderer mr = (MessageRenderer)factory.getBean("renderer"); mr.render(); }
private static BeanFactory getBeanFactory() throws Exception {
// get the bean factory XmlBeanFactory factory = new XmlBeanFactory(
new FileSystemResource("ch4/src/conf/beans.xml"));
return factory;
}
}
Copyleft by Diego Tarábola e
Denise Goya 30
Ex.: Injeção de Dependência com Spring
Usando Constructor Injection
A tag <constructor-arg> especifica a injeção de dependência, em vez da tag <property>;
É passada uma String (e não mais um bean);
Utiliza-se a tag <value> em vez da tag <ref> para especificar o valor do argumento do construtor;
<bean id="provider"
class="com.apress.prospring.ch4.ConfigurableMessageProvider">
<constructor-arg>
<value> This is a configurable message </value>
</constructor-arg>
</bean>
Copyleft by Diego Tarábola e
Denise Goya 31
Ex.: Injeção de Dependência com Spring
Configuração de Injeção de Dependência com XML:
Para passar mais de um argumento ou para utilizar mais de um construtor deve-se usar um índice, iniciando-se em 0 na tag <constructor-arg>.
public class ConfigurableMessageProvider {
private String message; public ConfigurableMessageProvider(String message){ this.message = message; } public String getMessage(){
return message; }
}
Copyleft by Diego Tarábola e
Denise Goya 32
Inversão de Controle e Padrão Reactor
Reactor: Padrão de Arquitetura [POSA 2];
Conhecido também como Dispatcher, Notifier
Contexto: Aplicação orientada a eventos que processa as informações
de forma síncrona e serial.
Problema: aplicações devem: atender muitas requisições simultaneamente, demultiplexar e despachar as indicações de eventos às
respectivas implementações de serviço.
Copyleft by Diego Tarábola e
Denise Goya 33
Inversão de Controle e Padrão Reactor
Define uma interface que permite que aplicações: registrem ou removam tratadores de eventos; sejam executadas no laço de eventos da aplicação.
Reactor utiliza um demultiplexador síncrono de evento para aguardar pela indicação de eventos que se originam de uma ou mais fontes.
Quando ocorre um evento: o demultiplexador síncrono de evento notifica o Reactor; o Reactor aciona o tratador associado, para realização do
serviço solicitado.
O Reactor inverte o fluxo de controle, pois é responsabilidade dele (e não da aplicação) em disparar os tratadores concretos para cada tipo de evento.
Copyleft by Diego Tarábola e
Denise Goya 34
Desvantagens na Inversão de Controle
Dificuldade na integração de arcabouços: quando dois ou mais arcabouços chamam
simultaneamente o código da aplicação, cada qual pressupondo seu próprio fluxo de controle;
Dificuldade na depuração do código e compreensão do fluxo: o controle é alternado entre o código da aplicação e
o código do arcabouço.
Copyleft by Diego Tarábola e
Denise Goya 35
Referências
[Fow06] Fowler, Martin. Inversion of Control Containers and Dependency Injection Pattern. Disponível em: http://www.martinfowler.com/articles/injection.html, acesso em 30/08/2006.
[Har05] Harrop, Rob. Machacek, Jan. Pro Spring. Capítulo 4, páginas 49 a 92. Apress, 2005.
[Mal06] Malarvannan Mani. Design Better Software with the Inversion of Control Pattern. Disponível em: http://www.devx.com/Java/Article/27583, acesso em 20/09/2006
[POSA 2] Schmidt, Douglas. Stal, Michael. Rohnert, Hans. Buschmann, Frank. Pattern-Oriented Software Architecture: Patterns for Concurrent and Networked Objects. Volume 2. Capítulo 3, páginas 175 a 214. Ed. John Wiley & Sons, 2000.
[SGN04] Schmidt, Douglas. Gokhale, Aniruddha. Natarajan, Balachandran. Leveraging Application Frameworks. ACM Queue Magazine, Vol2, Nº 5, jul-ago/2004.