Spring - Java Based Configuration

Spring introduced annotation-based Java configuration as a type-safe, refactor-friendly alternative to XML. A class annotated with @Configuration acts as a bean factory: methods annotated with @Bean register beans in the ApplicationContext.

Contents

@Configuration and @Bean basics

A @Configuration class is itself a Spring bean. Each @Bean method is intercepted by Spring's CGLIB proxy so that calling the method multiple times always returns the same singleton instance.

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

@Configuration
public class AppConfig {

    @Bean
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb");
        ds.setUsername("user");
        ds.setPassword("pass");
        ds.setMaximumPoolSize(10);
        return ds;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() {
        // Calling dataSource() here returns the same singleton instance
        return new JdbcTemplate(dataSource());
    }
}

Declaring bean dependencies via method parameters

You can declare the dependency as a method parameter instead of calling a sibling method directly. Spring injects the correct bean automatically.

Java
@Configuration
public class ServiceConfig {

    @Bean
    public UserRepository userRepository(DataSource dataSource) {
        return new JdbcUserRepository(dataSource);
    }

    @Bean
    public UserService userService(UserRepository userRepository) {
        return new UserServiceImpl(userRepository);
    }
}

Splitting config with @Import

Large applications can split their configuration into multiple classes and compose them with @Import.

Java
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({DataSourceConfig.class, SecurityConfig.class, CacheConfig.class})
public class RootConfig {
    // Aggregates the other configuration classes into one root context
}

Conditional beans with @Conditional

Spring Boot extends the base @Conditional with convenient shortcuts. @ConditionalOnMissingBean registers a bean only if no other bean of that type has been defined: great for providing sensible defaults.

Java
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class NotificationConfig {

    @Bean
    @ConditionalOnProperty(name = "notification.channel", havingValue = "email")
    public NotificationService emailNotificationService() {
        return new EmailNotificationService();
    }

    @Bean
    @ConditionalOnMissingBean(NotificationService.class)
    public NotificationService noOpNotificationService() {
        return message -> System.out.println("NoOp: " + message);
    }
}