Spring Boot prefers a Java-based configuration. Although you can use SpringApplication with XML sources, we generally recommend that the main source be a single class annotated with @Configuration. Typically, the class that defines the main method is a good candidate to be the main @Configuration.

There are many Spring configuration examples published on the Internet that use XML configuration. If possible, always try to use an equivalent Java-based configuration. Looking for Enable* annotations might be a good starting point.

Importing additional configuration classes

You don't need to put all @Configuration annotations in one class. You can use the @Import annotation to import additional configuration classes. Additionally, you can use the @ComponentScan annotation to automatically collect all Spring components, including classes with the @Configuration annotation.

Import XML configuration

If you absolutely must use XML-based configuration, we recommend starting with a class marked with the @Configuration annotation. You can then use the @ImportResource annotation to load the XML configuration files.

Auto-configuration

Auto-configuration in Spring Boot attempts to automatically configure your Spring application based on the added jar dependencies. For example, if HSQLDB is in your classpath, but you have not manually configured any beans to connect to the database, then Spring Boot will automatically configure a resident database.

You must explicitly opt-in to auto-configuration by adding the @EnableAutoConfiguration or @SpringBootApplication annotations to one of your classes with the @Configuration annotation.

Only one @SpringBootApplication or @EnableAutoConfiguration annotation should be added. We generally recommend adding a particular annotation only to the primary class annotated with @Configuration.

Gradual replacement of auto-configuration

Auto-configuration works non-aggressively. You can start defining your own configuration at any time to replace certain parts of the auto-configuration. For example, if you add your own DataSource bean, embedded database support is disabled by default.

If you want to know which autoconfiguration is currently being applied and why, run the application with the --debug option. This will enable debug logs for the selected primary logging managers and output a condition report to the console.

Disable certain auto-configuration classes

If you find that there are certain autoconfiguration classes that you don't need, you can use the exclude attribute in the @SpringBootApplication annotation to disable them, as shown in the following example:

Java
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApplication {
}
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
@SpringBootApplication(exclude = [DataSourceAutoConfiguration::class])
class MyApplication

If the class is not on the classpath, you can use the excludeName attribute of the annotation and specify the full name instead. If you prefer to use the @EnableAutoConfiguration annotation rather than the @SpringBootApplication annotation, the exclude and excludeName functions will also be available. Finally, you can control the list of autoconfiguration classes that are excluded using the spring.autoconfigure.exclude property.

You can define exceptions both at the annotation level and using a property.
Although autoconfiguration classes are public, the only aspect of a class that is considered a public API is the name of the class, which can be used to disable auto-configuration. The actual contents of these classes, such as nested configuration classes or bean methods, are for internal use only, and we do not recommend using them directly.

Spring Beans and Dependency Injection

You can use any of the standard Spring Framework tools to define your beans and their injectable dependencies. We generally recommend using constructor dependency injection to bind dependencies and the @ComponentScan annotation to find beans.

If you structure your code as suggested above (placing the application class in the top package), you can add the @ComponentScan annotation without any arguments, or use the @SpringBootApplication, which implicitly contains it. All components of your application (annotations @Component, @Service, @Repository, @Controller and others) are automatically registered like Spring beans.

The following example shows a bean marked with the @Service annotation that uses constructor dependency injection to obtain the required RiskAssessor bean:

Java
import org.springframework.stereotype.Service;
@Service
public class MyAccountService implements AccountService {
    private final RiskAssessor riskAssessor;
    public MyAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
    }
    // ...
}
Kotlin
import org.springframework.stereotype.Service
@Service
class MyAccountService(private val riskAssessor: RiskAssessor) : AccountService

If a bean has more than one constructor, then you need to mark the one you want to use Spring with the @Autowired annotation:

Java
import java.io.PrintStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyAccountService implements AccountService {
    private final RiskAssessor riskAssessor;
    private final PrintStream out;
    @Autowired
    public MyAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
        this.out = System.out;
    }
    public MyAccountService(RiskAssessor riskAssessor, PrintStream out) {
        this.riskAssessor = riskAssessor;
        this.out = out;
    }
    // ...
}
Kotlin
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.io.PrintStream
@Service
class MyAccountService : AccountService {
    private val riskAssessor: RiskAssessor
    private val out: PrintStream
    @Autowired
    constructor(riskAssessor: RiskAssessor) {
        this.riskAssessor = riskAssessor
        out = System.out
    }
    constructor(riskAssessor: RiskAssessor, out: PrintStream) {
        this.riskAssessor = riskAssessor
        this.out = out
    }
    // ...
}
Note that using constructor dependency injection allows you to mark the riskAssessor field as final, which means that it cannot be changed later.