Spring Bean Scope defines the lifecycle and the visibility of the instances created from the bean definitions.
This article is focused on — how to inject a bean with a shorter-lived scope such as a
prototype
into another bean with a longer-lived scope such as asingleton
. we will briefly discuss relevant bean scopes.
Below are various scopes provided by the Spring framework :
- singleton — Only one instance of the bean is created per ApplicationContext. It lives and dies with ApplicationContext — thus, It provides the longest life span. This is the default scope and every Spring-managed bean has it unless another scope is provided.
- prototype — New bean instance is created every time a request for the specific bean is made. Thus it has a shorter lifecycle.
The below scopes are relevant only for web-aware Spring ApplicationContext
- request — A new instance of the bean is created for every HTTP request from a single bean definition.
- session — A new instance of the bean is created for an HTTP session.
Spring also provides globalSession
, application
and websocket
scopes as well.
we can use @Scope
annotation to provide the scope to the bean.
@Scope("prototype")
public class Command {
...
}
For XML configuration, we have to add a scope
attribute to the bean definition.
<bean id="appCommand" class="com.initgrep.demos.Command" scope="prototype"/>
Now that we have a little background of how Spring Bean Scopes work. Let’s analyze the below code snippets 😎:
@Component
@Scope("singleton") //default
public class CommandProcessor {
@Autowired
private Command command;
public void processCommand() {
command.run();
}
}
CommandProcessor.java
@Component
@Scope("prototype")
public class Command {
public void run(){
System.out.println("Command Run for hashCode - "+this.hashCode());
}
}
Command.java
@Component
public class ProcessorApplication{
@Autowired
CommandProcessor processor;
@Override
public void run() {
processor.processCommand();
processor.processCommand();
processor.processCommand();
processor.processCommand();
}
ProcessorApplication.java
let’s see what we have here —
A Singleton Scoped Bean - CommandProcessor
and a Prototype Scoped Bean — Command
. The CommandProcessor
bean also has a dependency on Command
Bean and invokes the Command.run()
method.
We also have a singleton scoped bean — ProcessorApplication
bean which invokes CommandProcessor.process()
method.
In terms of the number of instances, two singleton bean instances for CommandProcessor
and ProcessorApplication
are created .
Since the Command
bean has the prototype scope. I am assuming, we should have multiple instances of it.
If you run the above code, the output will be similar to the below. The hash code of the Command
bean instance returned is the same for all invocations of the run()
method. That means, only one bean instance of Command
is created even though it has the prototype
scope.
Command Run for hashCode - 1155862258
Command Run for hashCode - 1155862258
Command Run for hashCode - 1155862258
Command Run for hashCode - 1155862258
Wait 🤔— Shouldn’t the prototype scope generate multiple instances since it is being called multiple times? The answer is No.
Despite the fact, the dependency has a Prototype scope, the Singleton bean is created once and all of its dependencies are resolved at that time. Hence, even though Command
has a prototype scope, it would still have only one instance of it present in the CommandProcessor
bean.
Now the obvious question here is — what if I want to inject a prototype bean in a singleton but still want multiple instances to be created, much like prototypal behavior?
Well, Spring framework provides multiple options to help with that. We will go through each one of them in detail below.
This article was orginally posted @ initgrep.com.
You can check the detailed post here
Top comments (0)