How to Autowire objects in Non-Spring classes / How to get Application context in Non-Spring classes / How to get access to the Spring application context In a non-Spring class

Scenario

Imagine you are working on a Spring application where most of the objects are created using Spring annotations and fields are also injected using Spring mechanisms (using @Autowired or XML configuration). Now you develop a component or use an API which is written without any use of Spring and you need one of your Spring managed classes in it.

Suppose below is the class which performs various operations and is managed by Spring :

/*
* Spring managed class which handles utility tasks
* such as database, file etc.
*/
@Component
Class MainSpringClass {
 
@Autowired
DaoClass savesInDatabase;
@Autowired
FileManager fileBasedOperations;
 
// other utility fields and methods
}

Now you modify a set of classes from an open source library which does not use Spring or write your own class to perform some operation and one of these classes needs to use the above Spring managed class. Example, see below class

public class ApiClass {
  MainSpringClass springObject;
  public void performDatabaseOperation() {
      // require an instance of MainSpringClass (Spring Managed class)
  }
}

Since the above class is from an API, its object can only be created using new operator. Or let’s say this is your own class but you cannot create its object using Spring and you need to create its object using new operator. Now you are stuck !!!! because the moment you create its object using new, you will not be able to get the instance of Spring managed class.
So the question lies, how will you get instance of MainSpringClass in ApiClass. Or how to get the instance of Spring Managed class into a Non-Spring Managed class ?
There is one way out. If somehow we can get access to Spring’s application context in any non-Spring class, instance of any Spring class can be retrieved.

Getting Spring Application Context in a class

There are many ways to get an instance of Spring application context in a class. One of them is to make the class implement org.springframework.context.ApplicationContextAware interface.
Any class which implements org.springframework.context.ApplicationContextAware interface has to implement its setApplicationContext method. This is a callback method which accepts an argument of type org.springframework.context.ApplicationContext. It is automatically called by Spring during startup and Spring passes its application context into this method.
Thus if we create a class which has access to Spring’s application context and add a public static method to this class which returns this application context, then it would be easy to get application context anywhere in the application. Once we get Application context in a class, we can get reference to any bean registered in this context.


Thus, we only need to import this class and call its public method to get application context which can then be used to get any bean registered in this context.

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContext implements ApplicationContextAware {
  @Autowired
  static ApplicationContext context;
 
 @Override
 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    context = applicationContext;
 }
 
 public static ApplicationContext getAppContext() {
    return context;
 }
}

Since the above class is annotated with @Component annotation, it is automatically called by Spring during startup and as this class implements ApplicationContextAware interface, it has to implement setApplicationContext method which is supplied with Application context by Spring as explained above.

Thus, our new class(non Spring class) which required a Spring managed bean now becomes :

public class ApiClass {
 
  public void performDatabaseOperation() {
      //get application context
      ApplicationContext context = SpringContext.getApplicationContext();
      // get instance of MainSpringClass (Spring Managed class)
      MainSpringClass springObject = (MainSpringClass)context.getBean("mainSpringClass");      
      // use this spring object to call its methods
  }
}

Let’s tweak in:

  1. Application context’s getBean method returns java.lang.Object. It has to be casted to the appropriate type before using.
  2. A bean is registered with its class name in lower case. In the above example, MainSpringClass was registered  as “mainSpringClass”.
  3. Method to get Application Context in above SpringContext class was declared as public static so that its getApplicationContext method can be accessed directly by class name and you are not required to create its object.

This Post Has 6 Comments

  1. This doesn’t make sense. When you get the ApplicationContext in you NON spring managed class you need to have spring as a dependency (or else you won’t know the getBean method)…which defeats the cope of this tutorial.

    1. Hi there,
      This tutorial does neither assumes nor states anywhere that Spring is not added as a dependency.
      It is possible that in an application, classes of one component create their object using new operator(not by Spring methods) and they need to use the functionality written in some other component which uses Spring methods such as dependency injection. Please read the Scenario section in the first paragraph carefully.
      Now how will you use Spring components in the first component. This is the problem addressed by this post. If you still have doubt, I can provide you a detailed scenario as this is the real world problem faced.

  2. Great! Exactly what I needed.
    In my case: I had to get the jdbcTemplate bean from the MvcConfig to the controller and then pass the jdbcTemplate from controller to the Dao object as parameter in order to query the db. Now using this tutorial I can access the jdbcTemplate directly in the Dao object. Thanks!

    1. Thanks!!
      Great to find it helped you…Keep visiting!

  3. nice article with very clear explaination. few questions: 1. Do we have any rule that the class implementing ApplicationContextAware interface can be anywhere or should be inside a class which is inside Spring scope?

    I also tried putting the class implementing ApplicationContextAware in the spring scope and I can see during the start up of the bootrun, the setApplicationContext() is getting called. However when I try to acess the getApplicationContext() in some class which is inside or outside the spring container I am still getting a null.

    Are we missing something here?

    1. Thank you for appreciation.
      Yes, class implementing ApplicationContextAware should be inside Spring scope because then only it will be instantiated by Spring and hence, an instance of ApplicationContext will be made available to it.
      Regarding the problem you are facing, post the code you are using so that it can be investigated further.
      Keep Visiting !!!

Mark Your Impression

Close Menu