Spring com multiplos componentes/jars?

Oi galera,

Estou desenvolvendo uma aplicação composta de vários pequenos componentes e partí,
após a modelagem, pra uma pequena prova de conceito pra ver se a parada rodaria
numa boa - de cara quebrei a cara, tô que nem uma mané tentando descobrir como
fazer isso funcionar …

Seguinte: tenho num jar comum à todos meus componentes minhas interfaces de
serviço, qq componente que quiser implementar um serviço em especial importa e
extende a interface apropriada.

Escrevi uma classe pra registry em cada um desses componentes e qdo alguém quer
usar o serviço basta importar esse registry e executá-lo para o devido setup do
beanFactory do Spring.

Até aí sem problemas, funciona tudo beleza, só que …
Primeiro: o cliente do meu serviço ficará diretamente acoplado ao pacote de
implementação pois o mesmo precisa ter conhecimento da classe de registry pra poder
executá-la e então usar o serviço.

Segundo: tentei mover esse registry pro pacote comum mas daí ELE é quem vai ficar
diretamente acoplado ao pacote de implementação e este deveria ser de completo
desconhecimento dele (já que este é uma biblioteca e deveria poder ser utilizada
por qq aplicação). Tá, meu cliente agora só precisa chamar essa classe da biblioteca
comum pra que esta então faça o registry de todo mundo mas isso é feio pra dé-déu
(afinal de contas eu estou usando o spring pra reduzir essas depêndencias certo?)

Alguém pode me dar uma luz? Tem alguma outra forma de fazer isso?

bom… vc pode usar http invoker
http://www.springframework.org/docs/reference/remoting.html

ele e mais leve que o webservice…

eu fiz um projeto como o seu a um tempo atraz, separei por projetos…
cada projeto tinha o seu contexto spring, fazia o seu controle de transações e assim por diante…
segurança eu fiz via AOP no façade…

no meu caso fez para minhas classes de negocios façades EJB…

ai ao invez de usar o http invoker eu usei EJB…

O spring instancia o ejb pra mim e injeta o serviço onde eu quiser como se fosse um pojo… a minha aplicação não precisa saber que aquilo e um ejb, ou um webservice ou um http invoker…

acho que esse e o caminho…
eu, neste projeto tive que usar ejb… (bom me disseram que era obrigatorio sabe como he…)…

espero ter ajudado…

Se você quer criar uma arquitetura de componentes de verdade é bom ler um pouco sobre o tema. Duas leituras recomendadas:

UML Components: A Simple Process for Specifying Component-Based Software - Fácil de achar (no Rio pelo menos), não muito caro mas não muito bom
Business Component Factory : A Comprehensive Overview of Component-Based Development for the Enterprise - Muito bom e meio difícil de achar mesmo na Amazon

Basicamente o que você precisa é do que em CBD chama-se de ‘Camada de Sistema’. Se você conhece arquitetura de Camadas isto é análogo à Camada de Aplicação.

edpipole, me desculpe - me expressei mal ou deixei alguma informação de lado.
Não estou usando EJBs nem WebServices - não fui claro quando mencionei ‘serviços’.

deixa ver se consigo corrigir isso:
O projeto é um plugin pro eclipse, a princípio é client server, com hibernate e o spring pra colar os vários bichinhos, os componentes, e obviamente pra ganhar skills com ioc (ou injeção de dependência, como preferirem). Digo a princípio client server porquê os detalhes de implementação (da forma como planejei) irão ficar a cargo do developer de cada componente.

Tenho uma biblioteca (um jar) com todas minhas interfaces de negócio e tipos simples utilizados pelas mesmas (uma penca de type safe enum).
Só pra exemplificar, nessa biblioteca tenho as interfaces:
ITeamDAO
IProjectDAO
IWPRDAO (WPR = Work Product Review)

ITeamDAO define alguns métodos pra CRUD e usa outras interfaces (todas na mesma biblioteca), tipo:
IMember
IRule

As outras interfaces (as dao) por sua vez tb usam outras interfaces e/ou type safes, mais ou menos como a ITeamDAO acima (puts, óbvio ululante né?).

Beleza, essa biblioteca define o que cada componente deve implementar para atender um determinado serviço (tarefa, assunto, esquema, não sei qual outro susbtantivo usar pra nomear isso). Tá num nível de abstração que considero ótimo pro meu caso (não sou especialista em OO mas não vejo como ser mais abstrato).

Na implementação dos componentes propriamente ditos, por exemplo TeamDAO, sei que devo implementar a interface ITeamDAO e qq classe utilizada pela mesma. Importo a biblioteca de interfaces, implemento e fim. Resta só o registry pro bean factory do spring (applicationContext.xml).

Até aqui está tudo direitinho, estou confuso é na hora de fazer o registry do spring, não estou encontrando uma solução decente pra registrar vários componentes sem amarrar o cliente destes à classe de implementação.

Um pouco de código, acho que vai ficar mais fácil de entender. A classe para registry do componente ProjectDAO:

[code]public final class ProjectDAORegistry {

private static final Logger _log = Logger.getLogger( ProjectDAORegistry.class.getName() );
private static final ApplicationContext _ctx = getApplicationContext();

private static ApplicationContext getApplicationContext() {
ApplicationContext ctx = null;
try {
ctx = new ClassPathXmlApplicationContext( “applicationContext.xml” );
} catch ( final Exception e ) {
_log.error( “application context not found.” );
}
return ctx;
}

public static SessionFactory getSessionFactory() {
return (SessionFactory) _ctx.getBean( “factory”, SessionFactory.class );
}

public static IProjectDAO getProjectDAO() {
return (IProjectDAO) _ctx.getBean( “projectDAO”, ProjectDAO.class );
}

private ProjectDAORegistry() {} // Singleton //
}[/code]
Maravilha né? como manda o figurino (pelo menos a documentação do spring).
Qualquer outro componente que precise desse dao (ProjectManager por exemplo) simplesmente usará algo do tipo:

É exatamente essa linha de código que está me complicando. Ela por sí só já acopla o cliente à classe de implementação. Se eu precisar usar 50 desses compo nentes vou ter de amarrar o cliente (hard coded, como acima) à esses 50 caras.
Ainda nem tenho certeza de quê essa preocupação é pertinente mas fico imaginando que essa linha possa ser facilmente replicada no meu código me fazendo acreditar que seja (se quiser usar um ProjectSuperDAO ao invés do ProjectDAO vou ter de sair procurando isso no meu fonte e ainda terei de recompilar tudo).

A primeira idéia que me veio à cabeça foi mover o registry de cada um dos componentes dao pra biblioteca comum, mas só estou mudando o problema de local (e o registry desses dao está acoplado à implementação).

Pensei então em simplesmente replicar a info do registry desses componentes (os dao) num singleton na biblioteca comum, dentro de um hash. O registry assim ficaria igualzinho ao o do código do ProjectDAORegistry acima só que em vez de retornar o bean apontado no application context ele o armazenaria nesse singleton (GlobalBeans), como segue:

public static void initProjectDAOManager() { // antigo getProjectDAOManager() GlobalBeans.put( "projectDAO", _ctx.getBean( "projectDAO", ProjectDAO.class ) ); }
O cliente então poderia utilizar o bean apropriado qdo precisasse usando:

Mas isso ainda não resolve o problema visto que esse cliente ainda vai ter de conhecer o registry de cada componente pra poder chamar seu método init correspondente (e tb não dá pra mover isso pra classe comum, a GlobalBeans, pois daí, novamente, ela é que ficaria dependente dos mesmos componentes).

O problema, no final das contas, pode ser resumido mais ou menos assim:
como posso fazer o registry de n componentes sem acoplar fortemente os clientes desses mesmos componentes? A idéia da ioc é essa não?

Alguém aqui já passou pela mesma dificuldade ? (se é que isso é difícil)

[quote=pcalcado]Se você quer criar uma arquitetura de componentes de verdade é bom ler um pouco sobre o tema. Duas leituras recomendadas:

UML Components: A Simple Process for Specifying Component-Based Software - Fácil de achar (no Rio pelo menos), não muito caro mas não muito bom
Business Component Factory : A Comprehensive Overview of Component-Based Development for the Enterprise - Muito bom e meio difícil de achar mesmo na Amazon

Basicamente o que você precisa é do que em CBD chama-se de ‘Camada de Sistema’. Se você conhece arquitetura de Camadas isto é análogo à Camada de Aplicação.[/quote]

shoes, conheço e li o primeiro livro (no mesmo curso que vc) mas o segundo ainda preciso tomar vergonha na cara (e arranjar bastante tempo) pra ler …

minha dúvida é com o spring mesmo (não fui claro no primeiro post), sorry.

valeu pela dica.

Que tal colocar um desenho, de preferência em UML, para explicar sua idéia?
:roll:

bom…
acho dificil vc fazer uma factory(registry) de componentes sem acoplar fortemente os componentes que essa factory(registry) vai construir…

Com Ioc e injeta os Beans mais mesmo assim, vc tem que conhecer as interfaces que vc vai injetar…

vc poderia fazer um registry que seria por exemplo um registryBean que injetaria os outros beans… mais percebe? vai ficar acoplado da mesma forma… inicializaria o contexto do spring em qualquer lugar da sua aplicação e lá estava ele… seu registry carregado com todos os beans…

só tem uma coisa…

pelo que eu vi… vc não precisa conhecer a classe concreta pra trazer o bean do contexto…
logo de:
return (IProjectDAO) _ctx.getBean( “projectDAO”, ProjectDAO.class );

seria :
return (IProjectDAO) _ctx.getBean( “projectDAO”);

o factory seria fortemente acoplado com as interfaces… só… isso e normal…

seria isso?

não sei se estamos falando da mesma coisa…

Lendo seu problema eu não consigo apra de pensar: você está usando Spring sem IoC?

Basicamente: acabe com a necessidade do Registry e mantenha todas as suas dependências gerenciadas pelo Spring, sem necessidade de lookups. Configure os componentes no applicationContext.xml e deixe o resto com o container de IoC.

Quanto ao livro, leia o outro. Só recomendo o Cheesman porque é fácil de achar.

[quote=edpipole]Com Ioc e injeta os Beans mais mesmo assim, vc tem que conhecer as interfaces que vc vai injetar…
[/quote]Okay, é isso mesmo que eu quero.

[quote=edpipole]vc poderia fazer um registry[/quote]Entendi, vou cair naquela história do ovo e da galinha …

[quote=edpipole]return (IProjectDAO) _ctx.getBean( “projectDAO”);[/quote]hmmm, preciso testar isso …

[quote=edpipole]o factory seria fortemente acoplado com as interfaces… só… isso e normal…
seria isso? [/quote]ISSO!!!

[quote=edpipole]não sei se estamos falando da mesma coisa… [/quote]Agora estamos!

[quote=pcalcado]Lendo seu problema eu não consigo apra de pensar: você está usando Spring sem IoC?[/quote]Desculpe minha ignorância - afinal ainda estou aprendendo e treinando (eu acho) os conceitos de ioc - mas pq vc diz que eu não estou usando?

[quote=Taz]Que tal colocar um desenho, de preferência em UML, para explicar sua idéia?
:roll: [/quote]Taz, assim que der um tempo eu posto alguns diagramas - tô hiper atolado agora.

Basicamente o que você precisa fazer é descrever a dependência entre os componentes no seu application context e deixar o resto com o Spring. Muito raramente você vai precisar de um registry e/ou factory para componentes ao utilizar IoC.

Uma classe sua precisa ser o entry point, a única que vai lidar com coisas do spring como ApplicationContext ou BeanFactory. Normalmente isso é feito por algum framework integrado, como EJB, Struts, WebWork, Spring-MVC, etc., mas se você não está utilizando esta integração precisa fazer na mão mesmo.

Nesta classe inicial você obtêm referência para um ou mais beans gerenciados pelo Spring. Ninguém fora desta deve chamar o appContext, todas as outras dependências deve ser configuradas e responsabilidade do Spring.