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
public 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 SpringContext class above 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.
    Refer static keyword.

3 Comments

Leave a Reply