An overview of the

In the previous post (Introduction to SpringBoot and Quick Setup), we briefly introduced what SpringBoot is and how to use it, but we did not introduce the basic principles of SpringBoot. In this post, we focus on how SpringBoot is automatically configured.


Dependency management

There is only one core dependency in our POM file:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.4</version>
    <relativePath/>
</parent>
Copy the code

Its parent project dependencies specify version information for all dependencies:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.4.4</version>
</parent>
Copy the code

As a result, we found that the SpringBoot framework declared the version numbers of almost all dependencies commonly used in development, regardless of the version numbers, and implemented an automatic version arbitration mechanism, and of course we could replace the default version of dependencies if we wanted.


The core annotation @SpringBootApplication

@SpringBootApplication
public class BootApplication {

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

We found a strange annotation @springBootApplication in the bootstrap class above. What does this annotation mean? Let’s click inside and have a look.

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
Copy the code

In fact, @SpringBootApplication is a combination of the above three annotations. We should understand the three annotations clearly, and explain them one by one:


@SpringBootConfiguration

@Configuration
public @interface SpringBootConfiguration {
Copy the code

@Configuration is no stranger to registering additional beans in context or importing other Configuration classes. @SpringBootConfiguration actually means that the current class is a Configuration class.


@EnableAutoConfiguration

The purpose of EnableAutoConfiguration is to enable the automatic configuration mechanism of SpringBoot.

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
Copy the code

AutoConfigurationPackage Specifies the default package rules

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
Copy the code

The AutoConfigurationPackage annotation is used to manage the package of the class to which it was added as an AutoConfigurationPackage. That is, when the SpringBoot application starts, the package in which the startup class is located will be automatically configured by default. It is then injected into the IOC container using the @import annotation. This way, the path can be retrieved in the container.

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(newPackageImports(metadata)); }}Copy the code

Focus on the registerBeanDefinitions method.

The second argument to the method is set using the new PackageImport(metadata).getPackagename () method.

Take a look at the PackageImport constructor method.

PackageImports(AnnotationMetadata metadata) {
   AnnotationAttributes attributes = AnnotationAttributes
         .fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false));
   List<String> packageNames = new ArrayList<>(Arrays.asList(attributes.getStringArray("basePackages")));
   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

ClassUtils. GetPackageName (metadata) getClassName ()) to get mark @ AutoConfigurationPackage annotations of the fully qualified name of the class.

Finally, use the Registrar to import the components into the container and bring in all the components under the specified package.

2, @ Import (AutoConfigurationImportSelector. Class)

Use Import to automatically Import all Bean definitions that meet the auto-configuration criteria and load them into the IOC container

@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

1, using getAutoConfigurationEntry (annotationMetadata); Give container bulk import some component 2, call List configurations = getCandidateConfigurations (annotationMetadata, <String, List> loadSpringFactories(@nullable ClassLoader ClassLoader); Load a file from the meta-INF /spring.factories location. [spring-boot-autoconfigure-2.4.4.release.jar] [spring-INF /spring.factories] [spring-boot-autoconfigure-2.4.4.release.jar] [spring-INF /spring.factories] [spring-boot-autoconfigure-2.4.4.release.jar] [spring-INF /spring.factories] [spring-boot-autoconfigure-2.4.4.release.jar] [spring-INF /spring.factories

Spring-boot-autoconfigure-2.4.4.release.jar/meta-INF/spring.Factories (spring-boots-autoconfigure-2.4.4.release.jar/meta-INF/spring.Factories)

All automatic configurations for 130 scenarios are loaded by default when SpringBoot starts. XxxxAutoConfiguration is configured on demand according to Conditional assembly rules (@Conditional).

Summary:

SpringBoot enables three features for our application: automatic configuration, component scanning, and the ability to define additional configurations on “application classes.”


@ComponentScan

@Component enables scanning on the software package in which the application resides, specifying which Spring annotations to scan.


ServletWebServerFactoryAutoConfiguration, for example

In 130 a scenario we are familiar with two components, ServletWebServerFactoryAutoConfiguration and WebMvcAutoConfiguration, ServletWebServerFactoryAutoConfiguration, for example, we see the webServer how SpringBoot automatic assembly.

In annotations, we see a large number of annotations beginning with @Conditional assembly, that is, Conditional assembly. If the conditions specified in Conditional assembly are met, component injection is performed. @EnableConfigurationProperties(ServerProperties.class)+@ConfigurationProperties(prefix = “server”, IgnoreUnknownFields = true), reads the properties we wrote in the configuration file and encapsulates them in javabeans for ready use.

At this point our Tomcat container has been injected into the IOC container as a Bean.


How do I disable a particular auto-configuration class

If you find that specific auto-configuration classes are not required in your application, you can disable them using the exclude attribute @SpringBootApplication, as shown in the following example:

import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.jdbc.*;

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
//@SpringBootApplication(excludeName = {"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"})
public class MyApplication {}Copy the code

If the class is not in the classpath, you can use the excludeName annotated property and specify the fully qualified name (full class name string). Define exclusions, that is, which annotation level can be used or can be defined using properties.


conclusion

  • SpringBoot preloads all the auto-configuration classes in meta-INF/Spring. factories, xxxxxAutoConfiguration

  • Each autoconfiguration class takes effect according to the conditions and is bound to the values specified in the configuration file by default. XxxxProperties. XxxProperties is bound to the configuration file

  • A valid configuration class assembles many components into the container, and as long as the container has these components, it has these functions

  • Customized configuration

    • The user replaces the underlying component directly with the @bean itself
    • The user can modify the configuration file based on what value the component is fetching.

EnableAutoConfiguration –> scan xxxxxAutoConfiguration –> assemble components according to Conditional @conditional. –> load attribute values according to xxxxProperties —-> application.properties


Author: Program Monkey Xiao Liang

Blogger writing is not easy, add a follow

Ask for attention, ask for praise, add a attention not to get lost, thank you

“Like” is the biggest encouragement for me