By default, all the beans provided by Spring are singletons
. This essentially means, Spring will maintain a single instance of all the beans, and that single instance will be used to inject on the dependent objects. Also the same instance will be used to return against the ApplicationContext.getBean() call. Of course we can change this behavior using @Scope
annotation.
The scopes supported by Spring are given below –
Mode | Description |
---|---|
Singleton | The default scope is singleton. Only one object will be created per Spring IoC container. |
Prototype | A new instance will be created by Spring when requested by the application. |
Request | A new instance will be created for every HTTP request. |
Session | A new instance will be created for every HTTP session. |
Global Session | A new instance will be created for every global HTTP session of portlet applications. |
Thread | A new bean instance will be created by Spring when requested by a newthread. |
Custom | Custom bean scope that can be created by implementing the interfaceorg.springframework.beans.factory.config.Scope. |
Let’s discuss singleton and prototype scope to give you an idea how to use scope annotation.
Singleton scope
The scope singleton means, only a single instance will be created by the Spring container and that single instance will be used for all the requests for that bean.
As we said, the default scope is singleton. Meaning if you don’t specify any scope, singleton scope will be used.
Let’s explicitly specify the singleton scope for a Vehicle bean.
@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class Vehicle {
.....
.....
}
Now to test if container provides us the same instance, use following code –
Vehicle vehicle1 = applicationContext.getBean(Vehicle.class);
Vehicle vehicle2 = applicationContext.getBean(Vehicle.class);
System.out.println(vehicle1 == vehicle2);
It will return true as the same instance will be returned for both the getBean request.
Prototype scope
The prototype scope means a new bean instance will be created every time a request is made for that bean.
Let’s specify the prototype scope for the Vehicle bean.
@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Vehicle {
.....
.....
}
Now to verify if container provides us different instance, use following code –
Vehicle vehicle1 = applicationContext.getBean(Vehicle.class);
Vehicle vehicle2 = applicationContext.getBean(Vehicle.class);
System.out.println(vehicle1 == vehicle2);
It will return false as different instances will be returned for both the getBean request.
Singleton beans with prototype bean dependencies
Let’s assume we have a singleton bean that has a dependency on a prototype bean.
public interface Engine {
void start();
}
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class EngineImpl implements Engine {
public void start() {
System.out.println("Starting engine...");
}
}
@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class Vehicle {
@Autowired
private Engine engine;
public void start() {
engine.start();
}
public Engine getEngine() {
return engine;
}
}
Now let’s get two instances of Vehicle bean and verify if the engine field is pointing to the same instance or different instance.
Vehicle vehicle1 = applicationContext.getBean(Vehicle.class);
Vehicle vehicle2 = applicationContext.getBean(Vehicle.class);
System.out.println(vehicle1.getEngine() == vehicle2.getEngine());
It will return true, which essentially means, the engine reference variables for vehicle1 and vehicle2 are pointing to the same instance.
Did you expect that? Probably you thought as scope for EngineImpl is prototype, engine reference variable will point to different engine instances.
The reason that is not happening is, dependencies are resolved at instantiation time. When the Vehicle instance is created, only then a brand new Engine bean will be supplied. As singleton beans are instantiated only once, that single instance is retrieved for every request and it will carry the exact same prototype instance.
But what if you need a new instance of the Engine bean (prototype-scoped bean) whenever you request a Vehicle instance?
To achieve this we can use method injection with the @Lookup
annotation as shown below.
@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class Vehicle {
@Autowired
private Engine engine;
public void start() {
engine.start();
}
@Lookup
public Engine getEngine() {
return null;
}
}
Behind the scenes, Spring will override the method annotated with @Lookup and everytime this method is called, a new instance will be returned.
So, if you again execute the following code, it will return false.
Vehicle vehicle1 = applicationContext.getBean(Vehicle.class);
Vehicle vehicle2 = applicationContext.getBean(Vehicle.class);
System.out.println(vehicle1.getEngine() == vehicle2.getEngine());
Bean Life-Cycle Management
Spring IoC containers let you perform certain processing at certain points of their life cycle. We will discuss how we can perform some operation post initialization and pre destruction of a bean.
Post initialization processing is triggered as soon as Spring finishes setting all the field values and dependencies after instantiation. If you want Spring to call a method post initialization, you have to annotate that method with @PostConstruct
annotation.
@Service
public class Vehicle {
@PostConstruct
public void init() {
System.out.println("init method called");
}
}
Pre destruction processing is triggered just before Spring destroys a bean instance. If you want Spring to call a method before destruction, you have to annotate that method with @PreDestroy
annotation.
@Service
public class Vehicle {
@PreDestroy
public void destroy() {
System.out.println("destroy method called");
}
}
So, a simplified version of Spring bean life cycle will look like below –
That’s it for now. Hope you have enjoyed this tutorial. If you have any doubt, please ask in the comment section. I will try to answer that as soon as possible. Till then, bye bye.
Itís nearly impossible to find experienced people on this subject, but you sound like you know what youíre talking about! Thanks