Close

Spring - Java-based configuration: Using @Configuration

[Updated: Dec 19, 2016, Created: Feb 5, 2016]

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



Using multiple Configuration Classes

To separate the concerns or to achieve modularization, we can define multiple configuration classes. During container initialization we can use one of the following overloaded constructors.

By passing multiple configs to AnnotationConfigApplicationContext. For example

 new AnnotationConfigApplicationContext( AppConfig.class, DataSourceConfig.class )

By passing one or multiple package names for the container to scan the classes having @Configuration. For example

 new AnnotationConfigApplicationContext("example.spring.app","example.spring.datasource")

DI in Configuration Classes

The configuration classes themselves are registered as beans to the Spring container. That means, we can do whatever we do with a normal spring bean. For example we can use @Autowire to have Spring to perform DI in them. In the following example we are going to inject a configuration class to another one.

package spring.example.di;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation. AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class AppConfig {
    @Autowired
    private DataSourceConfig dataSourceConfig;

    @Bean
    Client clientBean() {
        return new Client(dataSourceConfig.dataSourceBean());
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
          new AnnotationConfigApplicationContext(AppConfig.class, DataSourceConfig.class);
        context.getBean(Client.class).showData();
    }
}

@Configuration
class DataSourceConfig {

    @Bean
    DataSourceBean dataSourceBean() {
        return new DataSourceBean();
    }
}

class Client {
    private DataSourceBean dataSourceBean;

    Client(DataSourceBean dataSourceBean){
        this.dataSourceBean = dataSourceBean;
    }

    public void showData() {
        System.out.println(dataSourceBean.getData());
    }
}

class DataSourceBean {

    public String getData() {
        return "some data";
    }
}


We can also inject DataSourceBean directly to AppConfig, rather than injecting DataSourceConfig class:
package spring.example.di;

import org.springframework.beans.factory.annotation. Autowired;
import org.springframework.context.annotation .AnnotationConfigApplicationContext;
import org.springframework.context.annotation. Bean;
import org.springframework.context.annotation. Configuration;


@Configuration
public class AppConfig {
    @Autowired
    private DataSourceBean dataSourceBean;

    @Bean
    Client clientBean() {
        return new Client(dataSourceBean);
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                  new AnnotationConfigApplicationContext(AppConfig.class, DataSourceConfig.class);
        context.getBean(Client.class).showData();
    }
}

@Configuration
class DataSourceConfig {

    @Bean
    DataSourceBean dataSourceBean() {
        return new DataSourceBean();
    }
}

class Client {
    private DataSourceBean dataSourceBean;

    Client(DataSourceBean dataSourceBean){
        this.dataSourceBean = dataSourceBean;
    }

    public void showData() {
        System.out.println(dataSourceBean.getData());
    }
}

class DataSourceBean {

    public String getData() {
        return "some data";
    }
}


Constructor-base DI in the configuration class

Starting from Spring 4.3, configuration classes also support constructor DI, please see an example here to see in what kind of scenarios we should use that feature.

@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.

Run the following code, you will see the same output both times. Also try it without @Configuration and see the difference.

@Configuration
public class SpringConfig {

    @Bean
    public String something(){
        return new String(System.nanoTime());
    }

        public static void main(String... strings) {
            AnnotationConfigApplicationContext context =
                    new AnnotationConfigApplicationContext(SpringConfig.class);
            System.out.println("Spring container started and is ready");
            SpringConfig bean = context.getBean(SpringConfig.class);
            System.out.println(bean.something());
            System.out.println(bean.something());
        }
}

Notice we retrieved the SpringConfig instance as bean, that's because it's also registered as a bean.


@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

See Also