CodeGym /Courses /Module 5. Spring /Introduction to Spring Beans and Bean Lifecycle

Introduction to Spring Beans and Bean Lifecycle

Module 5. Spring
Level 1 , Lesson 9
Available

1. A quick refresher on Spring Beans

Spring Bean is basically an object managed by the Spring IoC container. These objects are created, initialized, configured, and eventually destroyed by the container based on your app configuration. If you want your Java object to be part of Spring's magic, it needs to be registered as a Bean.

Imagine a warehouse manager who always knows where the tool (or object) you need is stored. The IoC container is that manager, and the tools on the shelves are our beans.

How are beans registered in Spring?

There are several ways to register beans:

  • Annotations (for example, @Component, @Service, @Repository).
  • Java-based configuration using @Configuration and @Bean.
  • XML configuration (yeah, it's still around, but it's used less and less — why bother when you have Java annotations?).

That's why Spring is flexible — pick the registration style that works for you.


2. Spring Bean lifecycle

Beans, like living things, have a lifecycle. Their life path includes creation, initialization, usage, and destruction — all controlled by the IoC container. Let's break down how this works.

Main stages of the lifecycle

  1. Creation: the bean is created by the IoC container.
  2. Initialization: the bean can set up its internal state at this point.
  3. Usage: the bean starts doing its job (for example, handling requests).
  4. Destruction: once the bean is no longer needed, the container destroys it (unless, of course, it's a singleton).

Lifecycle visualization


1. Object creation
          ↓
2. Dependency injection (DI)
          ↓
3. Call initialization methods (@PostConstruct)
          ↓
4. Using the bean
          ↓
5. Cleanup resources (@PreDestroy)

Now let's look at a concrete example.


3. How does Spring manage the lifecycle?

Spring gives us convenient annotations for that. Let's meet the key ones.

Annotations @PostConstruct and @PreDestroy

  • @PostConstruct: runs actions after the bean is created and all dependencies are set (for example, connects a service or loads data).
  • @PreDestroy: fires before the bean is destroyed. Use it to free resources (like closing connections).

Example:


import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class LifecycleDemoBean {

    @PostConstruct
    public void init() {
        System.out.println("Bean initialized!");
    }

    public void doSomething() {
        System.out.println("Bean is working!");
    }

    @PreDestroy
    public void cleanup() {
        System.out.println("Bean destroyed!");
    }
}

When Spring sees @PostConstruct and @PreDestroy, it ensures those methods are called at the right times.


Alternative with InitializingBean and DisposableBean interfaces

If you prefer interfaces over annotations (for a more explicit contract), you can use:

  • InitializingBean — the afterPropertiesSet() method is called after the bean is created.
  • DisposableBean — the destroy() method is called before the bean is destroyed.

Example:


import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class AlternativeLifecycleBean implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Object configured (InitializingBean)!");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("Object destroyed (DisposableBean)!");
    }
}

While this approach works, modern projects usually prefer @PostConstruct and @PreDestroy for their simplicity and readability.


4. Managing beans with annotations

@Component and company**

  • @Component: a general-purpose annotation for any bean, used when a more specialized annotation doesn't fit.
  • @Service: for classes with business logic.
  • @Repository: for classes responsible for data access.
  • @Controller: for MVC controllers.

Example using @Component:


@Component
public class SimpleBean {
    public void sayHello() {
        System.out.println("Hello, bean world!");
    }
}

@Autowired and automatic dependency injection

We've touched on dependency injection a bit already, but let's go deeper.

  • @Autowired: lets Spring wire dependencies automatically.

Example using @Autowired:


@Component
public class DependencyBean {
    public String getDependencyInfo() {
        return "Dependency info.";
    }
}

@Component
public class AutowiredBean {

    private final DependencyBean dependency;

    @Autowired
    public AutowiredBean(DependencyBean dependency) {
        this.dependency = dependency;
    }

    public void printDependencyInfo() {
        System.out.println(dependency.getDependencyInfo());
    }
}

When the app runs, Spring will find DependencyBean and pass it into AutowiredBean.


5. Bean scopes

By default all beans in Spring have the singleton scope. That means there's only one instance of the bean in the IoC container. But sometimes we need different scopes.

Main scopes

  • Singleton: one bean per IoC container.
  • Prototype: a new object is created each time the bean is requested.
  • Request: one instance per HTTP request.
  • Session: one instance per HTTP session.

Setting the scope

The @Scope annotation lets you control the bean's lifecycle.


import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("A new PrototypeBean instance has been created!");
    }
}

Each time this bean is requested, a new instance is created.


6. Common mistakes and how to fix them

  1. Missing dependency error: if you use @Autowired but the bean isn't registered, Spring will throw NoSuchBeanDefinitionException. Fix? Make sure the bean is registered via annotation or configuration.
  2. Destroying prototype beans: Spring doesn't manage the lifecycle of prototype beans, so you have to destroy them yourself.
  3. Multiple matching beans: if you have several beans of the same type, Spring can get confused. Use @Qualifier to specify the exact bean.

Example with @Qualifier:


@Component("catBean")
public class Cat {}

@Component("dogBean")
public class Dog {}

@Component
public class AnimalShelter {

    @Autowired
    @Qualifier("catBean") // Specify which bean to use
    private Cat pet;
}

Where do we learn all this?

If you want to go deeper, here are a couple of useful links:


Long live beans, the lifecycle, and making our lives easier! Next step — even more Spring magic!

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION