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