Spring Beans - Scopes
The scope of a bean defines its life cycle and visibility.
It also determines how the actual instances of a bean will be created.
For example, we may want to create a single global instance or a different instance every time a bean is requested.
Overview
We can create the beans in the spring container in six bean scopes.
Singleton
(default):- (Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
- It enforces the container to have only one instance per spring container irrespective of how much time you request for its instance. This singleton behavior is maintained by bean factory itself.
- Note that
singleton beans will not create only one instance of a class
, butone bean per bean identifier in a container
.
Prototype
:- Scopes a single bean definition to any number of object instances.
- This bean scope just reverses the behavior of singleton scope and produces a new instance each and every time a bean is requested.
Request
:- Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
- With this bean scope, a new bean instance will be created for each web request made by client. As soon as request completes, bean will be out of scope and garbage collected.
- The bean with @Scope(“request”) would be created for every new incoming request. Thus, it’s thread safety is guaranteed, since it is created everytime a new request comes in.
Session
:- Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
- This ensures one instance of bean per user session. As soon as user ends its session, bean is out of scope.
- The bean instance would be same for every session of the user. In cases where the user is accessing the application through multiple tabs of the browser, this bean scope can surely give concurrency issues. Thus, it is important for the developer to make sure that the state of the shared session data doesn’t become corrupt.
Application
:- Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
- global-session is something which is connected to Portlet applications. When your application works in Portlet container it is built of some amount of portlets. Each portlet has its own session, but if your want to store variables global for all portlets in your application than you should store them in global-session. This scope doesn’t have any special effect different from session scope in Servlet based applications.
Websocket
:- Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
- enables two-way communication between a client and a remote host. Web socket provides a single TCP connection for traffic in both directions. This is specially useful for multi-user applications with simultaneous editing and multi-user games.
Spring 3.0 has also added one additional scope called thread scope which is similar to Threadlocal.
Are Singleton Beans Thread-safe?
Spring framework does not do anything under the hood concerning the multi-threaded behavior of a singleton bean. It is the developer’s responsibility to deal with the singleton bean’s concurrency issues and thread safety.
While practically, most spring beans have no mutable state (e.g., Service and DAO classes), and as such are trivially thread-safe. But if your bean has a mutable state (e.g., View Model Objects), so you need to ensure thread safety.
The easiest and obvious solution for this problem is to change the scope of mutable beans from “singleton” to “prototype“.
Spring Singleton Thread Safety
Web containers don’t synchronize threads. Concurrent requests will be served by concurrent threads, and if these happen to read and write the same data, that can cause a data race. For instance, one thread could read the list of accounts while it is being updated with new information, and thus see an incomplete list.
Spring framework does not do anything under the hood concerning the multithreaded behavior of a singleton bean. It is the developer’s responsibility to deal with concurrency issue and thread safety of the singleton bean.
Spring does not synchronize access to a bean. If you have a bean in the default scope (singleton), there will only be a single object for that bean, and all concurrent requests will access that object, requiring that object to the thread safe.
Most spring beans have no mutable state, and as such are trivially thread safe.
If your bean has mutable state (see example below), you need to ensure that no thread sees a list of accounts (or data pulled from a backend DB/web service or some other source) the other thread is currently assembling.
The easiest way to do that is to make the accounts field volatile
. That assumes that you assign the new list to the field after having filled it (as you appear to be doing).
Using volatile
is simpler, wait-free and probably a bit more efficient than an explicit lock (though that difference is negligible when comparing it with I/O to a database).
public AccountDao {
private NamedParameterJdbcTemplate njt;
private volatile List<Account> accounts;
public AccountDao(Datasource ds) {
this.njt = new NamedParameterJdbcTemplate(ds);
refreshAccounts();
}
/*called at creation, and then via API calls to inform service new users have been added to the database by a separate program*/
public void refreshAccounts() {
this.accounts = /*call to database or to backend service to get list of accounts*/
}
//called by every request to web service
public boolean isActiveAccount(String accountId) {
Account a = map.get(accountId);
return a == null ? false : a.isActive();
}
}
For scenarios like these, caching/database is the best option. Managing concurrency ourselves is difficult. With cacheing, we can at least have memorizing for concurrency control.
How do these singleton beans behave in a heavy load web application?
Remember the golden rule choose only those beans as singleton that don’t have state.
First of all, it is important to understand that “Singleton” means only one instance i.e. the application will have only one instance of that bean. Now Spring framework doesn’t do anything under the hood concerning the multithreaded behavior this Singleton bean i.e. it’s just a normal Singleton bean and it’s upto the developer to handle the Concurrency issues pertaining to this bean.
Now, the question arises, what kind of beans should be Singleton in a web application?
. Well, the answer is pretty straightforward. Any Bean without a STATE can be singleton.
For example, beans that easily qualify to be singleton are DAO, Service, Controller - these beans don’t have their own states. Instead, we leverage these beans in our application to perform certain operations. The DAO layer beans can be singleton as they don’t have their own state - but every thread accessing them uses the DAO bean to perform certain thread specific operation. Thus, the DAO bean remains unaffected by it’s own concurrent access because it doesn’t have it’s own state.
A really bad example of choosing a Singleton bean would be a bean that needs to maintain it’s state. In that case, each thread would try to impose it’s own state on that bean, there by corrupting the data. For example, if a Person bean with setters and getter for name and age is made Singleton, if multiple threads start accessing this bean, they would keep overriding the last set values of the Person’s instance thereby corrupting the state.
Josh Long added a comment to this:
I would add that singleton Spring beans themselves can maintain their own state, it’s just that care (as you indicate) must be taken in guarding against potentially concurrent, client-specific state. There are examples of this in Spring itself: one common example is the support for the JPA EntityManager (which is not thread-safe), which, when used (e.g., @PersistenceContext EntityManager em) actually injects a proxy, which in turn forwards to a thread-local EnittyManager. So, each client gets their own thread-local-bound (which is appropriate: the JPA spec recommends that the client unit-of-work / session map 1:1 to an accquired EntityManager), but the developer just writes single-threaded code using that EntityManager. There are places like this all over the place so that developers get the best of both worlds: the speed of non-synchronized access on a singleton, and the safety of single-threaded access, where required. 99% of the time, you never need to know about it, of course.
Examples of anamolies with scopes
I was using prototype beans in my project because i want new object. Actually it was a list where all my prototype beans are getting stored. But I had to use getBean() of applicationcontext to make it work, to actually get the new object, otherwise without calling getBean() method it returned same object and worked like singleton. I didn’t realize this until my project went to production.
From spring docs “However, the bean properties themselves are not set until the bean is actually created. For beans which are singleton and set to be pre-instantiated (such as singleton beans in an ApplicationContext)” .
Singleton beans are initialized when applicationContext is initialized, but to initialize prototype bean you would have to do getBean(“BeanNameofPrototypebean”)