Registrando um bean no Spring dinamicamente
Este blog deixou de ser mantido, mas o autor continua escrevendo aqui. Não deixe de assinar o novo feed!
Hoje, pleno carnaval e tal… nada melhor do que disperdiçar um tempo com projetos Open Source, não? Lógico que não. Eu devo sofrer de algum distúrbio mental mesmo, só pode…
Enfim, estava mexendo no código do Surf, melhorando o suporte ao Spring. Era algo que julgava fácil de ser resolvido, mas passei umas boas horas em cima até que uma solução apareceu.
Para utilizar o Spring em conjunto com o Surf, era preciso adicionar manualmente alguns beans do Surf para que tudo funcionasse. Um exemplo:
-
-
<beans>
-
<!– faz a integração com o Spring –>
-
<bean id="presenterSetup" class="net.sf.surfframework.integration.ioc.spring.SpringPresenterSetup" />
-
-
<!– beans da aplicação –>
-
<bean id="mainPresenter" class="surfdemo.presenter.MainPresenterImpl" />
-
-
<bean id="aboutPresenter" class="surfdemo.presenter.AboutPresenterImpl">
-
<property name="parentPresenter" ref="mainPresenter" />
-
</bean>
-
<beans>
-
Veja o bean declarado na linha 9. Em todo santo projeto era necessário declarar esse bean para que a integração entre o Surf e o Spring fosse acionada.
Mas então, o que essa classe SpringPresenterSetup tem de especial? Não muita coisa… segue um trecho do código:
-
-
package net.sf.surfframework.integration.ioc.spring;
-
-
public class SpringPresenterSetup implements InitializingBean, ApplicationContextAware {
-
-
// …
-
-
setupConfiguration();
-
}
-
-
// Faz a integração entre o Surf e o Spring
-
}
-
-
// …
-
}
-
-
Esta classe implementa a interface InitializingBean, fazendo com que o Spring invoque o método afterPropertiesSet após a criação e configuração do bean, sendo este um momento ideal para disparar o código de integração entre o Surf e o Spring.
Como o bom desenvolvedor vagabundo que sou, eu deixei que a vagabundice me orientasse. A pergunta que me veio foi:
Porque declarar toda vez o mesmo bean se existe a possibilidade de adicioná-lo automaticamente?
Depois de algumas horas de pesquisa e palpites (em vão, lógico), descobri como isso podia ser feito:
-
-
package net.sf.surfframework.integration.ioc.spring;
-
-
public class SpringPresenterSetup implements InitializingBean, ApplicationContextAware {
-
-
// …
-
-
public static void registerPresenterSetupBean(AbstractApplicationContext context) {
-
DefaultListableBeanFactory bf = (DefaultListableBeanFactory) context.getBeanFactory();
-
RootBeanDefinition bd = new RootBeanDefinition(SpringPresenterSetup.class);
-
bf.registerBeanDefinition("springSetup", bd);
-
bf.getBean("springSetup");
-
}
-
-
// …
-
}
-
Basicamente o que este código faz é criar um BeanDefinition com os dados do bean a ser instanciado e adicionar esse BeanDefinition no ApplicationContext recebido por parâmetro. O getBean() na linha 11 serve para que o Spring faça a criação e configuração do bean recém-adicionado e, conseqüentemente, dispare o código de integração.
Para que não seja preciso chamar este método toda vez que criarmos um BeanFactory, eu criei duas classes, que herdam de ClassPathXmlApplicationContext e FileSystemXmlApplicationContext e que chamam o método registerPresenterSetupBean em seus construtores. Segue um trecho de uma das classes:
-
-
package net.sf.surfframework.integration.ioc.spring;
-
-
// …
-
public class SurfClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
-
-
super(filename);
-
SpringPresenterSetup.registerPresenterSetupBean(this);
-
}
-
-
super(filenames);
-
SpringPresenterSetup.registerPresenterSetupBean(this);
-
}
-
-
// outros construtores…
-
}
-
Talvez não seja a solução mais elegante para resolver esse “problema”, mas ainda assim esta solução se mostrou razoável para o meu caso. A criação de sub-classes só para chamar o tal do método não parece certo, mas, no carnaval meu amigo.. vale tudo. Depois do feriadão eu arrumo isso!
Fazendo as alterações mostradas, agora não é mais necessário declarar o bean SpringPresenterSetup, como mostrado na primeira listagem. O único trabalho que temos é trocar
-
-
public class MinhaClasse {
-
// Trocar a classe do Spring…
-
BeanFactory beanFactory = new ClassPathXmlApplicationContext("application-context.xml");
-
}
-
}
-
por
-
-
public class MinhaClasse {
-
// … pela nossa classe
-
BeanFactory beanFactory = new SurfClassPathXmlApplicationContext("application-context.xml");
-
}
-
}
-
Esse tipo de procedimento costuma ser chamado vulgarmente de gambiware. Mas tudo bem, facilidade de uso em primeiro lugar!
UPDATE
A decisão de incluir o código de integração em sub-classes realmente foi péssima. Só estou aqui para avisar que a coisa foi separada em uma outra classe cujo uso é parecido com a listagem abaixo:
-
-
public class MinhaClasse {
-
AbstractApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
-
new SurfSpringIntegration(context).performIntegration(); // Feito!
-
}
-
}
-
Dessa forma, fica fácil para modificar ou estender o código de integração.
Tags: java, spring, tutorial

23 de fevereiro de 2007 às 5:18 am
Hum, isso dá idéias