How do I define bean scoping in Spring?

Bean scoping is how the bean is created and returned from the spring container to the bean requester. By default, the scope of all bean is singleton. The spring container will always return the same bean whenever this bean is required, for instance when in injected or call using the getBean() method from the application context.

There are five types of bean scope define in the Spring Container:

Scope Description
singleton Scope the bean definition to a single bean instance per Spring Container. This is the default scope when no scope is defined when creating a bean.
prototype Scope the bean to allow multiple times bean creation. This will create a new bean for each time the bean is required.
request Scope the bean definition to a single HTTP request. *
session Scope the bean definition to a single HTTP session. *
global-session Scope the bean definition to a global HTTP session. *

*) This is only valid when using the web-capable Spring context.

Let’s see the difference between Singleton and Prototype scope. First we’ll create our DummyService class.

package org.kodejava.spring.core;

public class DummyService {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Singleton Scope

By default, when no scope defined it will be a singleton.

<?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 id="service" class="org.kodejava.spring.core.DummyService" />

</beans>

Now create a program to run our example. First will run it using the singleton.xml as the configuration.

package org.kodejava.spring.core;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopeDemo {
    public static void main(String[] args) {
        try (var context = new ClassPathXmlApplicationContext("singleton.xml")) {
            DummyService serviceA = (DummyService) context.getBean("service");
            serviceA.setMessage("Hello From A");
            System.out.println("Message A = " + serviceA.getMessage());

            DummyService serviceB = (DummyService) context.getBean("service");
            System.out.println("Message B = " + serviceB.getMessage());
        }
    }
}

The output of the singleton configuration is:

Message A = Hello From A
Message B = Hello From A

The above output show that the message printed by the serviceB is the same as the serviceA. We don’t even set the message in the serviceB explicitly. It prints the same message because the getBean() method actually return the same bean both for serviceA and serviceB. This is the singleton scope.

Prototype Scope

To change the scope to prototype use the scope attribute in the bean element as shown below.

<?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 id="service" class="org.kodejava.spring.core.DummyService" scope="prototype" />

</beans>
package org.kodejava.spring.core;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopePrototypeDemo {
    public static void main(String[] args) {
        try (var context = new ClassPathXmlApplicationContext("prototype.xml")) {
            DummyService serviceA = (DummyService) context.getBean("service");
            serviceA.setMessage("Hello From A");
            System.out.println("Message A = " + serviceA.getMessage());

            DummyService serviceB = (DummyService) context.getBean("service");
            System.out.println("Message B = " + serviceB.getMessage());
        }
    }
}

Now if you try to run the same program again but changing the configuration to prototype.xml you’ll get the following output printed:

Message A = Hello From A
Message B = null

The serviceB now print a different message. This is the effect of using the prototype scope. When we call the getBean() a new bean will be created per request.

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.3.23</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central

How do I create beans through factory method?

This example show you how to create a bean using factory method in Spring Framework. We will use a singleton as an example. An instance of a singleton can be obtained only from a factory method because a singleton will have a private constructor, so it will not be possible to create an instance of this class from outside the singleton itself.

Here is our singleton bean will look like. To get an instance of it we will need to call the getInstance() method.

package org.kodejava.spring.core;

public class Singleton {

    /**
     * Private constructor.
     */
    private Singleton() {
    }

    /**
     * Get an instance of Singleton class.
     *
     * @return an instance of Singleton class.
     */
    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }

    /**
     * Do something.
     */
    public void doSomething() {
        System.out.println("Singleton.doSomething");
    }

    private static class SingletonHolder {
        static Singleton instance = new Singleton();
    }
}

Next, we will create a spring configuration file. At it simplest a bean in the configuration file will have an id and a class. To tell the spring container to create the bean using a factory method we must use the factory-method attribute of the bean element.

Here is our configuration file and we name it factory-method.xml.

<?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 id="singleton" class="org.kodejava.spring.core.Singleton" factory-method="getInstance"/>

</beans>

Let’s now run our program below:

package org.kodejava.spring.core;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FactoryMethodDemo {
    public static void main(String[] args) {
        try (ClassPathXmlApplicationContext context =
                     new ClassPathXmlApplicationContext("factory-method.xml")) {
            Singleton instance = (Singleton) context.getBean("singleton");
            instance.doSomething();
        }
    }
}

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.3.23</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central

How do I implement a Singleton pattern?

Singleton Pattern is used when we want to allow only a single instance of a class can be created inside our application. This pattern ensures that a class only have a single instance by protecting the class creation process, which can be done by defining the class constructor with private access modifier.

To get an instance of a singleton we provide a getInstance() method, this will be the only method that can be accessed to get an instance of the singleton class.

package org.kodejava.pattern.factory;

public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {
    }

    public static synchronized Singleton getInstance() {
        return instance;
    }

    public void doSomething() {
        for (int i = 0; i < 10; i++) {
            System.out.println("i = " + i);
        }
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Clone is not allowed.");
    }
}

There are some rules that need to be followed when we want to implement a singleton.

  • From code above we can see that a singleton has a static variable to keep it sole instance.
  • We need to set the class constructor into private access modifier. By this we will not allow any other class to create an instance of this singleton because they have no access to the constructor.
  • Because no other class can instantiate this singleton how can we use it? the answer is the singleton should provide a service to it users by providing some method that returns the instance, for example getInstance().
  • When we use our singleton in a multi threaded application we need to make sure that instance creation process not resulting more that one instance, so we add a synchronized keywords to protect more than one thread access this method at the same time.
  • It is also advisable to override the clone() method of the java.lang.Object class and throw CloneNotSupportedException so that another instance cannot be created by cloning the singleton object.

And this is how we use the singleton class.

package org.kodejava.pattern.factory;

public class SingletonDemo {
    public static void main(String[] args) {
        // Gets an instance of Singleton class and calls the
        // doSomething method.
        Singleton singleton = Singleton.getInstance();
        singleton.doSomething();
    }
}