Open In App

Custom Bean Scope in Spring

Last Updated : 04 Oct, 2025
Comments
Improve
Suggest changes
3 Likes
Like
Report

In Spring Framework, bean scopes determine the lifecycle and visibility of beans in an application context. While Spring provides several built-in scopes such as singleton, prototype, request, session, and application, sometimes applications require custom scopes to manage beans according to specific business requirements.

Spring allows developers to define custom bean scopes to control the lifecycle beyond the predefined scopes.

When to Use Custom Scopes

  • When a bean needs to live beyond a single HTTP request but less than a singleton.
  • When managing resources per thread, user, or tenant.
  • When the built-in scopes do not provide the required lifecycle behavior.

Steps to Define a Custom Scope

1. Implement the Scope Interface

The org.springframework.beans.factory.config.Scope interface defines methods to manage the lifecycle of custom-scoped beans.

Java
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ThreadLocalScope implements Scope {
    private final ThreadLocal<Map<String, Object>> threadLocal =
            ThreadLocal.withInitial(ConcurrentHashMap::new);

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> scopedObjects = threadLocal.get();
        return scopedObjects.computeIfAbsent(name, k -> objectFactory.getObject());
    }

    @Override
    public Object remove(String name) {
        return threadLocal.get().remove(name);
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        // Optional: destruction logic if required
    }

    @Override
    public Object resolveContextualObject(String key) {
        return null; // Not used in this example
    }

    @Override
    public String getConversationId() {
        return Thread.currentThread().getName();
    }
}

Explanation of Methods:

  • get(): Returns the bean instance for the given name; creates one if not present.
  • remove(): Removes the bean from the scope.
  • registerDestructionCallback(): Registers a callback to be called on bean destruction.
  • resolveContextualObject(): Provides contextual objects (optional).
  • getConversationId(): Returns a unique ID for the current scope context.

2. Register the Custom Scope in Spring Context

Custom scopes can be registered using CustomScopeConfigurer in Java configuration or XML configuration.

Java Configuration Example:

Java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.config.CustomScopeConfigurer;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class AppConfig {
    @Bean
    public static CustomScopeConfigurer customScopeConfigurer() {
        CustomScopeConfigurer configurer = new CustomScopeConfigurer();
        Map<String, Object> scopes = new HashMap<>();
        scopes.put("thread-local", new ThreadLocalScope());
        configurer.setScopes(scopes);
        return configurer;
    }

    @Bean
    @org.springframework.context.annotation.Scope("thread-local")
    public MyBean myBean() {
        return new MyBean();
    }
}

3. Using the Custom Scoped Bean

Java
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class CustomScopeDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);

        Runnable task = () -> {
            MyBean bean1 = context.getBean(MyBean.class);
            MyBean bean2 = context.getBean(MyBean.class);
            System.out.println(Thread.currentThread().getName() + ": " + (bean1 == bean2));
        };

        Thread t1 = new Thread(task, "Thread-1");
        Thread t2 = new Thread(task, "Thread-2");

        t1.start();
        t2.start();
    }
}

Output Example:

Thread-1: true

Thread-2: true

Explanation:

  • Each thread gets its own instance of MyBean.
  • Instances are shared within the same thread but isolated across threads.

Advantages of Custom Bean Scopes

  • Fine-grained control over bean lifecycle.
  • Enables per-thread, per-user, or per-conversation bean management.
  • Reduces resource usage by limiting bean lifespan to specific contexts.
  • Improves modularity by isolating beans according to business requirements.

Explore