É fato que a especificação EJB3 trouxe uma enorme facilidade para o desenvolvimento de aplicações Java EE, porém, ainda sinto falta de algumas simplicidades, como por exemplo: “Como injetar um POJO em um SessionBean?” Ok, mas porque eu iria querer fazer isso ? E outra, fiquei sabendo que tem injeção de dependência em EJB3 via annotations, pra que colocar outro container de IoC, como o Spring ?

Ótimas perguntas! Então, vamos lá:

Em primeiro lugar, o IoC do EJB3 só funciona para recursos controlados pelo container, tais como: EJBs, Datasources, Filas, Topicos, etc. Ou seja, se você quiser injetar um POJO, no seu SessionBean, infelizmente não existe uma annotation @POJO, para fazer isso.

Com isso, podemos concluir que para tirar proveito da IoC do seu servidor de aplicação Java EE favorito, você deveria transformar todos os seus objetos de negócio em objetos gerenciados pelo container (traduzindo, EJB), mas isso nem sempre é desejado ou permitido (no caso de você utilizar uma classe ou jar de terceiros, ou compartilhar um modulo com outro projeto que não utiliza EJB). Então, o que fazer ? Simples: AOP!

AOP ?!?! Sim, mas calma, a solução é bem mais simples do que parece. Basta criar uma annotation (@Spring, por exemplo) e implementar o seu próprio interceptor, que irá carrega o seu xml do spring com as definições dos beans (seu applicationContext.xml) e injetá-los, onde estiver marcado com a annotation criada.

A sua annotation poderia ser:

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Spring {
        String bean();
}

A mágica:

Aqui vai um exemplo bem simples de interceptor que carrega as configurações do applicationContext, e sai injetado os beans do spring onde tiver uma propriedade anotada com @Spring:

public class SpringInterceptor {

	// AplicationContext - Spring
	private static ApplicationContext appCtx = new ClassPathXmlApplicationContext("applicationContext.xml");

	@PostConstruct
	// O Método anotado com PostConstructor deve receber um parametro (InvocationContext),
	// nao deve lançar exceção e o retorno deve ser void
	public void init(InvocationContext invocationContext) {

		// Obtém o session bean que terá as propriedades injetadas
		Object o = invocationContext.getTarget();

		Field[] fields = o.getClass().getDeclaredFields();
		try {
			for (int i = 0; i < fields.length; i++) {

				if (fields[i].isAnnotationPresent(Spring.class)) {
					// Seta o atributo como acessível (sim, quebra o encapsulamento =p )
					fields[i].setAccessible(true);
					// Obtém o nome do Bean e o busca no contexto do spring (ApplicationContext)
					Spring springAnnotation = fields[i].getAnnotation(Spring.class);
					// Injeta o SpringBean(POJO) na propriedade do SessionBean
					fields[i].set(o, appCtx.getBean(springAnnotation.bean()));
				}
			}
		} catch (Exception e) {
                        // Tá, isso pode ser bem melhor ;p
			e.printStackTrace();
		}
	}
}

O Segredo:

Note que toda a lógica do interceptor está no método anotado com @PostConstruct, ou seja o pós-construtor do interceptor. Na verdade este nosso interceptor não intercepta nenhuma chamada. Ele apenas é construído, e na sua construção, injeta os pojos que definimos no arquivo applicationContext.xml. Legal né?

Modo de usar:

Para usar, você tem que indicar, no seu SessionBean, que irá utilizar o interceptor criado:

@Stateless
@Interceptors(value = SpringInterceptor.class)
public class MySessionBean implements MySession {

	@Spring(bean="MyBean")
	private MyBean MyBeanImpl;

        ...
}

Neste caso, a nossa annotation funciona apenas para propriedades (Fields), mas é facilmente expansível para métodos, o que fica como "lição de casa".

No TweetBacks yet. (Be the first to Tweet this post)