Spring - Injecting a Prototype Bean into a Singleton Bean Problem
If same scoped beans are wired together there's no problem. For example a singleton bean A injected into another singleton bean B. But if the bean A has the narrower scope say prototype scope then there's a problem.
To understand the problem let's see an example. We are going to have two beans
MyPrototypeBean , scoped as prototype and MySingletonBean , scoped as singleton . We will inject the prototype bean into the singleton bean. We will also access MySingletonBean via method call context#getBean(MySingletonBean.class) multiple times. We are expecting (per prototype specifications) that a new prototype bean will be created and be injected into MySingletonBean every time.Example Project
Dependencies and Technologies Used:
When
to use Spring prototype scope?
·
Prototype scope = A
new object is created each time it is injected/looked up. It will use new SomeBean() each
time.
·
Singleton scope =
The same object is returned each time it is injected/looked up. Here it will
instantiate one instance of SomeBean and then return it each time.
Prototype bean is created at the time of usage. So when you would like
to have statefull beans there is strong need sometimes to have prototypes scope
or when you don't wont to cache any values in beans. Prototype bean can be
associated with one session or some call.
Example:
A data access object (DAO) is not typically configured as a prototype,
because a typical DAO does not hold any conversational state; it was just
easier for this author to reuse the core of the singleton diagram.
Java
Singleton VS Spring singleton
The Java singleton is
scoped by the Java class loader, the spring singleton is scoped by the
container context.
Which basically means that, in Java, you can be sure a singleton is a
truly a singleton only within the context of the class loader which loaded it.
Other class loaders should be capable of creating another instance of it
(provided the class loaders are not in the same class loader hierarchy),
despite of all your efforts in code to try to prevent it.
In spring, if you could load your singleton class in two different
contexts and then again we can break the singleton concept.
Java considers something
a singleton if it cannot create more than one instance of that class within a
given class loader, whereas spring would consider something a singleton if it
cannot create more than one instance of a class within a given
container/context.
Injecting Spring Prototype bean into Singleton bean
Have you ever wonder why singleton is the default scope for Spring beans? Why isn’t it prototype?
It’s not a random choice. It’s because the vast majority of business logic we create can be safely kept in stateless objects. And the best choice for stateless beans is the singleton scope. The prototype scope is better for stateful beans to avoid multithreading issues.
Yet, sometimes you need to mix both and use a prototype bean in a singleton bean. This particular case is a bit tricky. In this article, I’m going to explain to you different ways of accessing prototypes in singletons.
When to use prototype beans?
Before we fall into the pitfalls of injecting prototype into singleton beans, stop for a moment to think when you actually need such relation.
Just because you use dependency injection in your project, it doesn’t mean you should avoid the new keyword like the plague. There is nothing wrong if you instantiate a stateful object on your own.
Usually, we use the prototype scope for a stateful object when it has dependencies on other Spring beans. Why? Because the framework will autowire these dependencies for us.
Prototype in singleton bean example
Now consider the following compoistion of Spring beans.
Let’s start with the right side of the diagram where a prototype bean depends on a singleton. No matter how many instances of MessageBuilders Spring creates, we expect they will always get the reference to the same ContentProcessor object. This part is easy.
Next, the left side. By contrast, here a singleton bean depends on a prototype. When Spring creates the MessageService bean, it will also create a single instance of MessageBuilder. But just one. That’s all MessageService needs to be created.
But hang on a minute.
For this particular graph of objects, Spring creates only one instance for each bean definition. Even though one of them is a prototype. If we had another bean depending on MessageBuilder, it would get another instance of the prototype bean. But in this case, Spring creates only one.
So what if you want a new instance of the prototype bean on every call to a particular method of the singleton bean? Not only when Spring creates this singleton?
Don’t worry. There’re multiple solutions.
You will see all possible options in a moment. But before I share them with you, we need a sample dependency between a prototype and a singleton for demonstration purpose.
Prototype in singleton dependency demo
We need a prototype, a singleton which depends on the prototype, and an automated test to verify the number of prototype instances.
Let’s write each step by step.
Prototype with instance counter
First, the prototype.
We want to know how many objects the Spring framework creates. We’re going to use a simple static counter incremented in the class constructor.
We need the counter only for testing. The main task of the class is to build some immutable Message object. Our prototype will use the Builder pattern as presented below.
Singleton dependent on prototype bean
Next, the singleton implementation.
The MesssageService class is a simple singleton with only one method. It calls all three methods of the prototype.
As a reminder, since Spring 4.3 you do not have to put the @Autowired annotation on a constructor if there is only one in a class. The framework uses it automatically.
Checking prototype instance count
Finally, we write a test that will confirm that on every call to the singleton, Spring creates a new prototype instance. That’s our goal. We call the singleton twice so we expect two objects.
Now we’re ready to examine all possible solutions to inject prototype bean into a singleton.
How to inject prototype bean into singleton bean?
When you work with a prototype bean in a singleton, you have three options to get a new instance of the prototype:
Option 1: Injecting on singleton construction
As I already mentioned, injecting on construction is default behavior of the framework. If a singleton bean depends on a prototype, Spring creates a single prototype instance dedicated for this particular singleton.
The singleton resuses its single prototype instance through its whole lifecycle.
Let’s run the test we wrote in the previous paragraph and confirm that Spring creates only one prototype.
Option 2: Injecting on prototype method call
Another possibility is to force Spring to create a new prototype instance when every call on 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:
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.
What is the outcome of our test?
We didn’t get one instance, as without the proxy, but as many as six.
Why that happened?
In our test, we call the createMessage() method on the MessageService object twice and this, in turn, executes three methods of the proxied MessageBuilder. Two times three gives us six in total and that is what our test proved.
However, that is not what we wanted and it is even worse. Not only got we more instance than we expected, but also the final result is different than wanted because each instance has a separate state.
The createMessage() method relies on the state that is stored between sequential calls on the prototype. With the given setup, the state is lost on every call to prototype methods. Therefore, setting a proxy mode is a dead end for our problem.
Option 3: Creating prototype on demand with ObjectFactory
The last option is the most flexible because it allows you to create a new prototype instance manually. Thanks to bean definition, Spring knows how to create a prototype. You just need to tell the framework when to do it.
That’s when ObjectFactory comes in.
ObjectFactory is a functional interface from Spring framework designed to provide a reference to beans managed by the application context. The interface defines only one method which returns an instance of the selected bean.
How to use ObjectFactory with prototype beans?
It’s very simple. You just need to define a dependency on the ObjectFactory for the chosen bean. Spring will generate and inject the appropriate implementation of the interface.
Let’s update the MessageService singleton to see the factory in action.
Thanks to ObjectFactory you can create a prototype instance exactly when you need it.
If we run our test again, it will pass. Every call to the createMessage() method gets its own instance of the prototype.
ObjectFactory in unit test
One of the reasons to use dependency injection is to simplify unit testing. It’s really simple to replace a real dependency with a stub or a mock.
Because ObjectFactory is a function interface, you can easily write its stub implementation with the lambda expression.
conclusion
At this point, you should know about all the possible options for creating prototype beans. You learned that injecting a prototype bean into singleton may be a bit tricky. After reading the article, you know which injecting option is best for your requirements.
How many instances created for singleton bean referring to a session bean/prototype bean
The singleton scope
When a bean is a
singleton , only one shared instance of the bean will be managed, and all requests for beans with an id or ids matching that bean definition will result in that one specific bean instance being returned by the Spring container.
To put it another way, when you define a bean definition and it is scoped as a
singleton , then the Spring IoC container will create exactly one instance of the object defined by that bean definition. This single instance will be stored in a cache of such singleton beans, and all subsequent requests and references for that named bean will result in the cached object being returned.
The session scope
With the above bean definition in place, the Spring container will create a brand new instance of the bean , for the
lifetime of a single HTTP Session .
According to Spring framework reference, a different approach needs to be followed in cases where a class which "
lives longer "(singleton bean in this case) needs to be injected with another class having a comparatively shorter life-span(session-scoped bean). The approach is different for prototype & singleton scope though.
In your XML, what we want is that the singletonBean instance should be instantiated only once, and it should be injected with sessionBean. But since
sessionBean is session-scoped(which means it should be re-instantiated for every session), the configuration is ambiguous(as the dependencies are set at instantiation time and the session scoped value can change later also).
So instead of injecting with that class, its injected with a proxy that exposes the exact same public interface as sessionBean. The container injects this proxy object into the singletonBean bean, which is unaware that this sessionBean reference is a proxy. Its specified by writing this tag in the sessionBean:
|
Saturday, April 6, 2019
Spring interview Questions and Answers
Subscribe to:
Post Comments (Atom)
All Java 8 / J2EE Interview for Experienced
1. Functional Interface, Stream API? Functional interfaces are also called Single Abstract Method interfaces (SAM Interfaces). As ...
No comments:
Post a Comment