A. SpringBootApplication is introduced

SpringBootApplication is a composite annotation annotated on the startup class. It is the core implementation of springBoot startup and IOC container. It is also the key logic for SpringBoot to realize automatic assembly.

Without further ado, as usual, take a look at the source code for this annotation

@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 { @AliasFor(annotation = EnableAutoConfiguration.class) Class<? >[] exclude() default {}; @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<? >[] scanBasePackageClasses() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator") Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; }Copy the code

As you can see from the source code, this annotation consists of three child annotations.

1.1. @ SpringBootConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}
Copy the code

The code for SpringBootConfiguration is relatively simple, annotated by @Configuration, and registers the boot class as a Configuration class managed by SpringBoot. This allows you to configure some common system-level configuration beans, such as configuration for external Tomcat, on the startup class.

1.2. @ EnableAutoConfiguration

@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 {}; }Copy the code
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { String[] basePackages() default {}; Class<? >[] basePackageClasses() default {}; }Copy the code

The functionality of @enableAutoConfiguration, defined in annotations, is primarily for the related autoconfiguration classes introduced by @Import.

1.3. @ ComponentScan

@ComponentScan code is longer, the main role is to scan the components and bean definitions that conform to the definition. The scanned bean and component information is loaded into the IOC container.

2. In-depth understanding of @Configuration

2.2. @ Component

In the daily business development process, the most common way to define a class as a Spring bean is no more than @Configuration/@Component/ @service /@Controller. If you click on the annotation, you will find that the @Component annotation is the source of all the beans that springBoot can use to animate a class into an IOC. Any bean that is extended based on the @Component annotation can bea Spring bean.

2.2. @ Bean

So is there any other operation besides @Component that will add a bean to IOC? The first reaction is @Bean

So what’s the difference between @bean and @Component

Quoting a paragraph of parsing (www.cnblogs.com/just-for-be…

@Component applies to classes only if our SpringBoot application has Component scanning enabled and contains annotated classes. With Component scanning, Spring will scan the entire classpath and add all @Component annotated classes to the Spring Context. The downside is that the entire class will be registered with the Spring container as a bean, if not all methods in the class need to be registered as beans. In this case, it is necessary to make sure that these methods can also be registered as beans or add a filter to the scan to filter the beans. Otherwise, Spring will fail to start successfully.

@bean is more flexible. It can be added to a method on its own, registering it with the Spring container on demand, and if you want to use a method in a third-party library, you have to register it with the Spring container using @bean. With @Component you would need to configure the Component to scan for the third party classpath and annotate it in someone else’s source code, which is obviously impractical.

2.3. @ Import

@Component and @Bean are the most frequently used scenarios in everyday work, showing that a class or method is defined as a Bean. Now, if a class is very complex, involves a lot of correlation logic, is a core configuration class. Writing a lot of configuration logic or bean loading logic in the bean would be bloated and difficult to understand. This is where the @import annotation comes in. I believe that some of the students who have read the Spring source code or have seen the open source framework are familiar with this annotation. So what exactly does this annotation do? How does it work?

@ Import role

1. Import the class in the three-party JAR package as a bean

2. Decompose complex configuration classes into unit configuration classes, which take effect and fail together with the main configuration class

The three main uses of @import include:

1, directly fill in the class array way 2, ImportSelector way [key] 3, ImportBeanDefinitionRegistrar way

Use of the @import method

package com.baiyan.demo;

public class User {
}
Copy the code
package com.baiyan.demo; import org.springframework.context.annotation.Import; import org.springframework.stereotype.Component; @Component @import (user.class) public class Test {} Print the ioc container class: com.baiyan.demo.userCopy the code

2.4. ImportSelector

ImportSelector This is an interface, used in conjunction with @import, that registers arrays returned by interface methods as IOC-managed beans

@Component
@Import(BaiyanImportSelector.class)
public class Test {
}
Copy the code
public class BaiyanImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata  importingClassMetadata) { return new String[] {BaiyanServiceA.class.getName(), BaiyanServiceB.class.getName()}; }} a print of the ioc container class can see: com. The baiyan. Demo. BaiyanServiceA com. The baiyan. Demo. BaiyanServiceBCopy the code

If you have a fixed bean definition directly, you can use the above method, but if you want to define beans dynamically with logic, it is useful to use ImportSelector. Because in its selectImports() you can implement all kinds of logic to get the Class of the bean, using the AnnotationMetadata parameter to get all kinds of information about the @import annotated Class, including its Class name, The name of the interface implemented, the name of the parent Class, other annotations added, and other additional information can help you choose the Class name that you want to define as a Spring bean. Now suppose we use @componentScan on HelloConfiguration to scan the bean definition, We expect BaiyanImportSelector to also scan the HelloService implementation classes in the Package specified by @ComponentScan and define them as beans.

2.5. ImportBeanDefinitionRegistrar

This is similar to the ImportSelector interface, except for the additional parameter BeanDefinitionRegistry

public class User implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class); beanDefinitionRegistry.registerBeanDefinition("User123455",rootBeanDefinition); }}Copy the code

Support for manual registration of beans into the IOC container

2.6. Summarize

  1. @Component: Registers the class as a bean
  2. @bean: Registers the method return value as a Bean
  3. @import ({component from container to Import}) : The container will automatically register this component with the default id of the full class name **
  4. ImportSelector: Returns an array of the class names of the component to be imported. This is especially used by springBoot
  5. ImportBeanDefinitionRegistrar: manually register beans to the container

3. In-depth understanding of @ComponentScan

The name of this annotation makes it clear that it is used for component scanning. Scan what? Is the bean definition for Spring. The annotation itself has no business meaning, but the various parameter configurations on the annotation will be used to resolve the scanned package path and excluded class definitions. See what this class does in the startup class later.

In-depth understanding of EnableAutoConfiguration

4.1. AutoConfigurationImportSelector

Click comments after we found that by introducing the @ Import AutoConfigurationImportSelector the configuration class, according to the above article into @ Import, the interpretation of this class must have a configuration class, Click in and you see that the DeferredImportSelector interface is implemented, which in turn inherits from the ImportSelector interface. DeferredImportSelector interface implementation and ImportSelector have differences, do not do, method will become a DeferredImportSelector entrance. The process method

Please refer to: blog.csdn.net/it_lihongmi…

Pay attention to check the AutoConfigurationImportSelector AutoConfigurationGroup processing of an inner class

@Override public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); }}Copy the code

The focus is on core statements

AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
      .getAutoConfigurationEntry(annotationMetadata);
Copy the code

For automatic configuration node, view the getAutoConfigurationEntry method

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (! isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }Copy the code

Focus on core statements

List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
Copy the code
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
         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;
}
Copy the code

This method is found to load the configuration file in the JAR package. What is loaded?

. Step by step into the way back to SpringFactoriesLoader loadSpringFactories method is found to load each jar package under the meta-inf/spring. Factories file within the class at the end of a heap to AutoConfiguration.

Do you see a clue, ladies and gentlemen, is it similar to EnableAutoConfiguration? Here is the subtlety of SpringBoot out of the box, and also the extension point of each framework based on SpringBoot to do three-party starter.

The above implication is: If we want to make a starter or SDK for daily business development, we can define a meta-INF /spring.factories folder in our root resource directory resourece and configure some auto-configuration classes in it so that when people reference your package, You can also register your various configuration classes in the IOC container if the package scan path is inconsistent with your bean definition

4.2. AutoConfigurationPackages. The Registrar

AutoConfigurationPackages. The Registrar is * * * @ AutoConfigurationPackage annotations on the Import in the configuration of the class. Again, DeterminableImports** is inherited.

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])); } @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImports(metadata)); }}Copy the code

Take a look at the PackageImports class

PackageImports(AnnotationMetadata metadata) { AnnotationAttributes attributes = AnnotationAttributes .fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false)); List<String> packageNames = new ArrayList<>(); for (String basePackage : attributes.getStringArray("basePackages")) { packageNames.add(basePackage); } for (Class<? > basePackageClass : attributes.getClassArray("basePackageClasses")) { packageNames.add(basePackageClass.getPackage().getName()); } if (packageNames.isEmpty()) { packageNames.add(ClassUtils.getPackageName(metadata.getClassName())); } this.packageNames = Collections.unmodifiableList(packageNames); }Copy the code

Does that make sense? @componentScan (basePackages) @componentScan (basePackages)

If not specified, the default Spring framework implementation will scan from the package in which @ComponentScan is declared. By default, this is not specified, so SpringBoot boot classes are best placed under the root package

Scan the package path through AutoConfigurationPackages. The Registrar. RegisterBeanDefinitions register method into the register this class, The Registrar class scans the directories and subpackages of the main configuration class and imports the corresponding annotated bean components into the SpringBoot creation container using the determineImports method.

4.3. Summarize

The overview EnableAutoConfiguration annotations, through AutoConfigurationImportSelector this class loading to all three parties beans in the jar, Through AutoConfigurationPackages. The Registrar class – this class is loaded into the package under the scanning path of bean definitions

5. Automatic configuration of SpringbootApplication

  1. The SpringBoot application is started.
  2. @springBootApplication works.
  3. @ EnableAutoConfiguration.
  4. @ AutoConfigurationPackage: Main function is to @ Import (AutoConfigurationPackages. The Registrar. The class), it will through the Registrar class imported into the container, The Registrar class is used to scan the basePackages attribute defined in the @ComponentScan annotation to get the root scan path of the bean component. The Registrar class is used to scan the root scan path of the bean component. And import the corresponding components into the container that SpringBoot creates and manages.
  5. @ Import (AutoConfigurationImportSelector. Class) : It will by AutoConfigurationImportSelector class imported into the container, Through SpringFactoriesLoader. SpringFactoriesLoader loaded into jars in the meta-inf/spring. Factories file defined in the automatic configuration class, will be a series of components loaded into the IOC container

6. References

Blog.csdn.net/elim168/art…

www.cnblogs.com/yichunguo/p…

Juejin. Cn/post / 684490…

My.oschina.net/u/3872757/b…

7. Contact me

Nailing: louyanfeng25

WeChat: baiyan_lou

Code word is not easy to point 👍, thank you for the audience master ~