Referencing Spring Managed Beans from Non-Spring Java Code

I encountered the need to reference Spring managed beans from legacy Java code (i.e. Java code which is not managed by Spring).

An ideal approach is to avoid mixed-mode code and Spring’ify everything. But that’s not always an option in reality. Legacy projects could have a incremental migration to Spring.

Another option is to instantiate the bean object in your non-managed code. Since you would craft such an object by hand, you have to carefully ensure that all the object dependencies are satisfied. If you miss initializing some properties, you are likely to end up with NullPointerExceptions at runtime.

A preferred approach is to let Spring create and initialize the object for you and to get a handle to that object in your legacy code. We create a ApplicationContextAware bean as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
 
public class SpringApplicationContextAware implements ApplicationContextAware {
 
  private static ApplicationContext applicationContext;
 
  public void setApplicationContext(ApplicationContext context)
                                                        throws BeansException {
      applicationContext = context;
  }
 
  public static Object getBean(String beanName) {
      return applicationContext.getBean(beanName);
  }
 
}

We then declare a singleton instance of this bean using something like this in the Spring config:

1
2
<bean id="applicationContextAware" 
class="com.somedomain.somesubdomain.SpringApplicationContextAware"/>

At the time of Spring initialization, Spring will instantiate the bean defined above. And since the class implements the ApplicationContextAware interface, Spring will invoke the setApplicationContext() method on it.

We can then access any named Spring bean as follows:

1
MyBean bean = (MyBean) SpringApplicationContext.getBean("whackyBeanName");

If you prefer the new Annotation based configuration, then we can skip the declaration above and use something like this:

1
<context:component-scan base-package="com.somedomain.somesubdomain"/>

And use the @Component annotation on the bean as follows:

1
2
3
4
5
6
7
8
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
 
@Component
public class SpringApplicationContextAware implements ApplicationContextAware {
	...
}