Close

Spring - Java-based configuration: Using @Configuration

[Last Updated: Nov 26, 2020]

Our Spring kick start example briefly demonstrated JavaConfig method of configuration. Here we will explore the details.


@Configuration

This is a class level annotation. The class annotated with this annotation may consist of methods annotated with @Bean. Spring container invokes such methods to get the object instances, so that the container can register them as beans.

package spring.example

   @Configuration
   public class MyAppConfig {
     @Bean
     public SomeBean someBean() {
    // instantiate, configure and return bean instance ...
     return new SomeBeanImpl();
     }
   }

The equivalent XML configuration will look like this:

<bean name="someBean" class="spring.example.SomeBeanImpl"/>



@Configuration classes are in fact nothing but spring managed factories to create and register bean instances.



Bootstrapping Spring Container

In Java-based spring configuration, the container can be bootstrapped using either AnnotationConfigApplicationContext or for web application: AnnotationConfigWebApplicationContext.

new AnnotationConfigApplicationContext(MyAppConfig.class);

We can also specify the qualified package name containing @Configuration annotated classes:

new AnnotationConfigApplicationContext("spring.example");

By using above overloaded variant, we can have multiple configuration classes in a single package



@Configuration Classes are Subclassed by CGLIB


All @Configuration classes are subclassed at startup-time with CGLIB. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance.


CGLIB proxying is the means by which invoking methods or fields within @Bean methods in @Configuration classes creates bean metadata references to collaborating objects; such methods are not invoked with normal Java semantics but rather go through the container in order to provide the usual lifecycle management and proxying of Spring beans even when referring to other beans via programmatic calls to @Bean methods.

That's why all methods will return the same instance at multiple calls (if they are singleton scoped which is the default scope).

There has to be @Configuration annotation, otherwise this runtime manipulation won't be done.


@ComponentScan

So far we saw JavaConfig using factory methods (annotated with @Bean) to provide bean implementation. Using this approach, we have to create the bean implementation instances ourselves. Instead of this factory approach, we can have spring to scan the provided packages and create all implementation automatically and then inject the dependencies. We can do that by using @ComponentScan along with @Configuration. We still don't have to use any XML. Please see an example here



Examples

Using @Configuration annotation

package com.logicbig.example;

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

@Configuration
public class ConfigExample {
    private int counter;

    @Bean
    public Greeter greeterBean() {
        return new Greeter();
    }

    public static void main(String... strings) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(ConfigExample.class);
        Greeter greeter = context.getBean(Greeter.class);
        greeter.sayHi("Joe");
    }

    public static class Greeter {
        public void sayHi(String name) {
            System.out.println("Hi there, " + name);
        }

    }
}

Output

Hi there, Joe

Demo for CGLIB manipulation of @Configuration classes

@Configuration classes are subclassed by CGLIB, poxying the @Bean methods to control their lifecycles. The bean instances created by these proxy methods are cached. That's why all bean methods will return the same instance if called multiple times.

package com.logicbig.example;

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

@Configuration
public class DemoCGLIB {
  private int counter;

  @Bean
  public String something(){
      System.out.println("method invoked");
      return String.valueOf(++counter);
  }

      public static void main(String... strings) {
          AnnotationConfigApplicationContext context =
                  new AnnotationConfigApplicationContext(DemoCGLIB.class);
          DemoCGLIB bean = context.getBean(DemoCGLIB.class);
          System.out.println(bean.something());
          System.out.println(bean.something());
      }
}

Output

method invoked
1
1

Let's remove @Bean annotation from something() method and see the difference:

package com.logicbig.example;

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

@Configuration
public class WithoutCGLIB {
  private int counter;

  public String something(){
      System.out.println("method invoked");
      return String.valueOf(++counter);
  }

      public static void main(String... strings) {
          AnnotationConfigApplicationContext context =
                  new AnnotationConfigApplicationContext(WithoutCGLIB.class);
          WithoutCGLIB bean = context.getBean(WithoutCGLIB.class);
          System.out.println(bean.something());
          System.out.println(bean.something());
      }
}

Output

method invoked
1
method invoked
2

Example Project

Dependencies and Technologies Used:

  • spring-context 4.3.2.RELEASE: Spring Context.
  • JDK 1.8
  • Maven 3.6.3

@Configuration Example Select All Download
  • spring-java-based-configuration
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • ConfigExample.java

    See Also