2011-03-09 23 views
9

Estoy intentando inyectar Spring beans en un EJB usando @Interceptors(SpringBeanAutowiringInterceptor.class) pero no puedo hacerlo funcionar con los ejemplos beanRefContext.xml que he visto.Inyectar beans de primavera en EJB3

Aquí es mi EJB:

@Stateless 
@Interceptors(SpringBeanAutowiringInterceptor.class) 
public class AlertNotificationMethodServiceImpl implements 
     AlertNotificationMethodService { 

    @Autowired 
    private SomeBean bean; 
} 

que he proporcionado un beanRefContext.xml de la siguiente manera:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="..."> 

    <!-- Have also tried with ClassPathXmlApplicationContext --> 
    <bean id="context" 
     class="org.springframework.web.context.support.XmlWebApplicationContext"> 
     <property name="configLocations" value="/config/app-config.xml" /> 
    </bean> 

</beans> 

embargo, parece ser la recreación de los granos en lugar de obtener el Application Context existente. Termino con la siguiente excepción porque uno de mis beans es ServletContextAware.

java.lang.IllegalArgumentException: Cannot resolve ServletContextResource 
without ServletContext 

Cuando se utiliza el SpringBeanAutowiringInterceptor, ¿no debería obtener el Application Context en lugar de crear una nueva?

También traté de cambiar mi web.xml para que el contextConfigLocation apunte al beanRefContext.xml, con la esperanza de que cargue mi configuración Spring pero termino con la misma excepción que la anterior.

¿Alguien sabe cómo hacer esto correctamente? Los ejemplos que he visto parecen usar el mismo método que estoy usando, y supongo que significa que los beans se vuelven a crear cuando se invoca el interceptor (o es así como se supone que debe funcionar y no he entendido bien).

+0

Un útil enlace que explica todo el proceso: http://techo-ecco.com/blog/spring-application-context-hierarchy-and-contextsingletonbeanfactorylocator/ – omartin

Respuesta

11

Cuando se utiliza el SpringBeanAutowiringInterceptor, ¿no debería obtener el ApplicationContext en lugar de crear una nueva?

Sí, y esto es lo que hace. Utiliza el mecanismo ContextSingletonBeanFactoryLocator, que a su vez gestiona varias instancias ApplicationContext como singleton estáticos (sí, incluso Spring tiene que recurrir a singleton estáticos a veces). Estos contextos se definen en beanRefContext.xml.

Su confusión parece deberse a la expectativa de que estos contextos tienen alguna relación con su aplicación web ApplicationContext - no, están completamente separados. Entonces, su aplicación web ContextLoader está creando y administrando un contexto basado en las definiciones de bean en app-config.xml, y el ContextSingletonBeanFactoryLocator crea otro. No se comunicarán a menos que usted les diga que lo hagan. Los EJB no pueden controlar el contexto de la aplicación web, ya que los EJB se encuentran fuera de ese alcance.

Lo que debe hacer es mover los beans que los EJB necesitan de app-config.xml a otro archivo de definición de bean. Este conjunto extraído de definiciones de bean formará la base de un nuevo ApplicationContext que (a) tendrá acceso a los EJB y (b) actuará como el contexto principal del contexto de su aplicación web.

Para activar el vínculo padre-hijo entre el contexto de su aplicación web y el nuevo contexto, debe agregar un <context-param> adicional a su web.xml llamado parentContextKey. El valor de este parámetro debe ser el nombre del contexto definido en beanRefContext.xml (es decir, context, en su ejemplo).

Los beans que se quedan en el contexto de la aplicación web podrán hacer referencia a los beans en el contexto principal, al igual que los EJB. Sin embargo, los EJB no podrán hacer referencia a nada en el contexto de la aplicación web.

Además, no puede usar XmlWebApplicationContext en beanRefContext.xml, ya que esa clase requiere conocimiento de la aplicación web, y ContextSingletonBeanFactoryLocator no puede proporcionar esa información. Deberías quedarte con ClassPathXmlApplicationContext allí.

+0

Finalmente me di cuenta de que estaba viendo todo mal. En lugar de crear el contexto de la aplicación cuando despliegue la aplicación, simplemente la creo cuando se llama al interceptor. Asumí que el ContextSingletonBeanFactoryLocator podría ubicar el contexto de la aplicación web, pero en realidad crea un contexto de aplicación como singleton. Gracias por la respuesta, skaffman, eres tan inteligente, como un Yoda virtual. – ravun

+3

@ravun: Conecta tus contextos, debes, sí – skaffman

Cuestiones relacionadas