In this article, we will discuss the complex scenario of Spring bean scopes. As we know the default bean scope of the bean is a singleton. Whenever we call getbean every time we will get the same bean instance from the application context. When application initialized JVM read all the configuration from the XML file or from the config class and loaded beans in the application context with a default bean scope singleton.
Spring Bean Scopes
To understand what happened in the background we need to enable the debug mode by adding below code in the application.properties file.
logging.level.org.springframework=debug
Show that we can identify what is happing in the background when we initialized the application.
Now in this article, we will discuss only prototype and singleton and its different way of use in the application.
Bean Scope | |
Singleton | One instance per spring context |
Prototype | New bean whenever requested |
Let’s create a java class to understand the above-mentioned scope.
RepoDaoLayer.java
@Component public class RepoDaoLayer { @Autowired DatabaseConnection jdbcConnection; public DatabaseConnection getJdbcConnection() { return jdbcConnection; } public void setJdbcConnection(DatabaseConnection jdbcConnection) { this.jdbcConnection = jdbcConnection; } }
As we can see in the above-mentioned code RepoDaoLayer has a dependency of DatabaseConnection bean. Whenever we initialized our application, spring will create an instance of DatabaseConnection along with an instance of RepoDaolayer.
Now let’s Create DatabaseConnection.java file
@Component public class DatabaseConnection { public DatabaseConnection() { System.out.println("JDBC COONECITON"); } }
Now Create DemoApplication.java main file to run the code.
@SpringBootApplication public class DemoApplication { static Logger LOG= LoggerFactory.getLogger(DemoApplication.class); public static void main(String[] args) { ApplicationContextcxt=SpringApplication.run(DemoApplication.class, args); RepoDaoLayer dao= cxt.getBean(RepoDaoLayer.class); LOG.info(dao.toString()); LOG.info(dao.getJdbcConnection().toString()); RepoDaoLayer da1= cxt.getBean(RepoDaoLayer.class); LOG.info(da1.toString()); LOG.info(da1.getJdbcConnection().toString()); } }
As we can see we are getting two instances of RepoDaoLayer class using getBean. When we run the above code we will get below output:
Here we are getting the same instance of RepoDaolayer & DatabaseConnection every time because the default bean scope is the singleton.
Now What will happen when the parent class is prototype and child is a singleton?
Now I am making RepoDaoLayer.java class prototype. By using @scope(“prototype”) over RepoDaolayer.java class
@Component @scope(“prototype”) public class RepoDaoLayer { ... }
Now run the main java file you will get below output:
As we can see in the screenshot we are getting the different instance of RepoDaolayer but same DatabaseConnection instance every time because of singleton nature of DatabaseConnection.
Now, what with happen if you make parent class as a singleton and child class as a prototype?
I am using @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) in DatabaseConnection.java class.
@Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class DatabaseConnection { ... }
Now run the main class. You will get the below output.
Now we can see we are getting same bean instances every time even we make DatabaseConnection class as a prototype? Why are we getting the same bean?
Because RepoDaoLayer class is singleton by nature and when we ask spring to give me bean of RepoDaolayer class it gives us a singleton bean without realizing that databaseConnection bean is the prototype.
If we really want to get different beans of DatabaseConnection whenever we request to Repodaolayer then we need to configure Proxy. The proxy will make sure that spring will give us new instances every time when we call RepoDaolayer bean. Below is the code to configure proxy bean of DatabaseConnecion.java class so that we can get new bean every time when we call Singleton bean.
@Component @Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE,proxyMode=ScopedProxyMode.TARGET_CLASS) public class DatabaseConnection { ... }
Here we use something called proxyMode=ScopedProxyMode.TARGET_CLASS. Which make sure that each time we get new bean when we call RepoDaoLayer. Now we can get different bean of DatabaseConnection every time when you get an instance of RepoDaolayer.
Here we can see we are getting same instance of RepoDaolayer but different instance of DatabaseConnection class because of proxy. Instead of giving DatabaseConnection object spring give us the proxy object of DatabaseConnection.
Great Article, Fahim. Thank you.
this articles is very much helpful and to the topic thankyou guys for such good piece of work….
great work fahim nice content ! keep it up the good work
Good one article with good explanation and also cover the internal part .
Very informative and helpful post. Thanks for this Fahim. Keep writing 🙂
This article gives lot of information.
Simply put and nicely explained. Thanks for the great article.
very helpful article to understand the internal object creation based on bean scope of spring framework.
very helpful article to understand the internal object creation based on bean scope of spring framework. Thanks
Thank you everyone for your appreciation..I am trying my best to explain a concept in depth.