Jerry's Blog

Recording what I learned everyday

View on GitHub


25 April 2019

Spring(3)----Bean Scope----part1

by Jerry Zhang



Type of Scopes

In the last two articles, we discussed Spring IoC and how to inject dependencies. Like traditional class, we can create more than one object instance of a class. In this article, I am going to discuss how to define the scopes of our beans.

Spring Framework has six scopes, and you can also create a custom scope.

Scope Description
singleton (Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototype Scopes a single bean definition to any number of object instances.
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.
session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.

source: https://docs.spring.io/spring/docs/5.1.6.RELEASE/spring-framework-reference/core.html#beans-factory-scopes

singleton: only one instance in each context

This is the default scope. Anytime we try to get a bean, it is always the same bean. Let’s do an experiment:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="springioc.class007.Bean2" id="bean2" scope="singleton"/>

    <bean class="springioc.class007.Bean1" id="bean1">
        <property name="bean2" ref="bean2"/>
    </bean>

</beans>
public class Bean1 {

    private Bean2 bean2;

    public Bean2 getBean2() {
        return bean2;
    }

    public void setBean2(Bean2 bean2) {
        this.bean2 = bean2;
    }

    @Override
    public String toString() {
        return "Bean1{" +
                "bean2=" + bean2 +
                '}';
    }
}
public class Bean2 {
}
public class Class007Test {

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Bean2 bean2_1 = context.getBean("bean2", Bean2.class);
        System.out.println("bean2_1 = " + bean2_1);
        Bean2 bean2_2 = context.getBean("bean2", Bean2.class);
        System.out.println("bean2_2 = " + bean2_2);
        Bean1 bean1 = context.getBean("bean1", Bean1.class);
        System.out.println("bean1 = " + bean1);

    }
}
bean2_1 = springioc.class007.Bean2@3234e239
bean2_2 = springioc.class007.Bean2@3234e239
bean1 = Bean1{bean2=springioc.class007.Bean2@3234e239}

Prototype: anytime we require a bean from the context, contain gives us a new bean/object

If we change the scope to prototype, like this:

<bean class="springioc.class007.Bean2" id="bean2" scope="prototype"/>
bean2_1 = springioc.class007.Bean2@3234e239
bean2_2 = springioc.class007.Bean2@3d921e20
bean1 = Bean1{bean2=springioc.class007.Bean2@36b4cef0}

Notice that the bean2 are different this time.

Nested scope: various scope combination for the outside bean and inside bean

bean2 is an instance variable of bean1, or ‘inside’ bean1. If we also specify a scope for bean1, different combinations lead to different result.

Our test code:

public class Class007Test {

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        
        Bean1 bean1_1 = context.getBean("bean1", Bean1.class);
        System.out.println("bean1_1 = " + bean1_1);
        Bean1 bean1_2 = context.getBean("bean1", Bean1.class);
        System.out.println("bean1_2 = " + bean1_2);
        System.out.println("(bean1_1 == bean1_2) = " + (bean1_1 == bean1_2));
    }
}

Obviously, there is only one bean1 and only one bean2.

test result:

bean1_1 = Bean1{bean2=springioc.class007.Bean2@3234e239}
bean1_2 = Bean1{bean2=springioc.class007.Bean2@3234e239}
(bean1_1 == bean1_2) = true

Inside bean1, bean2 is the same one. This is because the outside bean is singleton.

bean1_1 = Bean1{bean2=springioc.class007.Bean2@3234e239}
bean1_2 = Bean1{bean2=springioc.class007.Bean2@3234e239}
(bean1_1 == bean1_2) = false

Obviously, they are all different.

bean1_1 = Bean1{bean2=springioc.class007.Bean2@2173f6d9}
bean1_2 = Bean1{bean2=springioc.class007.Bean2@307f6b8c}
(bean1_1 == bean1_2) = false

Use annotation to config a scope

Add an @Scope(“yourscope”) above our bean class

@Component("testBean2")
@Scope("prototype")
public class TestBean {

}
tags: Spring - framework, - Bean - Scope, - Java