In this tutorial, we will discuss the fundamental concept of Spring that we must know, which is Spring Context, it is the basic knowledge that we need to understand in the Spring ecosystem. Spilca Laurentui said in his book:

Imagine the context as a place in the memory of your app in which we add all the object instances that we want the framework to manage. By default, Spring doesn’t know any of the objects you define in your application. To enable Spring to see your objects, you need to add them to the context.

Spilca, Laurentiu. Spring Start Here: Learn what you need and learn it well (p. 22). Manning. Kindle Edition.

So, the place in memory of the context or ApplicationContext interface I assume as per Spring doc is the IoC container, by adding the object instance or bean into the context, Spring can see and manage the bean in our application.

There are 3 ways to add beans into the Spring context, in this part we will talk about @Bean and Stereotype annotations (using programmatically will talk later in the next part).

Note: We will use the Lombok Java library to auto-generate getter, setter, etc (e.g. @Data) in the POJO class.

  1. Using @Bean annotation

    • Create a class (e.g. Car) to be added into the Spring context.

      @Data
      public class Car {
          private String brand;
      }
      
    • Define a configuration class of your application.

      • Annotated the class with @Configuration

      • Create a method that returns the object instance.

      • Annotate the method with @Bean annotation.

        @Configuration
        public class AppConfig {
            @Bean
            Car car() {
                var car = new Car();
                car.setBrand("Honda");
                return car;
            }
        }
        
    • Verify the bean in the context.

      • Create an instance of the Spring context, in this discussion we use the AnnotationConfigApplicationContext class for simple testing.

        var context = new AnnotationConfigApplicationContext(AppConfig.class);
        
      • Get a reference of a bean from the Spring context.

        Car car = context.getBean(Car.class);
        
      • Verify the result.

        System.out.println("Car brand : " + car.getBrand());
        
    • Output

      Car brand : Honda
           
      Process finished with exit code 0
      
  2. Using Stereotype annotation

    In this example, we will use one of some Stereotype annotations in Spring, it is @Component and for other Stereotype annotation types, you can refer here.

    • Annotate the class (in this case Animal class) with @Component annotation.

      @Component
      @Data
      public class Pet {
          private String name;
      }
      
    • Using @ComponentScan annotation in the configuration class.

      @Configuration
      @ComponentScan(basePackages = "id.vimona.blog.springcontext.domain")
      public class AppConfig {
      ....
      }
      

      Note: the Animal class is under the domain package.

    • Verify the bean in the context.

      Pet pet = context.getBean(Pet.class);
      
    • Verify the result.

      System.out.println("Pet name : " + pet.getName());
      
    • Output

      Pet name : null
           
      Process finished with exit code 0
      

      Note: the value is null cause we did not assign any value to the sound. You can set the value with @PostConstruct annotation after the instance creation.

      @Component
      @Data
      public class Pet {
          private String name;
           
          @PostConstruct
          public void init() {
              this.name = "Woody";
          }
      }
      
    • Now, re-verify the output

      Pet name : Woody
           
      Process finished with exit code 0
      

    In order to access the bean in your application, besides using AnnotationConfig-ApplicationContext class, another way we can use the @Autowired annotation to inject the bean into the field of the class, following the next snippet code:

    @SpringBootApplication
    public class SpringContextApplication implements ApplicationRunner {
       
     @Autowired
     private Car car;
       
     @Autowired
     private Pet pet;
       
     public static void main(String[] args) {
         SpringApplication.run(SpringContextApplication.class, args);
     }
       
     @Override
     public void run(ApplicationArguments args) throws Exception {
         System.out.println("Car brand : " + car.getBrand());
         System.out.println("Pet name : " + pet.getName());
     }
    }
    

    Output

    2022-03-15 22:42:26.616  INFO 1170 --- [           main] i.v.b.s.SpringContextApplication         : Starting SpringContextApplication using Java 11.0.8 on Taufiks-MBP with PID 1170 (/Users/mohdtaufik/Workspaces/blogs/sample-code-vimona/spring/spring-context/target/classes started by mohdtaufik in /Users/mohdtaufik/Workspaces/blogs/sample-code-vimona/spring/spring-context)
    2022-03-15 22:42:26.621  INFO 1170 --- [           main] i.v.b.s.SpringContextApplication         : No active profile set, falling back to 1 default profile: "default"
    2022-03-15 22:42:27.481  INFO 1170 --- [           main] i.v.b.s.SpringContextApplication         : Started SpringContextApplication in 1.605 seconds (JVM running for 2.301)
    Car brand : Honda
    Pet name : Woody
       
    Process finished with exit code 0
    

    Edit (26/03/2022) - Since the sample use Spring Boot, we can take out @ComponentScan annotation from the config class, a detailed explanation can be referred to this post.

Github repository

Reference: