Inversão de Controle - IoC
Tópicos (Avançados) de
Programação Orientada a Objetos
Prof. Fabio Kon
DCC - IME - USP
Diego Tarábola e Denise Goya
outubro/2006
Copyleft by Diego Tarábola e Denise Goya
1
Inversão de Controle - IoC
Visão Geral

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.
Copyleft by Diego Tarábola e Denise Goya
2
Inversão de Controle — Motivação
Cenário 1
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].
public class A{
private B b;
public A(){
b=new B();
}
}
1 - diagrama UML de seqüência
Copyleft by Diego Tarábola e Denise Goya
3
Inversão de Controle — Motivação
Cenário 2
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);
}
}
2 - diagrama UML de seqüência
Copyleft by Diego Tarábola e Denise Goya
4
Inversão de Controle — Motivação
Cenário 3
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;
}
}
3 - diagrama UML de seqüência
Copyleft by Diego Tarábola e Denise Goya
5
Tipos de Inversão de Controle
Inversão de
Controle
Procura por
Dependência
Contextualized
Dependency
Lookup
Injeção de
Dependência
Dependency
Pull
Interface
Copyleft by Diego Tarábola e Denise Goya
Setter
Construtor
6
Tipos de Inversão de Controle


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
Copyleft by Diego Tarábola e Denise Goya
7
Tipos de Inversão de Controle

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
Copyleft by Diego Tarábola e Denise Goya
8
Contêineres de Inversão de Controle
Spring
Excalibur: Fortress
Avalon
Resin
PicoContainer
Copland (Ruby)
HiveMind
Mentawai
Copyleft by Diego Tarábola e Denise Goya
9
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.
Procura por Dependência com Spring
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
10
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.
Interface do Componente para CDL com Spring
public interface ManagedComponent {
public void performLookup(Container container);
}
Copyleft by Diego Tarábola e Denise Goya
11
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.
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");
}
}
Copyleft by Diego Tarábola e Denise Goya
12
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.
Injeção de Dependência pelo Construtor com Spring
public class ConstructorInjection {
private Dependency dep;
public ConstructorInjection(Dependency dep) {
this.dep = dep;
}
}
Copyleft by Diego Tarábola e Denise Goya
13
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.
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;
}
}
Copyleft by Diego Tarábola e Denise Goya
14
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).
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;
}
Copyleft by Diego Tarábola e Denise Goya
15
Injeção de Dependência —
por meio de Interface

Exemplo:
 Classe de Teste no Avalon: configura os componentes e os
injetores.
public class Tester {
private Container container;
private void configureContainer(){
container = new Container();
registerComponents();
registerInjectors();
container.start();
}
}
Copyleft by Diego Tarábola e Denise Goya
16
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:
private void registerInjectors(){
container.registerInjector(InjectFinder.class,
container.lookup(“MovieFinder”));
}
Copyleft by Diego Tarábola e Denise Goya
17
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
18
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
19
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
20
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
21
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
22
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
23
Ex.: Injeção de Dependência com Spring

Com XmlBeanDefinitionReader, é possível gerenciar a
configuração do bean utilizando XML em vez de propriedades:
DefaultListableBeanFactory factory = new
DefaultListableBeanFactory();
XmlBeanDefinitionReader rdr = new XmlBeanDefinitionReader(factory);
rdr.loadBeanDefinitions(new
FileSystemResource("src/conf/beans.xml"));
Oracle oracle = (Oracle)factory.getBean("oracle");

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");
Copyleft by Diego Tarábola e Denise Goya
24
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.
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
</beans>

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
Copyleft by Diego Tarábola e Denise Goya
25
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
26
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
27
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”
<bean id="renderer”
class="com.apress.prospring.ch2.StandardOutMessageRenderer">
<property name="messageProvider">
<ref local="provider"/>
</property>
</bean>


A tag <ref> relaciona uma referência do bean à propriedade;
Não é mais preciso utilizar o método set para injetar as
dependências.
Copyleft by Diego Tarábola e Denise Goya
28
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
29
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
30
Ex.: Injeção de Dependência com Spring

Configuração de Injeção de Dependência com XML:
public class ConfigurableMessageProvider {
private String message;
public ConfigurableMessageProvider(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}

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>.
Copyleft by Diego Tarábola e Denise Goya
31
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
32
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
33
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
34
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.
Copyleft by Diego Tarábola e Denise Goya
35
Download

Inversion of Control Containers and the Dependency - IME-USP