springboot源码-自动化配置

2024-03-11  本文已影响0人  无聊之园

总结:
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));
    }
上一篇下一篇

猜你喜欢

热点阅读