springboot源码-自动化配置
总结:
1、EnableAutoConfiguration自动化配置类有很多实现类,各个实现类会自动化解析yml文件的属性,绑定到实例类中。比如server.port属性会通过ServletWebServerFactoryAutoConfiguration自动化配置类绑定到ServerProperties对象中,然后把这个对象注入到ioc容器。
2、绑定的方式就是自动化配置类比如ServletWebServerFactoryAutoConfiguration,通过注解@EnableConfigurationProperties(ServerProperties.class)完成。
3、注解@EnableConfigurationProperties(ServerProperties.class)注解,是通过注册器@Import(EnableConfigurationPropertiesRegistrar.class),EnableConfigurationPropertiesRegistrar类首先会构建一个ConfigurationPropertiesBindingPostProcessor配置属性绑定后置处理器,并注入到ioc容器(这个后置处理器的作用就是构建bean之后,触发afterPropertiesSet方法,从ConfigurationPropertySource属性列表中获取对应的属性,绑定到bean对象比如ServerProperties中)。再通过注解元数据信息类AnnotationMetadata获取到需要绑定的对象类:ServerProperties。然后构建对象,注入ioc,然后触发ConfigurationPropertiesBindingPostProcessor的afterPropertiesSet方法绑定属性。
比如,application.yml的配置,是如何解析到springboot的
server:
port: 8080
在META-INF/spring.factories里可以看到EnableAutoConfiguration的实现类有一个ServletWebServerFactoryAutoConfiguration。前面说了spring boot启动的时候会解析所有EnableAutoConfiguration的实现类,并实例化。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
可以看到这个类有注解:@EnableConfigurationProperties(ServerProperties.class)
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
/**
* Server HTTP port.
*/
private Integer port;
}
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConfigurationProperties {
可以看到@Import(EnableConfigurationPropertiesRegistrar.class)。
首先会注入ConfigurationPropertiesBindingPostProcessor对象到ioc容器,这个对象是一个BeanPostProcessor,所以会在对象实例化之后调用afterPropertiesSet方法(这段可以看spring ioc的源码理解)。
这个ConfigurationPropertiesBindingPostProcessor类的作用就是绑定@EnableConfigurationProperties(ServerProperties.class)注解上的ServerProperties类的属性。绑定的方式就是从获取ConfigurationPropertySource对象列表遍历获取值(之前分析过解析yaml文件或properties文件的属性都会保存为ConfigurationPropertySource,解析逻辑在之前的源码分析里)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {
}
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 注册一些基础类到ioc,不管
registerInfrastructureBeans(registry);
registerMethodValidationExcludeFilter(registry);
// 构建ConfigurationPropertiesBeanRegistrar 对象,没做其他的事情
ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
// // 获取@EnableConfigurationProperties(ServerProperties.class)注解上的ServerProperties注解。然后
getTypes(metadata).forEach(beanRegistrar::register);
}
// 获取@EnableConfigurationProperties(ServerProperties.class)注解上的ServerProperties注解。
private Set<Class<?>> getTypes(AnnotationMetadata metadata) {
return metadata.getAnnotations().stream(EnableConfigurationProperties.class)
.flatMap((annotation) -> Arrays.stream(annotation.getClassArray(MergedAnnotation.VALUE)))
.filter((type) -> void.class != type).collect(Collectors.toSet());
}
static void registerInfrastructureBeans(BeanDefinitionRegistry registry) {
ConfigurationPropertiesBindingPostProcessor.register(registry);
BoundConfigurationProperties.register(registry);
}
具体的绑定属性逻辑
private ConfigurationProperty findProperty(ConfigurationPropertyName name, Context context) {
if (name.isEmpty()) {
return null;
}
for (ConfigurationPropertySource source : context.getSources()) {
ConfigurationProperty property = source.getConfigurationProperty(name);
if (property != null) {
return property;
}
}
return null;
}
构建对象,注入springbean。
private void registerBeanDefinition(String beanName, Class<?> type,
MergedAnnotation<ConfigurationProperties> annotation) {
Assert.state(annotation.isPresent(), () -> "No " + ConfigurationProperties.class.getSimpleName()
+ " annotation found on '" + type.getName() + "'.");
this.registry.registerBeanDefinition(beanName, createBeanDefinition(beanName, type));
}