Uses of ApplicationContext while using reflection

Generally speaking, Spring’s ApplicationContext is not advised to be used in the project business logic code as it binds the code to Spring API. But, if your application is using Spring API a lot then it is okay to use the ApplicationContext interface to get the beans created in the Spring Application.

I have found one rare use case of this ApplicationContext being used in a static way inside a class whose instance is obtained using reflection.

So, in this post, I will share my experience of using the following piece of code that I found quite useful. The following Java Code helps you to access the beans created in the application in a static way.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class ApplicationContextAccessor {

    private static ApplicationContextAccessor instance;

    @Autowired
    private ApplicationContext applicationContext;

    public static  T getBean(Class clazz) {
        return instance.applicationContext.getBean(clazz);
    }

    @PostConstruct
    private void registerInstance() {
        instance = this;
    }
}

Using this class, we can utilize the code that has been modeled using the dependency injection. If dependencies are not injected by the underlying DI container the objects can not be directly used in the classes whose instances are obtained using reflection.

For example say, you have a service layer developed using the DI. The code will work fine when you use the service layer interfaces @Autowired in the classes that you intend to use. For that the class in which you want to use the service layer has to be marked as @Component. If you mark the class as @Component the DI container will take care of the object instantiation and it will manage everything for you.

But, at times you may be interested in using such a service layer in classes whose instances are obtained using Class.forName(..) approach. Then the newly created object instance is not known to the DI contaier and the fields marked with @Autowired will be null, in which case the whole service layer classes and their injections will also be null. As a result we will get NullPointerException.

To avoid such exceptions, the above Accessor class can be used in the following way…

YourServiceLayerInterface serviceInstance = ApplicationContextAccessor.getBean(YourServiceLayerInterface.class); 

Now, since you are getting the service layer instance from the DI container, objects won’t be null.

Drawbacks:

The possible drawbacks when an interface is used as the argument to the getBean method, there can’t be multiple implementations of that interface. If there are multiple implementations you will get RuntimeException from Spring that the instance could not be produced.

If only single implementation has to be there to be used an an argument that defeats the purpose of using interfaces. To solve this issue, one can use the direct implementation classes as the argument to the getBean method. But, actually it becomes hard coding the concrete classes in the application.

Hope you found this article useful and thank you for reading.

Rajasekhar
Helical IT Solutions

Leave a Reply