Accessing spring managed beans from non spring managed classes

There may be situation when some part of application uses Springs for dependency injection and bean management and other part of application is outside the spring managed environment. If classes which are not managed by Spring requires access to the Spring managed classes, then directory creating instance of spring managed class with new operator will not work. Because if we use new for creating instance, then spring will not be able to wire the dependency correctly.

In such situations we need to create bridge between Spring managed beans and classes outside the spring management scope. Following is the code for accessing Spring Managed beans from non Spring managed classes.

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * Bridge Between Spring Managed beans and non spring managed classes
 * @author Pranav Maniar
 */
@Component
public class SpringBridge implements ApplicationContextAware {

    // Maintain reference to Spring's Application Context
    private static ApplicationContext context;

    public void setApplicationContext(ApplicationContext context)
            throws BeansException {
        this.context = context;
    }

    // Make constructor private, so that the class can not be instantiated
    private SpringBridge() {
    }

    /**
     * Get Spring Managed bean from Non Spring Managed (outside of spring) classes
     * 
     * @param type, Class of Bean whose instance is required
     * @return Spring managed bean
     */
    public static <T> T getBean(Class<T> type) {
        return (T) context.getBean(type);
    }
}

For e.g. If there is Spring managed bean UserService, which needs to be accessed from some other class. In following way spring managed beans can be accessed in outside of spring (non managed) class.

 UserService userService = SpringBridge.getBean(UserService.class);

 

How does it work?

Spring Managed Component

First SpringBridge needs to be registered as spring managed component. In the above code it is done by using @Component annotation on top of the SpringBridge class. Also, SpringBridge class needs to be on the location of Spring’s component scan, so that spring can recognize it as spring managed component.

ApplicationContextAware Interface

By implementing this interface object will be notified of the ApplicationCotext that it runs in. Normally setApplicationContext method will be invoked after population of normal bean properties but before an init callback. SpringBridge class stores reference to the applicationContext in the static variable.  Using this applicationContext any bean can be looked up.

Generic method for returning the bean

Static method public static <T> T getBean(Class<T> type)  takes class name as a parameter and returns the instance of the bean. It looks up for the bean in ApplicationContext and if instance is found there, then it is returned.

Singleton in Java

What is Singleton?

Singleton is simply a class that is instantiated exactly once.

How to create Singleton in Java?

Following are broadly three different ways in which we can create Singleton in Java.

  1. Private constructor and public static final field
  2. Private constructor and public static factory method
  3. Enum with one element

1. Private constructor and public static field

//Singleton with private constructor and public static final field
public class Singleton{
	
	//Create Instance of the Class and make it as final, so that later on it cannot be changed
	public static final Singleton INSTANCE = new Singleton();
	
	//Make constructor private, so that it can be instantiated only from inside of the class 
	private Singleton(){
		//Throw exception if someone tries to instantiate the object by accessing the constructor using reflection
		if(INSTANCE != null){
			//Instance is not null, means already one instance of the class is created, hence throw execption.
			throw new RuntimeException("Class should be instantiated only once, don't try to be smart");
		}
	}
	
	/**
	 * Other code of the class goes here
	 * /
}

The private constructor is called only during initialization of the INSTANCE variable and since INSTANCE variable is final, it can not be assigned to something else.

NOTE: It is not enough to make constructor private, since a privileged client can invoke private constructor of the class using reflection and set it’s accessible proerty to true using setAccessible(true) and then create new instances, this will create more than one instance of the class and thus it won’t be singleton anymore. This is shown in the below code snippet

Singleton instance = Singleton.INSTANCE;
//Get list of constructor for this class
Constructor[] constructors =  Singleton.class.getDeclaredConstructors();
for(Constructor constructor : constructors){
	//setAccessible to true, this will now allow code to invoke the private Constructor
	constructor.setAccessible(true);
	
	//If the constuctor does not throw exception for second instantiation,
	//then below code will create new instance of the calss and sysout will return false
	Singleton newInstance = (Singleton)constructor.newInstance();
	System.out.println("New instance is equal to instance? " + (newInstance == instance));
}

To prevent this throw exception from the constructor, if it is making the second instance of the class

 

2. Private constructor and public static factory method

//Singleton with private constructor and public static final field
public class Singleton{
	
	//Create Instance of the Class and make it as final, so that later on it cannot be changed
	private static final Singleton INSTANCE = new Singleton();
	
	//Make constructor private, so that it can be instantiated only from inside of the class 
	private Singleton(){
		//Throw exception if someone tries to instantiate the object by accessing the constructor using reflection
		if(INSTANCE != null){
			//Instance is not null, means already one instance of the class is created, hence throw execption.
			throw new RuntimeException("Class should be instantiated only once, don't try to be smart");
		}
	}
	
	//Provide public static factory method
	public static Singleton getInstance(){
		return INSTANCE;
	}
	
	/**
	 * Other code of the class goes here
	 * /
}

Here again, the private constructor is called only during initialization of the INSTANCE variable and since INSTANCE variable is final, it can not be assigned to something else.

But it has the same caveat as of the approach 1, and private constructor should throw exception if it is being called to instantiate object more than once.

3. Enum with one element

//Singleton using Enum with one field -- preferred approach
public enum Singleton{
	INSTANCE;

	/**
    * Other code of the class goes here
	**/
}

Third and recommended approach of creating Singleton is with the Java ENUM. It provides guarantee against multiple instantiation and against reflection / serialization attacks.

 
 

Singleton and Serialization of object

If Singleton created using method 1 & 2 above, implements Serializable then it should declare all instance fields as transient and provide implementation for readResolve() method. If fields are not declared transient, then each time serialize instance is deserialized a new instance will be created.

Following readResolve() method can be added for deserialization of the objects

// readResolve method to preserve singleton property
private Object readResolve() {
	// Return the Singleton instance and let the garbage collector take care of its impersonator.
	return INSTANCE;
}

NOTE: 3rd approach mentioned above(Enum with one element) does not suffer from the serialization issue mentioned above and it is the recommended approach to implement the Singleton

 
 

Singleton and object Clone

If Singleton class does not extend any Class, then there is no need to worry about the cloning. Because default clone method will throw CloneNotSupportedException

But if class extends any class, then there is one caveat that if parent class implements Cloneable, then multiple instance of the Singleton class can be created. To prevent this implement following clone method

//throw exception on cloning
public Object clone() throws CloneNotSupportedException {
	throw new CloneNotSupportedException(); 
}

NOTE: Approach 3 mentioned above does not suffer from this cloning caveat and it is the preferred method for implementing Singleton
 
 

What is the difference between Java Singleton object and Spring Singleton bean?

Java Singleton is unique for the JVM, whereas Spring Singleton bean is unique for container. There could be multiple Spring container inside the same JVM, and in that each container will have its own Singleton bean, thus multiple instance of the Singleton inside JVM and hence different from the Java Singleton.