Interface + IoC versus Reflection

23 respostas
saoj

Estou com uma dúvida meio louca aqui:

Quando temos IoC através de uma interface como UserDAOAware, onde podemos injetar um UserDAO, temos algo assim:

public class MyAction extends BaseAction implements UserDAOAware {

    private UserDAO userDAO = null;

    public void setUserDAO(UserDAO dao) {
        this.userDAO = userDAO;
    }


    // restante da action aqui...
}

Logo para cada coisa que se queira injetar, eu tenho que criar uma interface para tal.

Não seria mais fácil usar reflection ??? Com reflection eu posso descobrir se a classe tem o tal setUserDAO. Se tiver eu injeto se não tiver não injeto.

Com reflection posso até mesmo injetar diretamente num atributo privado.

Faz sentido isso ??? Ou a interface é necessária para dizer se a minha classe quer ou não ser injetada ??? Implementando um setUserDAO já não seria suficiente para indicar isso?

23 Respostas

vamorim

Não entendi exatamente a sua dúvida mas a resposta é: não faz sentido. :smiley:

IoC não te obriga a usar interfaces. :wink:

saoj

Ué, dois atributos necessariamente precisam de dois nomes diferentes.

private UserDao userDao1;
private UserDao userDao2;

A minha dúvida é: IoC pode funcionar com reflection, injetando até mesmo diretamente num atributo privado ou é melhor que seja feito via Interface.

louds

Depende de como for feita a configuração dos componentes
da uma olhada no pico container

ronaldtm

Po, sergio, tu me decepciona desse jeito, pensei que vc ia dar uma olhada no Spring, como havia me dito :stuck_out_tongue:

Eu não tenho certeza, mas acho que no falecido projeto Apache Avalon, as dependências eram injetadas desse jeito, usando interfaces. Mas os containers IoC ‘modernos’ (Spring, Pico, HiveMind) usam reflection sim, você não precisa declarar uma interface pra cada dependência. As interfaces surgem apenas como boas práticas, mas é perfeitamente possível usar classes que não estendem de interface alguma. Aliás, eu acho que os setters de dependências não deveriam sequer serem declarados em interfaces, pois estas representam na maioria das vezes funções de negócio, enquanto dependências são detalhes de implementação.

Quanto às diferentes formas de injeção de dependências, Martin Fowler escreveu um artigo interessante que explica bem três formas de injeção - por construtores, por setters e por interfaces -, que há algum tempo atrás eu traduzi para o português.

Eu lembro de ter lido em um blog no java.net (faz tempo), de uma outra forma de injeção, a getter injection (!). Essa abordagem também é bastante interessante, apesar de ser meio viajante :slight_smile: Consistiria em declarar getters (abstratos ou que retornassem um valor default) para as dependências, que seriam sobrescritos pelo container, fazendo-os retornar as referências dos objetos injetados.

Uma grande vantagem que eu vejo nessa abordagem é que, ao contrário da setter injection (e das outras também), não haveria a necessidade de se criar métodos públicos para a injeção (como serão sobrescritos, os getters poderiam ser apenas protected), evitando ‘sujar’ a interface pública das classes.

Como desvantagem, eu penso que as pessoas já tem dificuldade o bastante para entender a injeção usando reflection simples, imagine usando herança com geração automática de bytecode (ainda mais ‘indireto’, a meu ver)! Outro ponto seria que, por essa abordagem, seria mais difícil usar o objeto sem um container (num test-case, por exemplo), já que os métodos injetores não são públicos. Você teria que estender cada classe para injetar a depenência (argh). Além disso, essa manipulação de bytecodes necessitaria de um framework adicional como a CGlib, BCEL ou Javassist, aumentando o número mínimo de jars empacotados junto da sua aplicação.

Bom, mas já estou viajando demais… voltando à pergunta: dá pra alterar atributos privados via reflection, sem que o security manager do java reclame (sinceramente eu nunca tentei)? Via policies talvez… Mas isso seria recomendável?

Como eu já disse (e outras pessoas também) , não é preciso criar uma interface para injeção de dependências, pelo menos nos containers de Dependency Injection mais usados por aí. O uso de interfaces já foi utilizado no passado, mas acho que a morte desse projeto dá uma indicação de que a abordagem não foi muito bem aceita (também, credo, uma interface pra cada dependência???). Acessar diretamente atributos privados é perigoso, quebra completamente o encapsulamento e expõe suas classes a bugs indetectáveis (por exemplo, se você declarar um atributo privado que não deve ser injetado, que é um caso bastante comum, creio). Sobrescrever getters tem vantagens, mas não acho que elas acrescentem valor suficiente para ignorar as desvantagens.

Eu continuo ‘partidário’ da injeção via setters construtores, que não são tão invasivas ao código, não requerem malabarismos muito grandes (só reflection simples), não têm problemas com security managers, e são relativamente fáceis de compreender.

Mauricio_Linhares

Ah, outra coisa, o Spring tem suporte a esse tipo de injeção por nomes, se você tem uma dependência “userDao” o Spring pode procurar o objeto que está definido com o “id” userDao. Lá isso é conhecido como “auto-wiring”.

Contudo, entretanto, todavia, isso é terrivelmente sofrível porque o desenvolvedor vai terminar dando nome aos beans a partir da propriedade, ou pior ainda, vai botar o nome da propriedade pra ficar igual ao nome do “id” do bean. Eu, pessoalmente, acho isso uma prática horrível, prefiro que tudo fique amarrado de verdade, evitando confusões e nomes que não tem significado nenhum.

pcalcado

Mesmo para usar Autowiring voce precisaria declara beans, acho que o que o Sergio pensou e em injetar automaticamente, sem declarar nada (No XML, thanks :mrgreen:).

Sergio, sou mais um em dizer para olhar o Pico Container. Pela sua abpordagem, nao da para saber qual objeto deve ser injetado no container, convençoes de nomenclatura para este tipo de coisa sao horriveis (sim, eu conheço Rails e continuo achando horrivel te obrigar a programar do modo X ou Y por um detalhe), anotaçoes poderiam resolver mas eu ainda acredito que a grande vantagem do codigo feito pensando num IoC e que voce nao precisa se rpender ao Container. Se quem vai setar meu DAO e o Spring ou uma Factory, tanto faz (meu teste seta um mock na marra e o objeto testado nem liga).

Eu acredito que voce deva definir isso em outro lugar.

Alias, me ocorreu algo agora, mas vou abrir outro topico, esperem :twisted: :twisted: :twisted:

Mauricio_Linhares

pcalcado:
Eu acredito que voce deva definir isso em outro lugar.

Alias, me ocorreu algo agora, mas vou abrir outro topico, esperem :twisted: :twisted: :twisted:

Cadê? Cadê? Cadê? :twisted:

pcalcado

Maurício Linhares:

Cadê? Cadê? Cadê? :twisted:

Aqui, voce ja viu mas so rpa constar :slight_smile:

Thiago_Senna

Opa… acredito que este problema já está resolvido! O Sérgio já fez uma alteraçãozinha básico no Mentawai para que seja possível vc integrar o Mentawai com o container IoC que você quiser!!!

Fazer a integração com PicoContainer, Fábrica, Spring, HiveMind será tão fácil quanto tirar pirolito de criança! :mrgreen:

Thiago_Senna

Opa… acredito que este problema já está resolvido! O Sérgio já fez uma alteraçãozinha básico no Mentawai para que seja possível vc integrar o Mentawai com o container IoC que você quiser!!!

Fazer a integração com PicoContainer, Fábrica, Spring, HiveMind será tão fácil quanto tirar pirolito de criança! :mrgreen:

Shoes, será que eu naum li sua pergunta direito e respondi merda? :shock:

Bom… de qualquer jeito, pelo menos o desenvolvedor se sentirá livre para escolher qual container IoC que ele deseja, e então integrá-lo com o Mentawai.

Com isso será possível vc injetar as dependências nas suas actions numa boa, seja via setter, via construtor, interface marcadora, clips, lacinhos vermelhos e etc…

saoj

Valeu pelas dicas pessoal.

Acho então que vou oferecer no futuro todas as possobilidades de injeção. Interface Aware, Setter via reflection, e Atributo privado via reflection.

Acredito que o WebWork só oferece por interface.

E vejam que o Thiago está dando uma pesquisada na integração do Mentawai com outros containers de IoC, ou seja, ao gosto do freguês.

vamorim

Interfaces, Interfaces, Interfaces. Acho que houve uma certa confusão aqui.

Significado 1:
Interface da sintaxe de java, correspontende às classes abstratradas com permissão de herança múltipla.

Exemplo:

interface Runnable { void run(); }

Significado 2:
Interface de um componente, correspontende a todas possibilidades de interação.

Exemplo: para o componente “Televisão” tenho uma interface que me possibilita ligá-la, mudar de canal, etc.

Suponha que uma classe C tenha uma dependência D. Dessa forma, Para os containers IoC Spring e Pico:

:arrow: Esta dependência D pode ser uma classe concreta, uma classe abstrata ou pode ser uma interface (siginificado 1).
:arrow: C não precisa implementar uma interface Dware (siginificado 1) que exija um setter de um D.
:arrow: C precisa ter uma interface (siginificado 2) para injeção da dependência D.

Em outras palavras, C não precisa ter implements Dware mas precisa implementar os métodos setters.

Tirar esta última exigência tá parecendo muito estranho. Acho que este é o tipo de situação onde anotação cai bem. Marcar os atributos que podem ser injetáveis.

louds

Sergio, olha o PicoContainer. Ele prega a configuração programática de todos componentes.

J

Você pode utilizar o PicoContainer + nanocontainer-nanowar com o WebWorks. E facinho facinho e todas as suas depêndencias vão ou pelo contrutor (comportamento padrão do Pico) ou até mesmo por setter se você quizer.

Qualquer coisa manda email ([email removido]) direto pra mim que te dou uma ajuda.

Abraços,
Juze Peleteiro

saoj

A idéia é que o Mentawai seja facilmente integrável com todos esses containers. Daí cada um pode escolher o que mellhor lhe agrada.

Tb penso em colocar algum esquema de IoC, parecido com o do WebWork mas feito programaticamente e sem a nessidade de interface Aware, ou seja, via reflection mesmo. Se o cara quiser usar interface tb vai dar, mas não será obrigato’rio.

J

Vixi… achei que você tava usando o WebWorks, desculpa ae…

Vocês pretendem colocar suporte build-in para o Pico/Nanowar no Mentawai? Se sim, depois manda um email para a lista do Pico que agente coloca no site do Pico, seria muito legal. :slight_smile:

saoj

juzepeleteiro:
Vixi… achei que você tava usando o WebWorks, desculpa ae…

Vocês pretendem colocar suporte build-in para o Pico/Nanowar no Mentawai? Se sim, depois manda um email para a lista do Pico que agente coloca no site do Pico, seria muito legal. :slight_smile:

Po cara, troca umas idéias com o Thiago Senna. É ele que está fazendo isso.

A classe ActionConfig tem uma função getAction(), que retorna uma instancia de action para o request. (No mentawai é uma instancia por request).

A idéia seria estender ActionConfig e dar um override nessa função para já retornar uma action configurada pelo PicoContainer.

PicoActionConfig !!! Sacou ???

Mas não sei se basta só isso… Se tu quiser dar umas idéias seria ótimo !

Thiago_Senna

opa… entaum… vou colocar pra vcs aqui como que vai ficar o esquema para integrar o Mentawai com um framework de IoC de sua preferência! No caso do exemplo, estou usando spring, mas a idéia é vc ter autonomia para integrar o Mentawai com quem vc quiser! Seja Pico Container, Spring, HiveMind, Avalon, Excalibur e outros!!!

public interface Hello {
	
	public String sayHello();

}
public class HelloImpl implements Hello {

	public String sayHello() {
		return "Hello World!";
	}

}
public class SayHelloAction extends BaseAction {
	
	private Hello hello;	
	
	public void setHello(Hello hello) {
		this.hello = hello;
	}
	
	public String execute() {
		String helloMessage = hello.sayHello();		
		output.setValue("helloMessage", helloMessage);
		
		return SUCCESS;
	}
}
public class SpringActionConfig extends ActionConfig {

	public SpringActionConfig(Class arg0) {
		super(arg0);
	}

	public SpringActionConfig(String arg0, Class arg1) {
		super(arg0, arg1);
	}

	public SpringActionConfig(String arg0, Class arg1, String arg2) {
		super(arg0, arg1, arg2);
	}
	
	public Action getAction() {
		ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");
		Action action = (SayHelloAction) ctx.getBean("SayHelloAction");
		
		return action;
	}
}

O segredo está na classe SpringActionConfig que extende ActionConfig!

public Action getAction() {
		ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");
		Action action = (SayHelloAction) ctx.getBean("SayHelloAction");
		
		return action;
	}

Este método getAction vai retornar a instância da Action que o mentawai vai usar. Basta vc colocar no método getAction a lógica que vc precisa para o seu container IoC preferido!

Vc pode criar por exemplo, as classes PicoActionConfig, HiveMindActionConfig e etc…

Eu ainda naum terminei de implementar, e naum testei, mas a alma do negócio é essa!..

Para colocar o SpringActionConfig em ação, na teoria seria isso:

public class ApplicationManager extends org.mentawai.core.ApplicationManager {
	
	public void loadActions() {
		SpringActionConfig ac = new SpringActionConfig("/HelloWorld", SayHelloAction.class);
		ac.addConsequence(HelloMentawai.SUCCESS, new Forward("/hello.jsp"));
		ac.addConsequence(HelloMentawai.ERROR, new Forward("/error.jsp"));
		addActionConfig(ac);
	}
}

Bom… reparem que a solução que dei de exemplo ainda está um pouco imatura. Ainda é necessário fazer algumas melhorias no SpringActionConfig, para que ele consiga lidar com mais de uma Action que necessite de dependências!

Observação:
Sérgio, o último binario que abaixei hoje no site do mentawai ainda não dá para sobrescrever o método getAction da classe ActionConfig! Vc já atualizou ele???,

Abraços!
Thiago Senna

J

No caso do Pico eu nem precisava disso tudo, so precisava que o getAction utiliza-se um Factory. Assim nem precisava existir PicoActionConfig, so o velho e bom ActionConfig sendo que o o Metawai teria em um único ponto configurado qual fectory utilizar… Acho que assim ficaria mais fácil e se o cara quizer trocar de Pico para Spring (se bem, que é melhor ele trocar sempre de Spring pra Pico) seria so nesse ponto.

A ideia é semelhante ao ObjectFactory do WebWorks… Assim, nao só as Action como todos os componentes do framework poderiam vir do Pico.

Um abraço,
Juze Peleteiro

saoj

Isso vai sair na versão 1.0.2, mas já tá no CVS. Vc pode pegar do CVS guest aqui: http://mentawai.lohis.com.br/cvs.jsp

Vc diz ser melhor passar um Factory para a ActionConfig do que extende-la ??? Pode ser melhor sim. Vou conversar com o Thiago sobre isso!

Thiago_Senna

É… eu acho que usar um factory bém interessante!

Mas e se apenas algumas actions necessitam de injeção de dependência? Sendo assim, se eu quisesse criar uma factory que usasse spring, eu usaria IIoC em algumas actions, e nas restantes teria que instanciar normalmente!
Daí, eu sempre terei que me preocupar de ficar atualizando a factory…

Outra coisa desnecessária, mas interessante em extender o ActionConfig é que eu naum teria este problema de ficar atualizando a factory…

Enquanto os actions que não usam IoC continuam usando actionConfig comuns, os que precisam de ioc usam o SpringActionConfig!

O que acham…??? Estou viajando? :mrgreen:

J

Nao necessariamente passar uma Factory para o ActionConfig, mas ter um Factory que governe toda a criação de objetos do framework. Se uma action nao precisa de IoC ela nao terá IoC pq o contrutor, no caso do Pico, nao vai ter nada…

Juze Peleteiro

noelrocha

Concordo com você …

Gosto de IoC pelo fato de que você nao precisa se preocupar em extender, instanciar e etc, o framework coloca lah p/ vc …

injetar direto no atributo não me parece correto até porque como o framework vai saber em qual atributo injetar supondo q vc tivesse dois atributos do tipo UserDAO …

O PicoContainer não te obriga a fazer isso …
qual container de IoC vc tah usando?

Criado 20 de julho de 2005
Ultima resposta 20 de jul. de 2005
Respostas 23
Participantes 9