Spring Boot 之 @ConfigurationProperties

@ConfigurationProperties 使用方式有两种
1、在类上使用该注解
2、在工厂方法上使用该注解 (@bean)

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConfigurationProperties {
    @AliasFor("prefix")
    String value() default "";

    @AliasFor("value")
    String prefix() default "";

    boolean ignoreInvalidFields() default false;

    boolean ignoreNestedProperties() default false;

    boolean ignoreUnknownFields() default true;

    /** @deprecated */
    @Deprecated
    boolean exceptionIfInvalid() default true;
}

方式1:

@Getter
@Setter
@Configuration
@PropertySource("classpath:db.properties")
@ConfigurationProperties(prefix = "spring.datasource.sakila")
public class DbConfigInfo {
    private String url;
    private String username;
    private String password;
    private String driverClassName;
    private String initialSize;
    private String maxIdle;
    private String minIdle;
}

方式2:

@Configuration
@PropertySource("classpath:db.properties")
public class DBConfig {

    @Primary
    @Bean("libraryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.library")
    public DataSource sakilaDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean("sakilaDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.sakila")
    public DataSource libraryDataSource() {
        return DataSourceBuilder.create().build();
    }
}

SpringBoot 是如何通過@ConfigurationProperties來获取配置信息的呢?

我们知道,SpringBoot在启动时默认会加载一些类,其中包含了AbstractAutowireCapableBeanFactory, 从而触发了applyBeanPostProcessorsBeforeInitialization接口,applyBeanPostProcessorsBeforeInitialization接口中调用了ConfigurationPropertiesBindingPostProcessor的postProcessBeforeInitialization接口。

applyBeanPostProcessorsBeforeInitialization接口:

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;
        Iterator var4 = this.getBeanPostProcessors().iterator();

        do {
            if (!var4.hasNext()) {
                return result;
            }

            BeanPostProcessor beanProcessor = (BeanPostProcessor)var4.next();
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
        } while(result != null);

        return result;
    }

postProcessBeforeInitialization接口:若存在ConfigurationProperties注解,则执行postProcessBeforeInitialization接口

 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        ConfigurationProperties annotation = (ConfigurationProperties)AnnotationUtils.findAnnotation(bean.getClass(), ConfigurationProperties.class); //方式一
        if (annotation != null) {
            this.postProcessBeforeInitialization(bean, beanName, annotation);
        }

        annotation = (ConfigurationProperties)this.beans.findFactoryAnnotation(beanName, ConfigurationProperties.class);//方式二
        if (annotation != null) {
            this.postProcessBeforeInitialization(bean, beanName, annotation);
        }

        return bean;
    }

postProcessBeforeInitialization接口:

private void postProcessBeforeInitialization(Object bean, String beanName, ConfigurationProperties annotation) {
        PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory(bean);
        factory.setPropertySources(this.propertySources);
        factory.setValidator(this.determineValidator(bean));
        factory.setConversionService(this.conversionService == null ? this.getDefaultConversionService() : this.conversionService);
        if (annotation != null) {
            factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());
            factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());
            factory.setExceptionIfInvalid(annotation.exceptionIfInvalid());
            factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties());
            if (StringUtils.hasLength(annotation.prefix())) {
                factory.setTargetName(annotation.prefix());
            }
        }

        try {
            factory.bindPropertiesToTarget(); //进行属性绑定
        } catch (Exception var8) {
            String targetClass = ClassUtils.getShortName(bean.getClass());
            throw new BeanCreationException(beanName, "Could not bind properties to " + targetClass + " (" + this.getAnnotationDetails(annotation) + ")", var8);
        }
    }

通过PropertiesConfigurationFactory的bindPropertiesToTarget进行属性绑定:target是需要进行属性绑定的object

public void bindPropertiesToTarget() throws BindException {
        Assert.state(this.propertySources != null, "PropertySources should not be null");

        try {
            if (logger.isTraceEnabled()) {
                logger.trace("Property Sources: " + this.propertySources);
            }

            this.hasBeenBound = true;
            this.doBindPropertiesToTarget();
        } catch (BindException var2) {
            if (this.exceptionIfInvalid) {
                throw var2;
            }

            logger.error("Failed to load Properties validation bean. Your Properties may be invalid.", var2);
        }

    }

private void doBindPropertiesToTarget() throws BindException {
        RelaxedDataBinder dataBinder = this.targetName != null ? new RelaxedDataBinder(this.target, this.targetName) : new RelaxedDataBinder(this.target);
        if (this.validator != null && this.validator.supports(dataBinder.getTarget().getClass())) {
            dataBinder.setValidator(this.validator);
        }

        if (this.conversionService != null) {
            dataBinder.setConversionService(this.conversionService);
        }

        dataBinder.setAutoGrowCollectionLimit(2147483647);
        dataBinder.setIgnoreNestedProperties(this.ignoreNestedProperties);
        dataBinder.setIgnoreInvalidFields(this.ignoreInvalidFields);
        dataBinder.setIgnoreUnknownFields(this.ignoreUnknownFields);
        this.customizeBinder(dataBinder);
        Iterable<String> relaxedTargetNames = this.getRelaxedTargetNames();
        Set<String> names = this.getNames(relaxedTargetNames);
        PropertyValues propertyValues = this.getPropertySourcesPropertyValues(names, relaxedTargetNames);
        dataBinder.bind(propertyValues); //属性绑定
        if (this.validator != null) {
            dataBinder.validate();
        }

        this.checkForBindingErrors(dataBinder);
    }

猜你喜欢

转载自blog.csdn.net/u013725455/article/details/79352459