springboot 成员变量_SpringBoot之@ConfigurationProperties自动注入成员变量值功能源码解析...

前言:

我们在使用SpringBoot开发相关项目时,经常会使用到@ConfigurationProperties注解,这个注解配合application.properties(或yml文件)使用,可以快速的为我们的Bean的成员变量进行赋值,常规用法如下:

// 创建bean

@ConfigurationProperties(prefix="person")

@Data

public class Person {

private int id;

private String name;

private String addr;

}

// 在application.properties文件中添加

person.name=jack

person.id=11

person.addr=china

这样就可以为Person实例自动注入属性

那么SpringBoot是如何为bean实例注入属性值的呢?

1.关于自动注入属性值的功能猜想

SpringBoot会为每一个在配置文件中有匹配项的bean注入属性值,根据之前的 BeanPostProcessor功能可知,我们的Spring容器中应该有一个Bean实现BeanPostProcessor接口,然后在返回每一个bean之前,获取配置文件内容,找到对应属性,然后进行赋值操作

SpringBoot中确实有这么一个Bean,ConfigurationPropertiesBindingPostProcessor,实现了相关赋值功能,那么这个Bean是如何被注入到容器中的呢,下面亲随笔者一层层分析查找

2.SpringBoot项目启动之@SpringBootApplication

@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,下面看下这个注解

@SuppressWarnings("deprecation")

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage

@Import(EnableAutoConfigurationImportSelector.class)

public @interface EnableAutoConfiguration {

主要功能就是把EnableAutoConfigurationImportSelector注入到容器中,下面看下这个类

public class EnableAutoConfigurationImportSelector

extends AutoConfigurationImportSelector {

@Override

protected boolean isEnabled(AnnotationMetadata metadata) {

if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {

return getEnvironment().getProperty(

EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,

true);

}

return true;

}

}

// AutoConfigurationImportSelector

public class AutoConfigurationImportSelector

implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,

BeanFactoryAware, EnvironmentAware, Ordered {}

AutoConfigurationImportSelector这个类实现了DeferredImportSelector接口,可知这个类应该在其selectImport方法中,应该获取了一个bean的列表,然后被这个bean列表的所有bean会被注入到容器中,下面重点分析下这个selectImport方法

对于@Import ImportSelector等接口注入bean到容器的方式不太明白的同学可以参考下这篇文章 https://blog..net/qq_26323323/article/details/81201717

3.AutoConfigurationImportSelector.selectImport(AnnotationMetadata annotationMetadata)

该方法源码如下:

public String[] selectImports(AnnotationMetadata annotationMetadata) {

if (!isEnabled(annotationMetadata)) {

return NO_IMPORTS;

}

try {

// 1.获取META-INF/spring-autoconfigure-metadata.properties 路径下所有bean URL

AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader

.loadMetadata(this.beanClassLoader);

AnnotationAttributes attributes = getAttributes(annotationMetadata);

// 2.重要操作在这里

List configurations = getCandidateConfigurations(annotationMetadata,

attributes);

configurations = removeDuplicates(configurations);

configurations = sort(configurations, autoConfigurationMetadata);

Set exclusions = getExclusions(annotationMetadata, attributes);

checkExcludedClasses(configurations, exclusions);

configurations.removeAll(exclusions);

configurations = filter(configurations, autoConfigurationMetadata);

fireAutoConfigurationImportEvents(configurations, exclusions);

// 3.经过中间的一系列操作返回configurations

return configurations.toArray(new String[configurations.size()]);

}

catch (IOException ex) {

throw new IllegalStateException(ex);

}

}

// getCandidateConfigurations(annotationMetadata,attributes)

protected List getCandidateConfigurations(AnnotationMetadata metadata,

AnnotationAttributes attributes) {

// 主要就是为了获取META-INF/spring.factories 文件下EnableAutoConfiguration对应的value值,并返回该值

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

}

通过以上分析可知:AutoConfigurationImportSelector类的主要功能就是为了加载META-INF/spring.factories文件下EnableAutoConfiguration对应的value值,这些value值对应一个个bean,Spring会将这些bean加载到容器中

我们看下是哪些bean(在spring-boot-autoconfigure-xxx.jar的META-INF/spring.factories中)

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\

org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\

org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\

org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\

org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\

org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\

org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\

org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\

...

org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\

org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\

org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\

org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\

...

org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\

org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\

org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\

org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\

org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\

org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\

org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\

...

org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

以上展示了部分类,可知,这些类都会被注入到Spring中,下面我们重点关注ConfigurationPropertiesAutoConfiguration类

4.ConfigurationPropertiesAutoConfiguration

1)ConfigurationPropertiesAutoConfiguration源码如下:

@Configuration

@EnableConfigurationProperties

public class ConfigurationPropertiesAutoConfiguration {

}

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Import({EnableConfigurationPropertiesImportSelector.class})

public @interface EnableConfigurationProperties {

Class>[] value() default {};

}

该类没有其他方法,由其注解@EnableConfigurationProperties可知,整个类主要是为了注入EnableConfigurationPropertiesImportSelector这个类,

2)EnableConfigurationPropertiesImportSelector源码如下:

class EnableConfigurationPropertiesImportSelector implements ImportSelector {

public String[] selectImports(AnnotationMetadata metadata) {

MultiValueMap attributes = metadata.getAllAnnotationAttributes(EnableConfigurationProperties.class.getName(),

false);

Object[] type = attributes == null ? null : (Object[]) ((Object[]) attributes.getFirst("value"));

return type != null && type.length != 0

? new String[]{ConfigurationPropertiesBeanRegistrar.class.getName(),

ConfigurationPropertiesBindingPostProcessorRegistrar.class.getName()}

: new String[]{ConfigurationPropertiesBindingPostProcessorRegistrar.class.getName()};

}

}

可知其会返回ConfigurationPropertiesBindingPostProcessorRegistrar类到容器中

3)ConfigurationPropertiesBindingPostProcessorRegistrar源码如下

public class ConfigurationPropertiesBindingPostProcessorRegistrar implements ImportBeanDefinitionRegistrar {

public static final String BINDER_BEAN_NAME = ConfigurationPropertiesBindingPostProcessor.class.getName();

private static final String METADATA_BEAN_NAME;

// 主要的注入方法

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

if (!registry.containsBeanDefinition(BINDER_BEAN_NAME)) {

BeanDefinitionBuilder meta = BeanDefinitionBuilder

.genericBeanDefinition(ConfigurationBeanFactoryMetaData.class);

BeanDefinitionBuilder bean = BeanDefinitionBuilder

.genericBeanDefinition(ConfigurationPropertiesBindingPostProcessor.class);

bean.addPropertyReference("beanMetaDataStore", METADATA_BEAN_NAME);

// 真正的注入功能就是这句话,将ConfigurationPropertiesBindingPostProcessor类注册进来

registry.registerBeanDefinition(BINDER_BEAN_NAME, bean.getBeanDefinition());

registry.registerBeanDefinition(METADATA_BEAN_NAME, meta.getBeanDefinition());

}

}

static {

METADATA_BEAN_NAME = BINDER_BEAN_NAME + ".store";

}

}

总结:通过以上的一层层分析,我们终于到了ConfigurationPropertiesBindingPostProcessor类,也成功将该类注入到容器中,下面我们就分析下ConfigurationPropertiesBindingPostProcessor是如何将参数注入到bean中

具体分析过程可参考:https://blog..net/qq_26000415/article/details/78942494 ,笔者不再分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值