SpringBootApplication (@springBootApplication); SpringBootApplication (@springBootApplication); For example:

@SpringBootApplication
public class SpringbootTestApplication {

    public static void main(String[] args) { SpringApplication.run(SpringbootTestApplication.class, args); }}Copy the code
  • So how does the @SpringBootApplication annotation work?
  • What is @Component derived annotation?

1. Understand @SpringBootApplication semantics

To quote: @SpringBootApplication is used to enable @EnableAutoConfiguration, @ComponentScan, and @Configuration. @enableAutoConfiguration is responsible for activating the SpringBoot auto-assembly mechanism, @ComponentScan activates the @Component scan, and the @Configuration declaration is labeled as a Configuration class. The official documentation goes on to tell developers that the @SpringBootApplication annotation is equivalent to the @Configuration, @EnableAutoConfiguraion, and @ComponentScan annotations, all of which use default properties. We modify the above code like this:

//@SpringBootApplication
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class SpringbootTestApplication {

    public static void main(String[] args) { SpringApplication.run(SpringbootTestApplication.class, args); }}Copy the code

We got it up and running, looked at the logs, and yes, everything worked as you’d expect.

Springboot2.x’s @SpringBootApplication source code looks something like this:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    ....
}
Copy the code

So the question is, right? Is @springBootSPplication inconsistent with the @enableAutoConfiguration, @ComponentScan, and @Configuration annotations?

So we can see from the above analysis, @springBootApplication is equivalent to @SpringBootConfiguration, @ComponentScan and @EnableAutoConfiguration. But @ ComponentScan not use the default values, but add to exclude the TypeFilter implementation: TypeExcludeFilter and AutoConfigurationExcludeFilter. The former, introduced by Springboot1.4, is used to find TypeExcludeFilter beans registered in the BeanFactory as proxy execution objects:

public class TypeExcludeFilter implements TypeFilter.BeanFactoryAware {...@Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        if (this.beanFactory instanceof ListableBeanFactory && this.getClass() == TypeExcludeFilter.class) {
            Collection<TypeExcludeFilter> delegates = ((ListableBeanFactory)this.beanFactory).getBeansOfType(TypeExcludeFilter.class).values();
            Iterator var4 = delegates.iterator();

            while(var4.hasNext()) {
                TypeExcludeFilter delegate = (TypeExcludeFilter)var4.next();
                if (delegate.match(metadataReader, metadataReaderFactory)) {
                    return true; }}}return false; }... }Copy the code

The latter is supported by SpringBoot1.5 and is used to exclude other classes that are annotated @configuration and @enableautoconfiguration:

public class AutoConfigurationExcludeFilter implements TypeFilter.BeanClassLoaderAware {...@Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        return this.isConfiguration(metadataReader) && this.isAutoConfiguration(metadataReader);
    }

    private boolean isConfiguration(MetadataReader metadataReader) {
        return metadataReader.getAnnotationMetadata().isAnnotated(Configuration.class.getName());
    }

    private boolean isAutoConfiguration(MetadataReader metadataReader) {
        return this.getAutoConfigurations().contains(metadataReader.getClassMetadata().getClassName());
    }

    protected List<String> getAutoConfigurations(a) {
        if (this.autoConfigurations == null) {
            this.autoConfigurations = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, this.beanClassLoader);
        }

        return this.autoConfigurations; }}Copy the code

Compare this with the @SpringBootApplication declaration in SpringBoot1.3.8:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configurationand@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
    ....
}
Copy the code

Thus, the implementation of SpringBoot1.3.8 is the same as described in the official documentation. Although @SpringBootApplication since SpringBoot1.4 does not normally behave differently from the documentation, the documentation has not been updated or explained in detail.

2. @Component

But as we know, starting with SpringBoot1.4, the @SpringBootApplication annotation no longer annotates @Configuration, but @SpringBootConfiguration, and the two behave the same at runtime. This kind of inheritance between objects is called “multi-level @Component ‘generativity'”, hahaha, and this capability also allows us to extend it, isn’t it cool? Take a look at the @Configuration annotation, which actually marks the @Component annotation:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    ...
}
Copy the code

So we know that @Configuration is actually a generative annotation of @Component, in the same way that @SpringBootConfiguration annotates @Configuration:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
Copy the code

Therefore, the relationship among the three is:

  • @component
    • @Configuration
      • @SpringBootConfiguration

We know that @CompoentScan only scans classes with @Component annotations and registers them as beans, but @SpringBootConfiguration is recognized by @CompoentScan because it is a multi-level @Component “derived” annotation. But we know that @compoentScan belongs to the Spring Framework, and @SpringBootConfiguration comes from SpringBoot, So what is the mechanism that allows @CompoentScan to recognize @SpringBootConfiguration annotations? This mechanism is the aforementioned “multi-level @Component ‘generativity'”.

3, summary

SpringBoot is annotated @enableAutoConfiguration to find, filter, and load the required Configuration, @ComponentScan to scan our custom bean, @SpringBootConfiguration causes the class annotated by @SpringBootApplication to be declared as an annotation class, So @SpringBootApplication is equivalent to using @EnableAutoConfiguration, @ComponentScan, @SpringBootConfiguration at the same time.