Talk to the @SpringBootApplication annotations for Springboot startup

A few days ago we learned how to create a springboot project. Today we talk about how it runs and why we don’t need to write heavy configuration

@SpringBootApplication

First, let’s take a look at this annotation. It is used to mark in the main program, indicating that it is a springboot project

@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 {
}< /pre>

After clicking into the @SpringBootApplication annotation, we will focus on the last three annotations

< span>@ComponentScan (Package Scan)
  • component is a component, scan is a scan, so the meaning of this annotation is to scan the component,

  • componentScan is to scan all the packages under the marked class The components that need to be injected, inject them, here he is reflected in @SpringBootApplication, so this annotation will automatically inject all the components in the package where the main program is located

  • In the ssm project, we needed to configure our package scanning

    < /li>
 
package="com.xxx">

< h5 class="md-end-block md-he ading">@EnableAutoConfiguration (enable auto-assembly)

@Target({ElementType. TYPE})

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.
class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY
= "spring.boot.enableautoconfiguration";
?
Class
[] exclude() default {};
?
String[] excludeName()
default {};
}

Here we focus on two annotations

1. @AutoConfigurationPackage

 
 @Target({ElementType.TYPE} )

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.
class})
public @interface AutoConfigurationPackage {
}

In this comment, Mainly to get the components under the package where our annotations are located to register

 
 static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

Registrar() {
}
?
//metadata is the meta information where our annotations are located
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//Look here for all the components under the package where we annotate Sign up
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName( ));
}
?
public Set determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}

register< /strong>Method: Use AutoConfigurationPackages to register the components under the package

 
 private  static final String BEAN = AutoConfigurationPackages.class.getName();

?
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
//First determine whether the entire BEAN is registered
if (registry.containsBeanDefinition(BEAN)) {
//Get bean definition
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
//Get constructor parameter values ​​through bean
ConstructorArgumentValues ​​constructorArguments = beanDefinition.getConstructorArgumentValues();
//Add parameter values,
constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
}
else {
//Create a new bean definition
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
//Set the type of bean to AutoConfigurationPackages type
beanDefinition.setBeanClass(AutoConfigurationPackages.BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(
0, packageNames);
beanDefinition.setRole(
2);
//Registration of beans
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}

二、@Import( {AutoConfigurationImportSelector.class})

Assemble our automatic configuration import selector

We click into this class, below there is a method getAutoConfigurationEntry to get the entrance of automatic assembly,

 
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {

if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
else {
AnnotationAttributes attributes
= this.getAttributes(annotationMetadata);
List
configurations = this.getCandidateConfigurations(annotationMetadata, attributes) ;
configurations
= this.removeDuplicates(configurations);
Set
exclusions = this.getExclusions(annotationMetadata, attributes) ;
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations
= this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}

This method is mainly Get a collection of configurations. Here we click into the getCandidateConfigurations method

 
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

List
configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}

Let’s look at him first Red error message: No automatic configuration class was found in META-INF/spring.factories. According to his error message, we can conclude that he obtained our automatic configuration information from META-INF/spring.factories

< span class="md-line md-end-block">We can also click into this loadFactoryNamesthis method span>

 public  static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {

String factoryClassName
= factoryClass.getName();
//The following method loadSpringFactories is called
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList() );
}
?
private static Map > loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap
result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
}
else {
try {
//According to the class loader to obtain the information in the configuration file< /span>
Enumeration urls = classLoader != null? classLoader.getResources("META-INF/spring.factories"): ClassLoader.getSystemResources( "META-INF/spring.factories");
LinkedMultiValueMap result
= new LinkedMultiValueMap();
?
while(urls.hasMoreElements()) {
URL url
= (URL)urls.nextElement();
UrlResource resource
= new UrlResource(url);
//The configuration information is transformed into properties after many conversions span>
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6
= properties.entrySet().iterator();
//Get all configuration information in a loop
while(var6.hasNext()) {
Entry
entry = (Entry)var6.next();
String factoryClassName
= ((String)entry.getKey()).trim();
String[] var9
= StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
?
for(int var11 = 0; var11 var11) {
String factoryName
= var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
?
cache.put(classLoader, result);
return result;
}
catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}

And this configuration file is in Where?

Find our spring-boot-autoconfigure in the External Libraries of our project Medium

share picture

share pictureThis completes some of our default automatic assembly

@SpringBootConfiguration

This method is relatively simple, indicating that this is a configuration class

< div class="code">

 @Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}


This is the end of our three comments. If you have any questions, please point out the big guys. Thank you.
span>

Have struggles, have failed, but still get up and continue fighting

 @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 {
}< /pre>

package="com.xxx">

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.
class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY
= "spring.boot.enableautoconfiguration";
?
Class
[] exclude() default {};
?
String[] excludeName()
default {};
}

 @Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.
class})
public @interface AutoConfigurationPackage {
}

 static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

Registrar() {
}
?
//metadata is the meta information where our annotations are located
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//Look here for all the components under the package where we annotate Sign up
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName( ));
}
?
public Set determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}

 private static final String BEAN = AutoConfigurationPackages.class.getName();

?
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
//First determine whether the entire BEAN is registered
if (registry.containsBeanDefinition(BEAN)) {
//Get bean definition
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
//Get constructor parameter values ​​through bean
ConstructorArgumentValues ​​constructorArguments = beanDefinition.getConstructorArgumentValues();
//Add parameter values,
constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
}
else {
//Create a new bean definition
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
//Set the type of bean to AutoConfigurationPackages type
beanDefinition.setBeanClass(AutoConfigurationPackages.BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(
0, packageNames);
beanDefinition.setRole(
2);
//Registration of beans
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {

if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
else {
AnnotationAttributes attributes
= this.getAttributes(annotationMetadata);
List
configurations = this.getCandidateConfigurations(annotationMetadata, attributes) ;
configurations
= this.removeDuplicates(configurations);
Set
exclusions = this.getExclusions(annotationMetadata, attributes) ;
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations
= this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}

protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

List
configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}

 public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {

String factoryClassName
= factoryClass.getName();
//The following method loadSpringFactories is called
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList() );
}
?
private static Map > loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap
result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
}
else {
try {
//根据类加载器去获取配置文件里的信息
Enumeration urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result
= new LinkedMultiValueMap();
?
while(urls.hasMoreElements()) {
URL url
= (URL)urls.nextElement();
UrlResource resource
= new UrlResource(url);
//配置信息经过多次转换最终成为properties形式
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6
= properties.entrySet().iterator();
//循环获取所有的配置信息
while(var6.hasNext()) {
Entry
entry = (Entry)var6.next();
String factoryClassName
= ((String)entry.getKey()).trim();
String[] var9
= StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
?
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName
= var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
?
cache.put(classLoader, result);
return result;
}
catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}

  @Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

Leave a Comment

Your email address will not be published.