Loading...

Chapter 8: Spring - Bean Definition

Introduction

In Spring, a bean is simply an object that is managed by the Spring IoC container. To tell Spring how to manage a bean, we need to define the bean. This chapter will dive into the concept of bean definitions, which describe how Spring should create and manage the beans in the container.

A bean definition consists of:

  • The bean class.
  • Bean name (optional).
  • Scope (singleton, prototype, etc.).
  • Dependencies (other beans or values to inject).

We will explore various ways to define beans and how Spring’s IoC container manages these definitions.


1. Ways to Define Beans in Spring

Spring provides several ways to define beans:

  • XML-based configuration.
  • Annotation-based configuration.
  • Java-based configuration.

In this chapter, we will focus on Java-based configuration, which is the most modern and recommended approach.


2. Defining Beans in Java-based Configuration

In Java-based configuration, we define beans using the @Bean annotation within a @Configuration-annotated class. Let’s take a look at a simple example:

  1. Create the Bean Class (HelloWorldService.java):
package com.example.springapplication;

public class HelloWorldService {
    
    public void sayHello() {
        System.out.println("Hello, World!");
    }
}
  1. Define the Bean in the Configuration Class (AppConfig.java):
package com.example.springapplication;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public HelloWorldService helloWorldService() {
        return new HelloWorldService();
    }
}

In this code, the @Bean annotation is used to define the helloWorldService() method as a Spring bean.


3. Bean Name

By default, Spring assigns the name of the method (helloWorldService) as the name of the bean. However, you can change the bean name by passing a name to the @Bean annotation.

@Bean(name = "myHelloWorldService")
public HelloWorldService helloWorldService() {
    return new HelloWorldService();
}

In this case, the bean will be named myHelloWorldService instead of the default helloWorldService.


4. Bean Scope

The scope of a bean determines the lifecycle and visibility of the bean in the container. Spring supports the following bean scopes:

  • Singleton (default): Only one instance of the bean is created for the entire Spring container.
  • Prototype: A new instance of the bean is created every time it is requested.
  • Request: A new bean is created for each HTTP request (used in web applications).
  • Session: A new bean is created for each HTTP session (used in web applications).
  • Global Session: A new bean is created for each global HTTP session (used in portlet-based applications).

To define the scope of a bean, we use the @Scope annotation:

@Bean
@Scope("prototype")
public HelloWorldService helloWorldService() {
    return new HelloWorldService();
}

In this example, the helloWorldService bean will be created as a prototype, meaning a new instance will be created every time it is requested.


5. Bean Dependencies

Spring allows you to inject dependencies into beans in several ways:

  1. Constructor Injection: Inject dependencies through the constructor.
  2. Setter Injection: Inject dependencies through setter methods.
  3. Field Injection: Inject dependencies directly into the fields (not recommended for production).

Let’s explore how to inject dependencies using constructor injection.

  1. Create a New Service Class (GreetingService.java):
package com.example.springapplication;

public class GreetingService {

    private String greetingMessage;

    public GreetingService(String greetingMessage) {
        this.greetingMessage = greetingMessage;
    }

    public void greet() {
        System.out.println(greetingMessage);
    }
}

Here, GreetingService has a constructor that accepts a greetingMessage.

  1. Inject the Dependency in AppConfig.java:
package com.example.springapplication;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public HelloWorldService helloWorldService() {
        return new HelloWorldService();
    }

    @Bean
    public GreetingService greetingService() {
        return new GreetingService("Hello from GreetingService!");
    }

    @Bean
    public void injectDependencies(HelloWorldService helloWorldService, GreetingService greetingService) {
        helloWorldService.sayHello();
        greetingService.greet();
    }
}

In this example, the GreetingService bean is created, and its dependency (greetingMessage) is injected via the constructor. The injectDependencies method calls both HelloWorldService and GreetingService.


6. Autowiring Beans

Spring also provides a feature called Autowiring, which allows you to automatically inject dependencies into your beans without explicitly specifying them.

You can autowire a bean by annotating a field, setter, or constructor with the @Autowired annotation.

Example:

package com.example.springapplication;

import org.springframework.beans.factory.annotation.Autowired;

public class HelloWorldService {

    @Autowired
    private GreetingService greetingService;

    public void sayHello() {
        System.out.println("Hello, World!");
        greetingService.greet();
    }
}

In this case, Spring will automatically inject the GreetingService bean into the HelloWorldService bean.

To enable autowiring, you also need to enable component scanning by adding the @ComponentScan annotation to your configuration:

@Configuration
@ComponentScan(basePackages = "com.example.springapplication")
public class AppConfig {
    // Bean definitions
}

7. Bean Initialization and Destruction

Spring allows you to define initialization and destruction methods for your beans. These methods are called after the bean is created and before it is destroyed.

You can specify initialization and destruction methods using the @PostConstruct and @PreDestroy annotations or by implementing the InitializingBean and DisposableBean interfaces.

Example using annotations:

package com.example.springapplication;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class HelloWorldService {

    @PostConstruct
    public void init() {
        System.out.println("HelloWorldService is being initialized");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("HelloWorldService is being destroyed");
    }

    public void sayHello() {
        System.out.println("Hello, World!");
    }
}

Conclusion

In this chapter, we have learned about bean definitions in Spring. We covered:

  • How to define beans using Java-based configuration.
  • How to specify bean names, scopes, and dependencies.
  • How to autowire beans and define initialization and destruction methods.

Understanding bean definitions is essential because they form the foundation of the Spring IoC container. In the next chapter, we will dive deeper into Bean Scopes and explore how to manage the lifecycle of beans in more detail.