Analysis of Spring Boot Autoconfiguration Principle for Springboot Series

Articles have been included in Github.com/niumoo/JavaNotes Welcome to Star and Instructions.
Welcome to my attention Public Number , articles are updated weekly.

Note: This Spring Boot series of articles is based on Spring Boot version v2.1.1.RELEASE for learning analysis, which may vary slightly from version to version.

Preface

About what a profile can configure, in The official Spring Boot website Complete configuration examples and explanations have been provided.

It can be said that one of the essence of Spring Boot is auto-configuration, which saves a lot of configuration time for development and can be integrated into business logic development more quickly. How does auto-configuration work?

<!-- more -->

1. @SpringBootApplication

Follow the comment @SpringBootApplication for the Spring Boot startup class for source tracking to find out how automatic configuration works.

@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 {

@EnableAutoConfiguration turns on automatic configuration.

@ComponentScan turns on annotation scanning

As we can see from SpringBootApplication, this is a simple annotated configuration that includes a series of functions such as automatic configuration, configuration classes, package scanning, and so on.

2. @EnableAutoConfiguration

Continue tracking and look at the @EnableAutoConfiguration source, where @Import is more important, and imports a class that translates into a selector called AutoConfiguration.This class is actually an auto-configured load selector.

@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 {};
}

Continue tracking AutoConfiguRationImportSelector.classAn important method in this class, getCandidateConfigurations, is the auto-configuration class used to load the Spring Boot configuration.

GetAutoConfiguration Entry filters out valid autoconfiguration classes.

protected AutoConfigurationEntry getAutoConfigurationEntry(
			AutoConfigurationMetadata autoConfigurationMetadata,
			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 = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}	

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;
	}

The following figure is the result of filtering in DEBUG mode because I only added web modules, so only web-related autoconfigurations are available.

3. xxxAutoConfiguration and xxxProperties

In debug above, we see the auto-configuration loaded successfully. At present, we only see the configuration class, but we have not found the auto-configuration value yet. Select any AutoConfiguration to view the source code.

ServletWebServerFactoryAutoConfiguration is selected here.

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
//Determine if the current project has this class
//CharacterEncoding Filter; Filter for scrambling resolution in SpringMVC;
@ConditionalOnClass(ServletRequest.class)
//Spring Bottom @Conditional Annotation (Spring Annotation Version), depending on the conditions, if
//If the specified condition is met, the configuration within the entire configuration class will take effect; determine if the current application is a web application, and if so, the current configuration class will take effect
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

Note that @EnableConfigurationProperties(ServerProperties.class). He means to start the specified class ConfigurationProperties function; binds the corresponding values in the configuration file to ServerProperties; and ServerProperties are added to the IOC container.

Take another look at ServerProperties.

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

	/**
	 * Server HTTP port.
	 */
	private Integer port;

Obviously, this uses the properties at the beginning of the server in the Configuration Properties binding property mapping file.Combined with default configuration

# Path spring-boot-autoconfigure-2.1.1.RELEASE.jar
# /META-INF/spring-configuration-metadata.json

    {
      "name": "server.port",
      "type": "java.lang.Integer",
      "description": "Server HTTP port.",
      "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties",
      "defaultValue": 8080
    }

Automatic configuration is achieved.

4. Summary of Automatic Configuration

  1. SpringBoot starts with the main configuration class loaded and the auto-configuration feature @EnableAutoConfiguration turned on.
  2. @EnableAutoConfiguration Imports META-INF/Spring.factoriesAutomatic configuration class defined in.
  3. Filter valid auto-configuration classes.
  4. Each auto-configuration class combines the correspondingXxxProperties.javaRead the configuration file for automatic configuration.

5. Configuration Class

Through automatic configuration, we find that we have saved a lot of configuration file writing, so do we need to write XML when we customize the configuration?Although Spring boot can be configured using the SpringApplicationXML file, it is often replaced by the @Configuration class, which is also officially recommended.

5.1 XML Configuration

Define helloService Bean.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="helloService" class="net.codingme.boot.service.HelloService"></bean>

</beans>

Configuration is introduced.

@ImportResource(value = "classpath:spring-service.xml")
@SpringBootApplication
public class BootApplication {

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

5.2 Annotation Configuration

This is equivalent to and officially recommended for the XML configuration above.The @Configuration annotated class (to be scanned in the package path) is scanned.

/**
 * <p>
 * Configuration class, equivalent to the configuration of xml-> beans in traditional Spring development
 *
 * @Author niujinpeng
 * @Date 2018/12/7 0:04
 */
@Configuration
public class ServiceConfig {

    /**
     * The ID added to the container by default is the method name (helloService)
     *
     * @return
     */
    @Bean
    public HelloService helloService() {
        return new HelloService();
    }
}

6. Appendix

@Conditional Extended Comment Role (determine whether the current specified condition is met)
@ConditionalOnJava Does the java version of the system meet the requirements
@ConditionalOnBean The specified Bean exists in the container;
@ConditionalOnMissingBean The specified Bean does not exist in the container;
@ConditionalOnExpression Satisfies SpEL expression specification
@ConditionalOnClass There are specified classes in the system
@ConditionalOnMissingClass There is no specified class in the system
@ConditionalOnSingleCandidate There is only one specified Bean in the container, or this Bean is the preferred Bean
@ConditionalOnProperty Does the property specified in the system have a specified value
@ConditionalOnResource Is there a specified resource file under the class path
@ConditionalOnWebApplication Currently a web environment
@ConditionalOnNotWebApplication Currently not a web environment
@ConditionalOnJndi Specified item exists in JNDI

The article code has been uploaded to GitHub Spring Boot Auto Configuration.

Last words

Articles have been included in Github.com/niumoo/JavaNotes Welcome to Star and Instructions.More front-line factory interviews, Java programmers need to master the core knowledge and other articles, also collated a lot of my text, welcome Star and perfect, hope we can become excellent together.

Articles that are helpful and can be clicked "like" or "share" are all supported and I like them!
Articles are updated continuously every week. To keep an eye on my updated articles and shared dry goods in real time, you can focus on the Unread Code Public Number or My Blog.

Tags: Programming Spring xml github Java

Posted on Mon, 01 Jun 2020 18:20:40 -0700 by atoboldon