Inject Spring beans into EJB3

14,962

When using the SpringBeanAutowiringInterceptor, shouldn't it obtain the ApplicationContext instead of create a new one?

Yes, and this is in fact what it does. It uses the ContextSingletonBeanFactoryLocator mechanism, which in turn manages a number of ApplicationContext instances as static singletons (yes, even Spring has to resort to static singletons sometimes). These contexts are defined in beanRefContext.xml.

Your confusion seems to stem from the expectation that these contexts have any relation to your webapp's ApplicationContext - they don't, they're entirely separate. So your webapp's ContextLoader is creating and managing a context based on the bean definitions in app-config.xml, and the ContextSingletonBeanFactoryLocator creates another one. They won't communicate unless you tell them to. The EJBs cannot get hold of the webapp's context, since EJBs sit outside of that scope.

What you need to do is to move the beans that need to be used by your EJBs out of app-config.xml and into another bean definition file. This extracted set of bean definitions will form the basis of a new ApplicationContext which will (a) be accessed by the EJBs, and (b) will act as the parent context of your webapp's context.

In order to activate the parent-child link between your webapp's context and the new context, you need to add an additional <context-param> to your web.xml called parentContextKey. The value of this parameter should be the name of the context defined in beanRefContext.xml (i.e. context, in your example).

The beans that stay behind in the webapp's context will be able to reference the beans in the parent context, as will the EJBs. However, the EJBs will not be able to reference anything in the webapp's context.

Also, you cannot use XmlWebApplicationContext in beanRefContext.xml, since that class requires awareness of the webapp, and ContextSingletonBeanFactoryLocator cannot supply that awareness. You should stick with ClassPathXmlApplicationContext there.

Share:
14,962

Related videos on Youtube

ravun
Author by

ravun

Updated on June 04, 2022

Comments

  • ravun
    ravun almost 2 years

    I'm trying to inject Spring beans into an EJB using @Interceptors(SpringBeanAutowiringInterceptor.class) but I cannot get it working with the beanRefContext.xml examples I've seen.

    Here's my EJB:

    @Stateless
    @Interceptors(SpringBeanAutowiringInterceptor.class)
    public class AlertNotificationMethodServiceImpl implements
            AlertNotificationMethodService {
    
        @Autowired
        private SomeBean bean;
    }
    

    I've provided a beanRefContext.xml as follows:

    <?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>
    

    But, it seems to be recreating the beans instead of obtaining the existing ApplicationContext. I end up with the following exception because one of my beans is ServletContextAware.

    java.lang.IllegalArgumentException: Cannot resolve ServletContextResource
    without ServletContext
    

    When using the SpringBeanAutowiringInterceptor, shouldn't it obtain the ApplicationContext instead of create a new one?

    I also tried changing my web.xml so the contextConfigLocation points to the beanRefContext.xml, hoping it'd load my Spring config but I end up with the same exception as above.

    Does anyone know how to do this properly? The examples I've seen seem to use the same method I'm using which I assume means the beans are being recreated when the Interceptor is invoked (or is that how it's supposed to work and I've misunderstood).

  • ravun
    ravun about 13 years
    I eventually realized I was looking at it all wrong. Instead of creating the application context when I deploy the app, I just create it when the interceptor is called. I was assuming the ContextSingletonBeanFactoryLocator would be able to locate the web app context, but it actually creates an app context as a singleton. Thanks for the answer, skaffman, you're so smart - like a virtual Yoda.
  • skaffman
    skaffman about 13 years
    @ravun: Wire up your contexts you must, yes
  • jpmottin
    jpmottin over 2 years
    This solution doesn't work anymore with Spring 5. SpringBeanAutowiringInterceptor support has been removed. Please check my solution for Spring >= v5 : here

Related