Solution for Scoped Bean Injection Problem in Spring
By: Eresh Gorantla
Tags: Spring Boot, Java8, Bean Scope, Lifecycle Management

By default, Spring beans are singletons. This problem arises “when Prototype Bean injected inside a Singleton Bean” the problem arises when we try to wire beans of different scopes. For example, a prototype bean into a singleton. This is known as the scoped bean injection problem.

Let us look at a simple example when a prototype bean injected inside a singleton bean. Individually when a prototype bean used, every time a new instance is expected and for singleton the same instance.

Singleton Bean always returns the same bean instance no matter where ever it is being referred. In fact, all the beans default scope is a singleton even though the scope of the bean is other than a singleton.

Let’s take an example of Prototype bean and singleton bean.

Singleton Bean

The Bean has an instance counter, which checks the number of instances created for the bean.

Prototype Bean

As in singleton bean prototype bean also has the same instance counter.

A Rest API is exposed and the hashcode of the self bean is sent to the logger to see its hashcode. Let’s check for only prototype bean.

Using @Autowired prototype bean is injected in the rest controller.

Rest API

Please see below for application startup logs

Startup console

One instance of prototype bean is created which is injected from the Rest controller and an instance of a singleton is created which is injected at startup. We will discuss more on this spring life cycle to address this issue.

Let’s hit the API endpoint /test for 5 times

If you observer no new instance of prototype bean is created. Every time the same instance which is created at the start-up is returned.

Problem :

As per the Spring bean life cycle, by default all the bean injections are singleton. No matter whatever the scope is defined to spring beans they will be singleton by default. They will not recreate a new instance in-case of a prototype bean as it used Autowired or constructor injection will be part of the application startup lifecycle.

Solution :

The solution is pretty straightforward to load these different scoped beans on demand and remove them at startup. But if there are any activities that have to perform right after startup also an on-demand injection of these beans is recommended.

There are many ways to load bean dynamically. But I prefer these two.

Loading through Application Context. Loading through @Lookup Method.

The second one is the most preferred

Using Application Context

For this, I have created a simple utility class.

The getBean method is a static method, Any Spring bean can be loaded in any class with this method.

Let’s change the Rest API method

Instead of Autowired, we used BeanUtil class to load prototype bean in API method.

Console output

Now each time a new instance is returned unlike the same one in previous cases.

Don’t confuse : If you the same thing for singleton bean (using BeanUtil), the firstly the bean is checked in container and returns the same instance every time for singleton.

Using Lookup Method

A method annotated with @Lookup tells Spring to return an instance of the method’s return type when we invoke it.

Essentially, Spring will override our annotated method and use our method’s return type and parameters as arguments to BeanFactory#getBean.

@Lookup is useful for:

Injecting a prototype-scoped bean into a singleton bean (similar to Provider)

Injecting dependencies procedurally

Note also that @Lookup is the Java equivalent of the XML element lookup-method.

Modify Rest API like below.

See console below

Other possible Options

Injecting on a prototype method call

There is a possibility is to force Spring to create a new prototype instance when every call on the prototype’s method. To achieve this, you need to modify the prototype bean and set its proxy mode. You can do this by modifying the @Scope annotation as follows

@Service

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,proxyMode = ScopedProxyMode.TARGET_CLASS)

public class PrototypeBean { // ... }

By default, Spring doesn’t create a proxy object for a bean and uses the reference to the real bean when injection occurs. However, when you change the proxy mode, Spring creates and injects a special proxy object instead of the real object. The proxy decides on its own when to create the real object. By setting the proxy mode to ScopedProxyMode.TARGET_CLASS, Spring will create a new instance of the prototype whenever you call its method.

Programmatically configuring constructors also creates a new instance.

Conclusion:

Among the options using the Lookup, the method is the most reliable and perfect solution for these scenarios. @Lookup allows us to inject a dependency procedurally.