A bean’s scope refers to the lifecycle of the bean; things like how long the bean will live, how many instances will be created, and how the bean is shared in the Spring environment. The default scope for the bean is a singleton, like the example below, in which we haven’t explicitly given a scope.
1 2 3
<bean id="myTeacher" class="com.nikhil.IoC.TrackTeacher"> </bean>
Singleton means that the Spring container creates only one instance of the bean, and cached in memory, and all the requests for that bean will return a shared reference to the same bean.
Here both the object references get referenced to the same bean because this is a stateless bean, where you do not need to maintain any state.
You can explicitly specify bean scope using the scope attribute.
Other bean scopes:
For a better understanding let’s code an example.
For this example our config file is,
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<!-- define the dependency --> <bean id="myQuoteService" class="com.nikhil.IoC.MotivationalQuoteService"> </bean> < !--Define your beans here --> < bean id = "myTeacher" class = "com.nikhil.IoC.TrackTeacher" > <!-- set-up constructor injection--> <constructor-arg ref="myQuoteService" /> < /bean>
Here myTeacher can be a normal Java class. As you can see, we haven’t explicitly scoped out the bean, so it is a singleton by default. Let’s test it and make a demo class to see our results. First, we create a context of our config file and then retrieve the bean from the container. Doing this calls the initialization method and then calls the close method on the context object, which then calls the destruction method.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.nikhil.IoC;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanScopeDemoApp {
public static void main(String[] args) {
// load the spring configuration file
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beanScope-applicationContext.xml");
// retrieve bean from spring container
Teacher sir = context.getBean("myTeacher", Teacher.class);
Teacher maam = context.getBean("myTeacher", Teacher.class);
String res = sir == maam ? "singleton" : "prototype";
System.out.println(res);
}
}
Output:
Let’s set it now to prototype and see the result.
1 2 3 4 5 6 7
<bean id="myTeacher" class="com.nikhil.IoC.TrackTeacher" scope="prototype"> <!-- set-up constructor injection--> <constructor-arg ref="myQuoteService" /> </bean>
Bean Lifecycle: When a container is started it initiates the beans, then dependencies are injected, and then some internal Spring processing is done. We then have the option of adding our own custom initialization code and we can also call a custom destruction method at the closing of the bean. These custom methods are called hooks, and can be used to hook in codes to execute during initialization or destruction.
To make use of the bean lifecycle we can simply add an init-method attribute to our bean**,** like below. It will call the actual method with the names doInit and doCleanUp.
1 2 3 4 5 6
<bean id="myTeacher" class="com.nikhil.IoC.TrackTeacher" init-method ="doInit" destroy-method="doCleanUp" > </bean>
Let’s code and try this on Eclipse. Below is our example class where we add our init and destruction methods.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.nikhil.IoC;
public class TrackTeacher implements Teacher {
// define a private field for the dependency
private QuoteService quoteService;
// define a constructor for dependency injection
public TrackTeacher(QuoteService quoteService) {
this.quoteService = quoteService;
}
@Override
public String getHomework() {
return "solve the previus year questions";
}
@Override
public String getDailyQuotes() {
return "Track: " + quoteService.getQuote();
}
// add an init method
public void doInit() {
System.out.println("TrackTeacher: initializaion");
}
// add a destruction method
public void doCleanUp() {
System.out.println("TrackTeacher: destruction");
}
}
Now add the attributes to our bean. Like below, make sure that the name you provide to the attribute is the same as the name of methods defined in the corresponding class, or else it may throw an exception.
1 2 3 4 5 6 7 8 9
<bean id="myTeacher" class="com.nikhil.IoC.TrackTeacher" init-method ="doInit" destroy-method="doCleanUp" > <!-- set-up constructor injection--> <constructor-arg ref="myQuoteService" /> </bean>
Make a demo class to see your results. First, we create a context of our config file and then retrieve the bean from the container. Doing this calls the initialization method and then calls the close method on the context object, which then calls the destruction method.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.nikhil.IoC;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeCycleDemoApp {
public static void main(String[] args) {
// load the spring configuration file
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beanLifeCycle-applicationContext.xml");
// retrieve bean from spring container
Teacher sir = context.getBean("myTeacher", Teacher.class);
context.close();
}
}
Output:
You can see how everything worked perfectly.
Note: When we scope our bean prototype, the destroy method isn’t called. Spring doesn’t manage the lifecycle of a prototype bean. Only the configuration, initialization, and handling to the client are done by Spring and no further record, although initialization lifecycle call methods are called on all beans regarding scope. We can destroy the prototype bean but custom coding is required.