Using Spring with EJB 3

Back when we were planning the migration to Glassfish, I realised we would have two dependency-injection frameworks in use – EJB 3 and Spring. For obvious reasons, I wanted to know more about how these would interact. At the time (last July), I couldn’t find anyone who had used EJB 3 and Spring together – even Ben Alex from Interface21 hadn’t come across it. Six months later, and I still haven’t heard of anyone using Spring _from_ EJBs. Except for us.


There’s lots of reasons to use both EJB 3 and Spring. EJBs have benefits Spring doesn’t give – integration with things like Servlets and JSP tags, better integration with the container for monitoring and management, tool support, and so on. Spring has benefits as well – most notably, you don’t need the container, but also you get more control over the bean lifecycle. Together, they are a good complement.

But how do you get a Spring-managed bean from an EJB? The answer: dependency injection, of course. That is, with the aid of a EJB Interceptor:

public class SpringBeanInterceptor {
  
  private BeanFactory beanFactory;
  
  @PostConstruct public void configureSpringBeans(InvocationContext context) throws Exception {
    for (Method method : context.getTarget().getClass().getMethods()) {
      if (method.isAnnotationPresent(SpringBean.class)) {
        Class springClass = method.getParameterTypes()[0];
        String springName = determineSpringBeanName(method, springClass);
        Object springBean = beanFactory().getBean(springName);
        try {
          method.invoke(context.getTarget(), springBean);
        } catch (IllegalArgumentException e) {
          throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
          throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
          throw new RuntimeException(e.getCause());
        }
      }
    }
    context.proceed();
  }
  
  private String determineSpringBeanName(Method method, Class springClass) {
    String springName = method.getAnnotation(SpringBean.class).value();
    if (springName.length() > 0) {
      springName = toCamelCase(springClass.getSimpleName());
    }
    return springName;
  }
  
  private String toCamelCase(String string) {
    return Character.toLowerCase(string.charAt(0)) + string.substring(1, string.length());
  }
  
  private BeanFactory beanFactory() {
    if (beanFactory == null) {
      BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance("classpath*:beanRefContext.xml");
      BeanFactoryReference ref = locator.useBeanFactory("applicationContext-service");
      beanFactory = ref.getFactory();
    }
    return beanFactory;
  }
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SpringBean {
  String value() default "";
}

That’s it. This Interceptor will look over an EJB, after it’s created, and provides the Spring beans. This version looks for ‘setter-methods’ with an @SpringBean annotation (you could also change it to look for fields), and looks up a corresponding bean from the Spring context (the ContextSingletonBeanFactoryLocator makes this possible).

Here’s how you would use it:

@Stateless
@Interceptors(SpringBeanInterceptor.class)
public class MyServiceBean implements MyService {
  private MySpringBean bean;

  ...

  @SpringBean public void setMySpringBean(MySpringBean bean) {
    this.bean = bean;
  }
}

With this (and one other trick I’ll discuss soon), you can (nearly) seamless integrate EJB3 and Spring.

The one big limitation of this: with Stateless Session Beans, you can only inject stateless dependencies, and you can only inject them when the EJB is initialised.

Author: Robert Watkins

My name is Robert Watkins. I am a software developer and have been for over 20 years now. I currently work for people, but my opinions here are in no way endorsed by them (which is cool; their opinions aren’t endorsed by me either). My main professional interests are in Java development, using Agile methods, with a historical focus on building web based applications. I’m also a Mac-fan and love my iPhone, which I’m currently learning how to code for. I live and work in Brisbane, Australia, but I grew up in the Northern Territory, and still find Brisbane too cold (after 22 years here). I’m married, with two children and one cat. My politics are socialist in tendency, my religious affiliation is atheist (aka “none of the above”), my attitude is condescending and my moral standing is lying down.

6 thoughts on “Using Spring with EJB 3”

  1. Thanks for the tip.
    What’s the other trick you mention at the end of your note ?
    Do you know if there is now an official package doing this ? I’m very puzzled that no body need this…

    thanks again

  2. I know this article’s a bit dated, but it comes up quite often when searching for “spring ejb3”.

    Like you guys, I was trying to roll out my own Spring + EJB3 interceptor, and even marginally succeeded to finish implementing it using Spring’s own internal classes.

    Then I realized I was using Spring Framework 2.5.1, and that comes with its own SpringBeanAutowiringInterceptor specifically for this use case.

    Just thought you and others might want to know.

  3. I’m still on Spring 1.2.8 – so I wasn’t aware of the new features in 2.5.1. However, it’s good to see that they’ve picked up this idea (or more likely come up with it themselves).

    Thanks for the tip.

  4. hi,

    this sample is very inspirational. Could you please add the full import statements of the SpringBeanInterceptor class?

  5. Hi there;
    just stumbled across this searching for a solution to the same problem (initializing Spring context within an EJB module), and so far enjoyed the idea, thanks for prodiving this example. Could you however be so kind also providing the beanRefContext.xml and, more especifically, the applicationContext-service declaration referred to in

    […]
    BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(“classpath*:beanRefContext.xml”);
    BeanFactoryReference ref = locator.useBeanFactory(“applicationContext-service”);
    […] ?

    Would be much appreciated. 🙂
    Thanks / best regards,
    Kristian

Leave a comment