The principle of automatic configuration of spring [Springboot]

Spring's automatic configuration principle

The assembly process of the springboot configuration file

1. Springboot will load the main configuration class when it starts, and @EnableAutoConfiguration is turned on.

2. The role of @EnableAutoConfiguration:

  • Use AutoConfigurationImportSelector to import some components to the container.
  • View the content of the selectImports method and return an AutoConfigurationEntry
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
      annotationMetadata);
------
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
------
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;
	}
  • You can see SpringFactoriesLoader.loadFactoryNames, continue to read and call the loadSpringFactories method to obtain the META-INF/spring.factories resource file
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		String factoryTypeName = factoryType.getName();
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}

	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

Summary: Add all the EnableAutoConfiguration values ​​configured in META-INF/spring.factories under the classpath to the container; each xxxAutoConfiguration class is a component in the container, and finally added to the container for automatic configuration. Each automatic configuration class can carry out automatic configuration function

Use HttpEncodingAutoConfiguration to explain the principle of automatic assembly

/*
表名这是一个配置类,
*/
@Configuration(proxyBeanMethods = false)
/*
启动指定类的ConfigurationProperties功能,进入HttpProperties查看,将配置文件中对应的值和HttpProperties绑定起来,并把HttpProperties加入到ioc容器中
*/
@EnableConfigurationProperties(HttpProperties.class)
/*
spring底层@Confitional注解,根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效
此时表示判断当前应用是否是web应用,如果是,那么配置类生效
*/
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
/*
判断当前项目由没有这个类CharacterEncodingFilter,springmvc中进行乱码解决的过滤器
*/
@ConditionalOnClass(CharacterEncodingFilter.class)
/*
判断配置文件中是否存在某个配置:spring.http.encoding.enabled
如果不存在,判断也是成立的,
即使我们配置文件中不配置spring.http.encoding.enabled=true,也是默认生效的
*/
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

    //和springboot的配置文件映射
	private final HttpProperties.Encoding properties;

    //只有一个有参构造器的情况下,参数的值就会从容器中拿
	public HttpEncodingAutoConfiguration(HttpProperties properties) {
		this.properties = properties.getEncoding();
	}

    //给容器中添加一个组件,这个组件的某些值需要从properties中获取
	@Bean
	@ConditionalOnMissingBean//判断容器中是否有此组件
	public CharacterEncodingFilter characterEncodingFilter() {
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
		return filter;
	}

	@Bean
	public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
		return new LocaleCharsetMappingsCustomizer(this.properties);
	}

	private static class LocaleCharsetMappingsCustomizer
			implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {

		private final HttpProperties.Encoding properties;

		LocaleCharsetMappingsCustomizer(HttpProperties.Encoding properties) {
			this.properties = properties;
		}

		@Override
		public void customize(ConfigurableServletWebServerFactory factory) {
			if (this.properties.getMapping() != null) {
				factory.setLocaleCharsetMappings(this.properties.getMapping());
			}
		}

		@Override
		public int getOrder() {
			return 0;
		}
	}
}

According to different current conditions, determine whether this configuration class is effective!

to sum up:

​ 1. Springboot will load a large number of automatic configuration classes

​ 2. Check whether the required functions are automatically configured by default in springboot.

​ 3. Check which components are configured in this automatic configuration class

​ 4. When adding components to the automatic configuration class in the container, the properties will be obtained from the properties class

@Conditional: The automatic configuration class can only take effect under certain conditions

@Conditional extended annotation effect
@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 Satisfy the SpEL expression
@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 the preferred bean
@ConditionalOnProperty Whether the attribute specified in the system has the specified value
@ConditionalOnResource Whether the specified resource file exists in the class path
@ConditionOnWebApplication Currently web environment
@ConditionalOnNotWebApplication Currently not a web environment
@ConditionalOnJndi JNDI has specified items

Guess you like

Origin blog.csdn.net/zw764987243/article/details/111879886