Fading Coder

One Final Commit for the Last Sprint

Home > Tools > Content

Understanding Bean Scopes and Lifecycle in Spring Framework

Tools May 7 4

In Spring Framework, Beans are central to application structure, serving as the primary units managed by the IoC container. This article explores how Bean scopes influence object behavior and how the lifecycle governs their creation and destruction.

Bean Scopes

A Bean’s scope defines its lifecycle and visibility within the Spring container. While Java SE uses "scope" to refer to variable visibility in code blocks, Spring uses it to describe how many instances of a Bean exist and how they are shared.

Spring supports six scopes:

  1. singleton – One instance per Spring IoC container (default).
  2. prototype – A new instance is created each time the Bean is requested.
  3. request – One instance per HTTP request (web-aware contexts only).
  4. session – One instance per HTTP session (web-aware contexts only).
  5. application – One instance per ServletContext (web-aware contexts only).
  6. websocket – One instance per WebSocket session (web-aware contexts only).

Only singleton and prototype are available in non-web Spring applications.

The Problem with Singleton Scope

Consider a scenario where a User object is defined as a singleton Bean:

public class User {
    private String name;
    private int age;

    // getters and setters
    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

Registered via:

@Component
public class UserConfig {
    @Bean
    public User user() {
        User u = new User();
        u.setName("zhangsan");
        u.setAge(20);
        return u;
    }
}

If one controller modifies this shared instance:

@Controller
public class UserControllerA {
    @Autowired
    private User user;

    public void process() {
        User temp = user; // shallow copy
        temp.setName("lisi");
        temp.setAge(18);
    }
}

Another controller retrieving the same Bean will observe the modified state, leading to unexpected behavior:

// Output after both controllers run:
// UserControllerA sees: User{name='zhangsan', age=20}
// After modification: User{name='lisi', age=18}
// UserControllerB sees: User{name='lisi', age=18}  ← unintended!

Resolving with Prototype Scope

To avoid shared mutable state, declare the Bean with prototype scope:

@Component
public class UserConfig {
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean
    public User user() {
        User u = new User();
        u.setName("zhangsan");
        u.setAge(20);
        return u;
    }
}

Now, each injection point receives a fresh instance:

// UserControllerA modifies its own copy
// UserControllerB receives original values
// Output:
// UserControllerA: User{name='zhangsan', age=20} → modified to lisi/18
// UserControllerB: User{name='zhangsan', age=20}

The @Scope annotation can be applied to either @Bean methods or @Component classes, and values can be specified as strings ("prototype") or constants (ConfigurableBeanFactory.SCOPE_PROTOTYPE).

Spring Execution Flow

  1. Container Initialization: ApplicationContext loads configuration (e.g., XML or annotations).
  2. Bean Instantiation: Beans are created via reflection using constructors.
  3. Dependency Injection: Properties are injected (via setter, field, or constructor injection).
  4. Registration: Fully initialized Beans are stored in the IoC container (typically a Map<String, Object>).
  5. Usage: Application code retrieves and uses Beans.
  6. Destruction: On container shutdown, destruction callbacks are invoked.

Bean Lifecycle

A Bean’s lifecycle consists of five phases:

  1. Instantiation – Memory allocation and constructor execution.
  2. Population of Properties – Dependency injection occurs.
  3. Initialization – In order:
    • Aware interface callbacks (e.g., BeanNameAware.setBeanName())
    • @PostConstruct annotated method
    • InitializingBean.afterPropertiesSet()
    • Custom init-method from XML or @Bean(initMethod = "...")
  4. Usage – The Bean is ready for application logic.
  5. Destruction – On shutdown:
    • @PreDestroy annotated method
    • DisposableBean.destroy()
    • Custom destroy-method

Lifecycle Demonstration

@Component
public class LifecycleDemo implements BeanNameAware, InitializingBean {
    public LifecycleDemo() {
        System.out.println("Constructor called");
    }

    @Autowired
    public void inject(User user) {
        System.out.println("Dependency injected");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("BeanNameAware: " + name);
    }

    @PostConstruct
    public void postConstructInit() {
        System.out.println("@PostConstruct executed");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("InitializingBean.afterPropertiesSet()");
    }

    public void initFromXml() {
        System.out.println("XML init-method executed");
    }

    public void use() {
        System.out.println("Using bean");
    }

    @PreDestroy
    public void cleanup() {
        System.out.println("@PreDestroy executed");
    }
}

With XML configuration:

<bean id="lifecycleDemo" 
      class="com.example.LifecycleDemo"
      init-method="initFromXml" />
<context:component-scan base-package="com.example" />

Output during startup and shutdown:

Constructor called
Dependency injected
BeanNameAware: lifecycleDemo
@PostConstruct executed
InitializingBean.afterPropertiesSet()
XML init-method executed
Using bean
@PreDestroy executed

Related Articles

Efficient Usage of HTTP Client in IntelliJ IDEA

IntelliJ IDEA incorporates a versatile HTTP client tool, enabling developres to interact with RESTful services and APIs effectively with in the editor. This functionality streamlines workflows, replac...

Installing CocoaPods on macOS Catalina (10.15) Using a User-Managed Ruby

System Ruby on macOS 10.15 frequently fails to build native gems required by CocoaPods (for example, ffi), leading to errors like: ERROR: Failed to build gem native extension checking for ffi.h... no...

Resolve PhpStorm "Interpreter is not specified or invalid" on WAMP (Windows)

Symptom PhpStorm displays: "Interpreter is not specified or invalid. Press ‘Fix’ to edit your project configuration." This occurs when the IDE cannot locate a valid PHP CLI executable or when the debu...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.