// 配置文件监听器
class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener {
// 默认的属性名称
public static final String DEFAULT_PROPERTIES = "defaultProperties";
// 默认查找的配置文件位置
public static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
// 默认的配置文件名称
public static final String DEFAULT_NAMES = "application";
// 激活的配置文件
public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";
// 需要包括的配置文件
public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include";
// 默认的配置文件名称的配置Key
public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
// 默认的配置文件路径的配置Key
public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
public static final Set<String> LOAD_FILTERED_PROPERTY;
static {
Set<String> filteredProperties = new HashSet<>();
// 需要过滤的属性
filteredProperties.add("spring.profiles.active");
filteredProperties.add("spring.profiles.include");
LOAD_FILTERED_PROPERTY = Collections.unmodifiableSet(filteredProperties);
}
// 判断支持的事件
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
// 当前类只支持ApplicationEnvironmentPreparedEvent和ApplicationPreparedEvent事件
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType) || ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
// 处理事件
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
// 处理ApplicationEnvironmentPreparedEvent事件
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
// 处理ApplicationPreparedEvent
onApplicationPreparedEvent(event);
}
}
// 处理ApplicationEnvironmentPreparedEvent事件
public void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors() {
// 从spring.factories文件中加载EnvironmentPostProcessor处理器
// EnvironmentPostProcessor用于处理环境的后置处理器
return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, getClass().getClassLoader());
}
// 将自己添加进来,ConfigFileApplication
postProcessors.add(this);
// 对环境后置处理器进行排序
AnnotationAwareOrderComparator.sort(postProcessors);
// 遍历所有的后置处理器
for (EnvironmentPostProcessor postProcessor : postProcessors) {
// 执行后置处理器的处理方法,这里解析springboot配置文件
/**
* 比较重要的两个
* @see {@link ConfigFileApplicationListener}
* @see {@link org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor}
*/
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
// EnvironmentPostProcessor处理器
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
addPropertySources(environment, application.getResourceLoader());
}
// 添加属性源,加载配置文件
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
// 添加随机数的生成对象保存到环境对象中
// 用于处理${random.int}等类型的随机数
RandomValuePropertySource.addToEnvironment(environment) {
// 添加一个PropertySource在systemEnvironment之后,名称为random
// super(name, new Random());
environment.getPropertySources().addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new RandomValuePropertySource(RANDOM_PROPERTY_SOURCE_NAME));
}
// 创建配置文件加载器
Loader loader = new Loader(environment, resourceLoader);
// 加载SpringBoot配置文件
loader.load();
}
// 处理ApplicationPreparedEvent
public void onApplicationPreparedEvent(ApplicationEvent event) {
// 添加BeanFactory后置处理器
addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());
}
// 添加BeanFactory后置处理器
protected void addPostProcessors(ConfigurableApplicationContext context) {
// PropertySourceOrderingPostProcessor: 该类的作用就是将环境对象中的defaultProperties属性配置移到最后面
context.addBeanFactoryPostProcessor(new PropertySourceOrderingPostProcessor(context));
}
class Loader {
// 环境对象
public ConfigurableEnvironment environment;
// 占位符解析器
public final PropertySourcesPlaceholdersResolver placeholdersResolver;
// 资源加载器
public final ResourceLoader resourceLoader;
// 所有加载属性文件的加载器
// 从Spring.factories配置文件,加载PropertySourceLoader的加载器
// 该PropertySourceLoader用于加载不同后缀的未配置文件,例如xml,properties,yml
public final List<PropertySourceLoader> propertySourceLoaders;
// 所有需要加载的环境配置文件
public Deque<Profile> profiles;
// 所有加载过的环境配置文件
public List<Profile> processedProfiles;
// 是否存在激活的配置文件
public boolean activatedProfiles;
// 对应环境配置与该环境配置文件解析的配置属性的映射关系
public Map<Profile, MutablePropertySources> loaded;
// 解析好的环境配置对应的配置属性环境,因为相同的文件可能解析多次
public Map<DocumentsCacheKey, List<Document>> loadDocumentsCache = new HashMap<>();
Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
// 环境对象
this.environment = environment;
// 占位符解析器
this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
// 资源加载器
this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
// 从Spring.factories配置文件,加载PropertySourceLoader的加载器
// 该PropertySourceLoader用于加载不同后缀的未配置文件,例如xml,properties,yml
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader());
}
// 开始加载配置
public void load() {
// 执行属性过滤操作
FilteredPropertySource.apply(
this.environment,
// 默认的属性配置名称
DEFAULT_PROPERTIES,
// 加载过滤的配置
// filteredProperties.add("spring.profiles.active");
// filteredProperties.add("spring.profiles.include");
// LOAD_FILTERED_PROPERTY = Collections.unmodifiableSet(filteredProperties);
LOAD_FILTERED_PROPERTY,
// 从上下环境中获取到的defaultProperties名称对应的配置属性
(defaultProperties) -> {
// 所有需要加载的环境配置文件
this.profiles = new LinkedList<>();
// 所有加载过的环境配置文件
this.processedProfiles = new LinkedList<>();
// 是否存在激活的配置文件
this.activatedProfiles = false;
// 对应环境配置与该环境配置文件解析的配置属性的映射关系
this.loaded = new LinkedHashMap<>();
// 初始化上下文环境对象中配置的环境配置对应的配置文件名称
this.initializeProfiles();
// 遍历所有需要处理的环境配置文件,在加载的过程中,会解析到配置文件中又需要解析的配置,会继续添加到profiles中
while (!this.profiles.isEmpty()) {
/**
* 从队列中获取出来
* 第一次处理的profile一定是null标识,该标识表示加载application.xxx配置
* 在{@link Loader#initializeProfiles}方法中添加的
*/
Profile profile = this.profiles.poll();
// 如果不是默认的环境配置文件,他这里命名有问题,isDefaultProfile -> return profile != null && !profile.isDefaultProfile();
// isDefaultProfile返回为true,表示不是默认的配置文件
if (this.isDefaultProfile(profile)) {
// 不是默认的配置文件,添加到环境对象中
// 如果环境对象中存在该激活文件,则不处理,否则保存
this.addProfileToEnvironment(profile.getName());
}
// 该函数通过配置环境对象来校验解析到的配置属性是否满足条件
Function function = new Function<Profile, Boolean>() {
@Override
public Boolean apply(Profile profile) {
// 用于获取配置文件中定义的"正向"配置文件激活的条件过滤器
// 正向条件表示只有满足这些条件的配置文件才会被激活
return Loader.this.getPositiveProfileFilter(profile);
}
}
// 获取一个对解析好的属性配置的Document对象进行过滤的工厂类
DocumentFilterFactory documentFilterFactory = this.getDocumentFilterFactory(function);
// 获取一个处理解析好的属性配置的Document对象
DocumentConsumer documentConsumer = this.getDocumentConsumer(false);
// 加载配置文件
load(profile, documentFilterFactory, documentConsumer);
// 记录已经加载过的配置文件
this.processedProfiles.add(profile);
}
// 该函数通过配置环境对象来校验解析到的配置属性是否满足条件
Function function = new Function<Profile, Boolean>() {
@Override
public Boolean apply(Profile profile) {
// 用于获取配置文件中定义的"反向"配置文件激活的条件过滤器
// 反向条件表示只有不满足这些条件的配置文件才会被激活
return Loader.this.getNegativeProfileFilter(profile);
}
}
// 获取一个对解析好的属性配置的Document对象进行过滤的工厂类
DocumentFilterFactory documentFilterFactory = this.getDocumentFilterFactory(function);
// 获取一个处理解析好的属性配置的Document对象
DocumentConsumer documentConsumer = this.getDocumentConsumer(true);
// 加载默认的配置文件,不带环境后缀的配置,application.xxx配置
load(null, documentFilterFactory, documentConsumer);
// 将loader中缓存的所有符合条件的配置属性保存到环境对象中
this.addLoadedPropertySources();
// 应用激活的环境配置,将配置同步到环境对象中
this.applyActiveProfiles(defaultProperties);
});
}
// 应用激活的环境配置,将配置同步到环境对象中
public void applyActiveProfiles(PropertySource<?> defaultProperties) {
// 需要保存的激活配置文件
List<String> activeProfiles = new ArrayList<>();
if (defaultProperties != null) {
// 创建使用defaultProperties给指定对象进行绑定的的绑定器
Binder binder = new Binder(ConfigurationPropertySources.from(defaultProperties), new PropertySourcesPlaceholdersResolver(this.environment));
// 从defaultProperties属性中获取spring.profiles.include的值
List<String> defaultIncludeProfiles = this.getDefaultProfiles(binder, "spring.profiles.include");
// 保存默认属性配置中的包含文件
activeProfiles.addAll(defaultIncludeProfiles);
// 如果不存在激活的配置文件
if (!this.activatedProfiles) {
// 获取默认配置中spring.profiles.active的配置
List<String> defaultActiveProfiles = getDefaultProfiles(binder, "spring.profiles.active");
activeProfiles.addAll(defaultActiveProfiles);
}
}
// 最后,将所有解析过的环境配置中,排除默认的环境配置,将剩下的都保存到激活的环境配置中
this.processedProfiles.stream().filter(this::isDefaultProfile).map(Profile::getName).forEach(activeProfiles::add);
// 将解析的所有激活的配置设置到环境对象中
this.environment.setActiveProfiles(activeProfiles.toArray(new String[0]));
}
/**
* 是否是默认环境的配置,他这里命名有问题,isDefaultProfile
*
* @param profile 环境配置信息
* @return true: 表示不是默认的配置文件, false: 表示是默认的配置环境
*/
public boolean isDefaultProfile(Profile profile) {
return profile != null && !profile.isDefaultProfile();
}
/**
* @param binder 使用defaultProperties中的配置属性进行绑定的绑定器
* @param property 属性的key
* @return 返回绑定成功的环境配置名称
*/
public List<String> getDefaultProfiles(Binder binder, String property) {
return binder.bind(property, STRING_LIST).orElse(Collections.emptyList());
}
// 将loader中缓存的所有符合条件的配置属性保存到环境对象中
public void addLoadedPropertySources() {
// 获取环境对象中的所有属性配置
MutablePropertySources destination = this.environment.getPropertySources();
// 获取当前Loader中加载到的符合条件的所有配置
List<MutablePropertySources> loaded = new ArrayList<>(this.loaded.values());
// 对加载的的配置进行倒序
Collections.reverse(loaded);
// 保存最后添加的配置属性的名称
String lastAdded = null;
// 保存的配置属性的名称,因为是set,防止相同的名称多次添加
Set<String> added = new HashSet<>();
// 遍历当前Loader解析到的配置
for (MutablePropertySources sources : loaded) {
for (PropertySource<?> source : sources) {
// 保存该配置属性名,因为是set,防止相同的名称多次添加
if (added.add(source.getName())) {
this.addLoadedPropertySource(destination, lastAdded, source);
// 保存最后添加的属性名称
lastAdded = source.getName();
}
}
}
}
/**
* 保存加载的属性配置
*
* @param destination 加到哪里,environment的配置属性中
* @param lastAdded 最后添加的配置属性的名称
* @param source 需要添加的配置属性
*/
public void addLoadedPropertySource(MutablePropertySources destination, String lastAdded, PropertySource<?> source) {
// 如果lastAdded为空,表示第一次添加属性
if (lastAdded == null) {
// 如果包含defaultProperties的属性配置
if (destination.contains(DEFAULT_PROPERTIES)) {
// 保存到defaultProperties之前
destination.addBefore(DEFAULT_PROPERTIES, source);
return;
}
// 如果不包含defaultProperties,则保存到最后
// 这样做的目的就是让defaultProperties默认的配置放在最后,查找的时候也是最后才会到defaultProperties中查找
destination.addLast(source);
return;
}
// 如果不为空,就添加上上次天最后添加的地方
destination.addAfter(lastAdded, source);
}
/**
* 获取一个对解析好的属性配置的Document对象进行过滤的工厂类
*
* @param function 该函数通过配置环境对象来校验解析到的配置属性是否满足条件
*/
public DocumentFilterFactory getDocumentFilterFactory(Function<Profile, Boolean> function) {
DocumentFilterFactory documentFilterFactory = new DocumentFilterFactory() {
@Override
public DocumentFilter getDocumentFilter(Profile profile) {
return function.apply(profile);
}
}
return documentFilterFactory;
}
/**
* 获取一个处理解析好的属性配置的Document对象
*
* @param checkForExisting 是否需要校验解析好的属性配置是否存在
* @return 处理Document对象的处理器
*/
public DocumentConsumer getDocumentConsumer(boolean checkForExisting) {
// 该BiConsumer对象只负责将解析好的PropertySource保存到指定的MutablePropertySources中
BiConsumer biConsumer = new BiConsumer<MutablePropertySources, PropertySource>() {
@Override
public void accept(MutablePropertySources propertySources, PropertySource propertySource) {
// 将解析好的属性配置保存到Loader.loaded缓存中
propertySources.addLast(propertySource);
}
}
// 该DocumentConsumer对象负责判断加载好的环境配置是否已经加载过,加载过就不处理,否则就使用biConsumer来处理逻辑
DocumentConsumer documentConsumer = this.addToLoaded(biConsumer, checkForExisting);
return documentConsumer;
}
/**
* 用于获取配置文件中定义的"正向"配置文件激活的条件过滤器
* 正向条件表示只有满足这些条件的配置文件才会被激活
*
* @param profile 环境配置
* @return 文档过滤器
*/
public DocumentFilter getPositiveProfileFilter(Profile profile) {
return new DocumentFilter() {
@Override
public boolean match(Document document) {
// 获取到document对应解析的配置文件中,解析到的spring.profiles的值
String[] profiles = document.getProfiles();
// 如果环境配置为空,表示为默认配置,就是application.xxx配置文件的情况
if (profile == null) {
// 如果spring.profiles的值也为空,表示该配置为默认配置,就是处理application.xxx配置文件,这种情况下,application.xxx被激活
return ObjectUtils.isEmpty(profiles);
}
// 其他情况,如果指定了环境配置,解析该表达式,然后利用表达式匹配
Profiles pfs = Profiles.of(profiles);
// 如果spring.profiles配置的环境包含指定的环境,则还需要判断一下条件
return ObjectUtils.containsElement(profiles, profile.getName())
// 使用(),&(and),!(not),|(or)
// (dev,pro),在环境对象中,dev和pro只要有一个设置了激活,当前document配置则保留
// dev|pro,和(dev,pro)效果一样
// dev&pro,在环境对对象中,dev和pro都设置了激活的情况下,当前document配置才保留,否则忽略该配置文件属性配置
// !dev ,在环境对象中,dev没有设置激活,则保留当前document配置
&& Loader.this.environment.acceptsProfiles(pfs);
}
};
}
/**
* 用于获取配置文件中定义的"反向"配置文件激活的条件过滤器
* 反向条件表示只有不满足这些条件的配置文件才会被激活
*
* @param profile 环境配置
* @return 文档过滤器
*/
public DocumentFilter getNegativeProfileFilter(Profile profile) {
return new DocumentFilter() {
@Override
public boolean match(Document document) {
// 获取到document对应解析的配置文件中,解析到的spring.profiles的值
String[] profiles = document.getProfiles();
// 解析该表达式,然后利用表达式匹配
Profiles pfs = Profiles.of(profiles);
// 当环境配置为null,并且解析到的配置文件中spring.profiles不为空,再判断以下条件
return (profile == null && !ObjectUtils.isEmpty(profiles)
// 使用(),&(and),!(not),|(or)
// (dev,pro),在环境对象中,dev和pro只要有一个设置了激活,当前document配置则保留
// dev|pro,和(dev,pro)效果一样
// dev&pro,在环境对对象中,dev和pro都设置了激活的情况下,当前document配置才保留,否则忽略该配置文件属性配置
// !dev ,在环境对象中,dev没有设置激活,则保留当前document配置
&& Loader.this.environment.acceptsProfiles(pfs);
}
};
}
/**
* 加载指定路径下,指定文件名对应的配置文件
*/
public void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
// 获取需要查找配置文件的路径
Set<String> searchLocations = this.getSearchLocations();
// 遍历需要扫描配置文件的路径
searchLocations.forEach((location) -> {
// 如果以/结尾,表示文件夹
boolean isFolder = location.endsWith("/");
// 如果是文件夹,则搜索指定文件名对应的文件,否则使用null来标识该路径
Set<String> names = isFolder ? this.getSearchNames() : NO_SEARCH_NAMES;
// 根据当前正在遍历的扫描路径中,再找所有需要扫描的文件名对应的文件
names.forEach((name) -> this.load(location, name, profile, filterFactory, consumer));
});
}
// 真正开始查找对应的配置文件资源,进行解析
public void load(PropertySourceLoader loader, String location, Profile profile, DocumentFilter filter, DocumentConsumer consumer) {
// 加载指定路径文件的资源
Resource resource = this.resourceLoader.getResource(location);
// 如果文件不存在,不处理
if (resource == null || !resource.exists()) {
return;
}
// 如果文件没有后缀名,不处理
if (!StringUtils.hasText(StringUtils.getFilenameExtension(resource.getFilename()))) {
return;
}
// 设置解析到的配置属性的名称
String name = "applicationConfig: [" + location + "]";
// 开始解析配置文件,并转换为Document对象
List<Document> documents = this.loadDocuments(loader, name, resource);
// 如果没有加载到属性配置,不需要处理
if (CollectionUtils.isEmpty(documents)) {
return;
}
// 最终需要保存的属性配置对应的Document
List<Document> loaded = new ArrayList<>();
// 遍历解析好的属性配置,一般情况只会有一个
// 因为一个配置文件一般情况下只会有一个Document对象(PropertySource)
for (Document document : documents) {
// 将解析好的Document对象交给文档过滤器filter来进行过滤
// 如果过滤成功,符合条件
if (filter.match(document)) {
// 从当前加载的配置文件对应的属性对象中,获取spring.profiles.active的属性值
// 保存这个激活的配置信息到当前Loader对象中
this.addActiveProfiles(document.getActiveProfiles());
// 从当前加载的配置文件对应的属性对象中,获取spring.profiles.include的属性值
// 保存这个激活的配置信息到当前Loader对象中
this.addIncludedProfiles(document.getIncludeProfiles());
// 保存符合条件的配置属性文件
loaded.add(document);
}
}
// 将这个配置属性进行倒序
Collections.reverse(loaded);
// 如果加载到了符合条件的配置属性文件
if (!loaded.isEmpty()) {
/**
* 遍历所有的符合条件的属性文件Document对象
* 然后交给DocumentConsumer文档消费者进行处理
* 实际上就是将解析好的环境缓存到Loader的loaders对象中,loaders属性对象保存了所有符合条件的环境配置->属性配置的映射
* @see {@link Loader#addToLoaded}
*/
loaded.forEach((document) -> consumer.accept(profile, document));
}
}
// 调用配置属性加载器加载属性文件,并且将环境相关的配置信息与解析到的属性配置封装成Document对象
public List<Document> loadDocuments(PropertySourceLoader loader, String name, Resource resource) {
// 创建缓存KEY
DocumentsCacheKey cacheKey = new DocumentsCacheKey(loader, resource);
// 是否已经处理过
List<Document> documents = this.loadDocumentsCache.get(cacheKey);
// 没有处理过该文件
if (documents == null) {
// 使用属性文件加载器加载属性文件
List<PropertySource<?>> loaded = loader.load(name, resource);
// 将属性配置封装为Document对象
documents = this.asDocuments(loaded);
// 缓存该Document
this.loadDocumentsCache.put(cacheKey, documents);
}
// 返回解析转换后的Document对象
return documents;
}
// 处理给定搜索路径是目录以及是文件的情况,并根据文件全称加载文件
public void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
// 如果没有指定了文件名,表示该location是一个文件,而不是目录
if (!StringUtils.hasText(name)) {
// 遍历所有的所有加载属性文件的加载器
// 从Spring.factories配置文件,加载PropertySourceLoader的加载器
// 该PropertySourceLoader用于加载不同后缀的未配置文件,例如xml,properties,yml
for (PropertySourceLoader loader : this.propertySourceLoaders) {
// 该属性文件加载器是否可以加载该文件后缀
if (this.canLoadFileExtension(loader, location)) {
// 使用指定的属性加载器加载该文件
this.load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
return;
}
}
// 如果没有加载器可以加载该文件,抛出异常
// 提示目录必须以"/"结尾
throw new IllegalStateException("File extension of config file location '" + location
+ "' is not known to any PropertySourceLoader. If the location is meant to reference "
+ "a directory, it must end in '/'");
}
// 缓存该文件处理过的后缀名
// 因为指定了路径和文件名,所以同一个后缀只需要处理一次,processed是用于保存执行过的
// 因为可能不同的属性加载器可能支持相同的后缀名,因此加载过一次的下次重复的文件名就保存不进来,就不会重复加载
Set<String> processed = new HashSet<>();
// 遍历所有的所有加载属性文件的加载器
// 从Spring.factories配置文件,加载PropertySourceLoader的加载器
// 该PropertySourceLoader用于加载不同后缀的未配置文件,例如xml,properties,yml
for (PropertySourceLoader loader : this.propertySourceLoaders) {
// 获取加载器支持的类型
for (String fileExtension : loader.getFileExtensions()) {
// 缓存该文件处理过的后缀名
// 因为指定了路径和文件名,所以同一个后缀只需要处理一次,processed是用于保存执行过的
// 因为可能不同的属性加载器可能支持相同的后缀名,因此加载过一次的下次重复的文件名就保存不进来,就不会重复加载
if (processed.add(fileExtension)) {
// 通过文件的全称加载文件
this.loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory, consumer);
}
}
}
}
// 获取查找配置文件的路径
public Set<String> getSearchLocations() {
// 如果环境对象中包含spring.config.location的key,表示指定了去那个路径找配置
if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
// 去配置的spring.config.location路径中查找文件
return this.getSearchLocations(CONFIG_LOCATION_PROPERTY);
}
// 如果没有设置spring.config.location的值
// 再找spring.config.additional-location中的路径
Set<String> locations = this.getSearchLocations(CONFIG_ADDITIONAL_LOCATION_PROPERTY);
// 再找ConfigFileApplicationListener.this.searchLocations对应的路径,如果没有手动调佣api,则searchLocations为空
// 会使用默认的搜索路径来找 "classpath:/,classpath:/config/,file:./,file:./config/"
// 将给定的属性值使用","进行切割,如果值不存在,使用兜底的值进行切割
Set<String> stringSet = this.asResolvedSet(ConfigFileApplicationListener.this.searchLocations, DEFAULT_SEARCH_LOCATIONS);
// 将spring.config.additional-location中的路径和(searchLocations或者默认的搜索路径)进行合并一起查找
locations.addAll(stringSet);
return locations;
}
/**
* 获取指定属性对应的值,并使用","切割,返回需要查找的路径集合
*
* @param propertyName 属性名称
*/
public Set<String> getSearchLocations(String propertyName) {
Set<String> locations = new LinkedHashSet<>();
// 如果环境对象中包含此属性值
if (this.environment.containsProperty(propertyName)) {
// 将给定的属性值使用","进行切割,如果值不存在,使用兜底的值进行切割
Set<String> resolvedSet = this.asResolvedSet(this.environment.getProperty(propertyName), null);
// 遍历所有的值
for (String path : resolvedSet) {
// 如果不包含${}表达式
if (!path.contains("$")) {
// 解析一下路径
path = StringUtils.cleanPath(path);
// 如果不是URL路径
if (!ResourceUtils.isUrl(path)) {
// 将路径拼接上file:
path = ResourceUtils.FILE_URL_PREFIX + path;
}
}
// 保存该路径
locations.add(path);
}
}
// 返回需要扫描的路径
return locations;
}
/**
* 获取需要查找的文件名称
*/
public Set<String> getSearchNames() {
// 如果环境对象中包含spring.config.name配置
if (this.environment.containsProperty(CONFIG_NAME_PROPERTY)) {
// 返回该spring.config.name配置对应的值
String property = this.environment.getProperty(CONFIG_NAME_PROPERTY);
// 将给定的属性值使用","进行切割,如果值不存在,使用兜底的值进行切割
return this.asResolvedSet(property, null);
}
// 将给定的属性值使用","进行切割,如果值不存在,使用兜底的值进行切割
// ConfigFileApplicationListener.this.names除非手动调用set的api设置,否则为空
// 最终使用默认的名称: application
return this.asResolvedSet(ConfigFileApplicationListener.this.names, DEFAULT_NAMES);
}
/**
* 将给定的属性值使用","进行切割,如果值不存在,使用兜底的值进行切割
*
* @param value 指定切割的值
* @param fallback 兜底的值
* @return 切割后的值的集合
*/
public Set<String> asResolvedSet(String value, String fallback) {
// 给定的路径使用","进行分割
List<String> list = Arrays.asList(StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray((value != null) ? this.environment.resolvePlaceholders(value) : fallback)));
// 对路径进行反向排序
Collections.reverse(list);
// 返回
return new LinkedHashSet<>(list);
}
/**
* 通过文件的全称加载文件
*
* @param loader 属性加载器
* @param prefix 路径+文件名
* @param fileExtension 文件后缀
* @param profile 环境配置
* @param filterFactory 环境配置过滤工厂,生产环境过滤器
* @param consumer 解析好的配置文件属性会封装成Document,这个就是来处理Document的对象
*/
public void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
/**
* @see {@link Loader#getDocumentFilterFactory(Function)}
* 以下两个都是DocumentFilterFactory,不同时机DocumentFilterFactory表示下面的某一个
* @see {@link Loader#getPositiveProfileFilter}
* @see {@link Loader#getNegativeProfileFilter(Profile)}
*/
// 获取默认配置的属性配置过滤器
DocumentFilter defaultFilter = filterFactory.getDocumentFilter(null);
// 获取指定环境配置的属性配置过滤器
DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile);
// 如果环境配置不为空
if (profile != null) {
// 根据环境后缀拼接为application-${prifile}.xxx的文件名
String profileSpecificFile = prefix + "-" + profile + fileExtension;
// 使用默认的配置文件过滤器对加载的该文件的属性配置进行过滤
this.load(loader, profileSpecificFile, profile, defaultFilter, consumer);
// 使用指定环境配置的属性配置过滤器对加载的该文件的属性配置进行过滤
this.load(loader, profileSpecificFile, profile, profileFilter, consumer);
// 遍历所有已经解析过的配置文件
for (Profile processedProfile : this.processedProfiles) {
// 如果解析的配置不为null,为null表示默认的配置
if (processedProfile != null) {
// 再利用当前正在处理的文件路径拼接之前加载的环境再来进行加载一下
String previouslyLoaded = prefix + "-" + processedProfile + fileExtension;
// 使用指定环境配置的属性配置过滤器对加载的该文件的属性配置进行过滤
this.load(loader, previouslyLoaded, profile, profileFilter, consumer);
}
}
}
// 使用指定环境配置的属性配置过滤器对加载的该文件的属性配置进行过滤
// 现在加载的则是普通的配置文件,没有带 -profile 的配置
this.load(loader, prefix + fileExtension, profile, profileFilter, consumer);
}
/**
* 该属性文件加载器是否可以加载该文件后缀
*/
public boolean canLoadFileExtension(PropertySourceLoader loader, String name) {
// 获取对应加载器支持的文件后缀与给定的文件名做匹配
return Arrays.stream(loader.getFileExtensions()).anyMatch((fileExtension) -> StringUtils.endsWithIgnoreCase(name, fileExtension));
}
/**
* @param addMethod 用来处理解析好的配置文件对应的PropertySource对象{@link Loader#addToLoaded},最终就是将该属性保存到loaded属性中
* @param checkForExisting
* @return
*/
public DocumentConsumer addToLoaded(BiConsumer<MutablePropertySources, PropertySource<?>> addMethod, boolean checkForExisting) {
// 返回一个对解析好的配置文件Document对象处理类
return new DocumentConsumer() {
@Override
public void accept(Profile profile, Document document) {
// 是否需要校验属性该环境对应的配置是否存在
if (checkForExisting) {
// Loader.this.loaded 对应环境配置与该环境配置文件解析的配置属性的映射关系
for (MutablePropertySources merged : Loader.this.loaded.values()) {
// 如果该环境已经加载过对应的配置
if (merged.contains(document.getPropertySource().getName())) {
// 直接返回,不处理
return;
}
}
}
// 如果不需要校验环境配置是否加载过,或者该环境配置没有加载过
// 如果loader中不存在该环境对应的属性,保存一个新的MutablePropertySources并返回
// 如果已经存在,则返回存在的属性配置
MutablePropertySources merged = this.loaded.computeIfAbsent(profile, (k) -> new MutablePropertySources());
/** 将该环境之前存在的配置信息与当前加载到的配置信息都交给BiConsumer处理器来处理
* propertySources.addLast(propertySource);这就是这个BiConsumer处理的逻辑
* 将加载好的属性配置缓存到loader中
* {@link Loader#getDocumentConsumer}
*/
addMethod.accept(merged, document.getPropertySource());
}
}
}
// 初始化环境配置配置文件
public void initializeProfiles() {
// 添加使用默认的配置文件标识: 值为null
this.profiles.add(null);
// 从整个上下文环境对象中,获取所有的配置属性,然后获取spring.profiles.active对应的环境配置对象
Set<Profile> activatedViaProperty = this.getProfilesFromProperty(ACTIVE_PROFILES_PROPERTY);
// 从整个上下文环境对象中,获取所有的配置属性,然后获取spring.profiles.include对应的环境配置对象
Set<Profile> includedViaProperty = this.getProfilesFromProperty(INCLUDE_PROFILES_PROPERTY);
// 从整个上下文环境对象中,获取手动调用api设置的额外的激活配置
List<Profile> otherActiveProfiles = this.getOtherActiveProfiles(activatedViaProperty, includedViaProperty);
// 手动api设置的优先级最高,比配置文件中和命令行中配置的优先级都高
this.profiles.addAll(otherActiveProfiles);
// 其次是spring.profiles.include配置
this.profiles.addAll(includedViaProperty);
// 最后是spring.profiles.actived的配置
// 如果已经之前已经保存过激活的配置,则不会在保存
this.addActiveProfiles(activatedViaProperty);
// 如果只有一个,那表示添加的就是默认的null标识,处理默认的环境配置
// 因为上面处理过spring.profiles.include,spring.profiles.active以及自己额外设置的,如果这些都没有设置,那么就会执行默认的环境
if (this.profiles.size() == 1) {
// 获取默认的激活文件
// 可能是手动设置的,也可以是spring.profiles.default配置设置的
for (String defaultProfileName : this.environment.getDefaultProfiles()) {
// 包装成Profile对象,标记该环境配置为默认的配置
Profile defaultProfile = new Profile(defaultProfileName, true);
// 保存默认的配置文件
this.profiles.add(defaultProfile);
}
}
}
// 添加激活环境配置文件到环境对象中
public void addProfileToEnvironment(String profile) {
// 如果环境对象中存在该激活文件,则不处理,否则保存
for (String activeProfile : this.environment.getActiveProfiles()) {
if (activeProfile.equals(profile)) {
return;
}
}
this.environment.addActiveProfile(profile);
}
// 从整个上下文环境对象中,获取所有的配置属性,然后获取指定key对应的环境配置对象
public Set<Profile> getProfilesFromProperty(String profilesProperty) {
// 如果上下文环境中不包含该配置,则不处理
if (!this.environment.containsProperty(profilesProperty)) {
return Collections.emptySet();
}
// 创建配置属性绑定对象,用于配置属性绑定到对象中
Binder binder = Binder.get(this.environment);
// 从给定Binder对象中存储的配置属性对象里(这里是整合环境对象中的所有属性),将指定key的属性绑定到对应的对象中
Set<Profile> profiles = this.getProfiles(binder, profilesProperty);
// 返回获取到的环境配置对象
return new LinkedHashSet<>(profiles);
}
/**
* 添加需要包含的环境配置
*/
public void addIncludedProfiles(Set<Profile> includeProfiles) {
// 保存已经保存的环境配置
LinkedList<Profile> existingProfiles = new LinkedList<>(this.profiles);
// 清空之前的数据,因为要确保顺序
this.profiles.clear();
// 保存当前给定的需要包含的环境配置
this.profiles.addAll(includeProfiles);
// 从刚刚添加的includeProfiles包含的环境配置中,删除之前已经解析过的配置环境
// 就是去重,已经解析过的就不会再处理,这里只需要保留需要包含,且还未解析的环境配置
// 因为包含的环境配置还要进行解析
this.profiles.removeAll(this.processedProfiles);
// 再合并之前已经存在的环境配置
this.profiles.addAll(existingProfiles);
}
// 批量保存激活的配置文件
public void addActiveProfiles(Set<Profile> profiles) {
// 是否已经添加过激活的配置文件
if (this.activatedProfiles) {
return;
}
// 保存激活的配置文件
this.profiles.addAll(profiles);
// 标记已经添加过激活的文件
this.activatedProfiles = true;
// 如果有默认的默认的环境配置,删除默认的环境配置文件
removeUnprocessedDefaultProfiles() {
// 环境名称为default的Profile
this.profiles.removeIf((profile) -> (profile != null && profile.isDefaultProfile()));
}
}
/**
* 获取手动调用api设置的额外的激活配置
*/
public List<Profile> getOtherActiveProfiles(Set<Profile> activatedViaProperty, Set<Profile> includedViaProperty) {
// 获取环境对象中保存的所有激活的配置文件
// 其中包含手动给上下文中添加的额外的激活配置
/**
* @see {@link org.springframework.boot.SpringApplication#setAdditionalProfiles}
* @see {@link org.springframework.boot.SpringApplication#configureProfiles}
*/
String[] activeProfiles = this.environment.getActiveProfiles();
return Arrays.stream(activeProfiles)
.map(Profile::new)
// 只需要不在active和include中的配置,存在的配置不要
.filter((profile) -> !activatedViaProperty.contains(profile) && !includedViaProperty.contains(profile))
.collect(Collectors.toList());
}
/**
* 从给定Binder对象中存储的配置属性对象里,将指定key的属性绑定到对应的对象中
*
* @param binder {@link Binder} 数据绑定对象,内部包含绑定对象需要哪个配置属性的数据进行绑定
* {@link Loader#getProfilesFromProperty} 中,该Binder则是从环境对象中的所有配置属性中查找配置进行绑定
* {@link Loader#asDocuments}中,该Binder则是从当前解析完成的配置文件对应的配置属性中查找配置进行绑定
* @param name 配置属性的key
*/
public Set<Profile> getProfiles(Binder binder, String name) {
return binder.bind(name, STRING_ARRAY).map(this::asProfileSet).orElse(Collections.emptySet());
}
/**
* 将环境对象名称转换为Profile对象
*
* @param profileNames 环境对象名称
*/
public Set<Profile> asProfileSet(String[] profileNames) {
List<Profile> profiles = new ArrayList<>();
// 遍历指定的属性key对应的环境配置的值
for (String profileName : profileNames) {
// 将环境名称包装成Profile对象
profiles.add(new Profile(profileName));
}
return new LinkedHashSet<>(profiles);
}
/**
* 将解析好的配置文件对应的配置属性转换为Document对象
*
* @param loaded 加载好的配置文件对应的配置属性
*/
public List<Document> asDocuments(List<PropertySource<?>> loaded) {
// 遍历当前配置文件中加载的所有属性
return loaded.stream().map((propertySource) -> {
// 将这个加载的配置属性,使用配置属性绑定器绑定到指定的对象中
Binder binder = new Binder(ConfigurationPropertySources.from(propertySource), this.placeholdersResolver);
// 从当前加载的配置文件对应的属性对象中,将spring.profiles.active的属性绑定到对应的对象中
Set<Profile> activeProfiles = this.getProfiles(binder, ACTIVE_PROFILES_PROPERTY);
// 从当前加载的配置文件对应的属性对象中,将spring.profiles.include的属性绑定到对应的对象中
Set<Profile> includeProfiles = this.getProfiles(binder, INCLUDE_PROFILES_PROPERTY);
// 从当前加载的配置文件对应的属性对象中,将spring.profiles的属性绑定到对应的数组对象中
/**
* @see {@link Document]
*/
String[] springProfiles = binder.bind("spring.profiles", STRING_ARRAY).orElse(null);
// 将该配置文件中加载到的配置属性,激活的配置文件,包含的配置文件,和公共key(spring.profiles)的配置文件
// 注意: 当前Document仅仅表示当前解析的配置文件对应的配置信息
return new Document(propertySource, activeProfiles, includeProfiles, springProfiles);
}).collect(Collectors.toList());
}
}
// Profile配置文件解析器
class ProfilesParser {
// 解析环境配置属性值
public static Profiles parse(String... profiles) {
Profiles[] parsed = new Profiles[profiles.length];
// 一一对配置的值进行解析
for (int i = 0; i < profiles.length; i++) {
// 解析表达式
parsed[i] = parseExpression(profiles[i]) {
// 使用(),&(and),!(not),|(or)
// (dev,pro),在环境对象中,dev和pro只要有一个设置了激活,当前document配置则保留
// dev|pro,和(dev,pro)效果一样
// dev&pro,在环境对对象中,dev和pro都设置了激活的情况下,当前document配置才保留,否则忽略该配置文件属性配置
// !dev ,在环境对象中,dev没有设置激活,则保留当前document配置
StringTokenizer tokens = new StringTokenizer(expression, "()&|!", true);
}
}
// 返回解析好的环境配置信息
return new ParsedProfiles(expressions, parsed);
}
// 生成关系为or条件的Profiles
// 使用环境配置进行or运算
public static Profiles or(Profiles... profiles) {
return new Profiles() {
@Override
public boolean matches(Predicate<String> activeProfile) {
// 遍历所有的环境配置,所有的环境配置都任何一个匹配成功就算符合条件
return Arrays.stream(profiles).anyMatch(ProfilesParser.this.isMatch(activeProfile));
}
};
}
// 生成关系为and条件的Profiles
// 使用环境配置进行and运算
public static Profiles and(Profiles... profiles) {
return new Profiles() {
@Override
public boolean matches(Predicate<String> activeProfile) {
// 遍历所有的环境配置,所有的环境配置都需要匹配成功才算符合条件
return Arrays.stream(profiles).allMatch(ProfilesParser.this.isMatch(activeProfile));
}
};
}
// 生成关系为not条件的Profiles
// 使用环境配置进行非运算
public static Profiles not(Profiles profiles) {
return new Profiles() {
@Override
public boolean matches(Predicate<String> activeProfile) {
// 将给定的环境配置进行匹配,再进行取反
return !profiles.matches(activeProfile);
}
};
}
// 真实使用环境配置进行匹配
// 直接利用给定的激活环境匹配器对环境进行匹配,所有的关系最终都是走向这里
public static Profiles equals(String profile) {
return new Profiles() {
@Override
public boolean matches(Predicate<String> activeProfile) {
// 直接利用给定的激活环境匹配器对环境进行匹配,所有的关系最终都是走向这里
return activeProfile.test(profile);
}
};
}
/**
* 返回一个对指定Profiles进行匹配的匹配器
* {@link ParsedProfiles#matches(Predicate)}
* {@link ProfilesParser#and(Profiles...)}
* {@link ProfilesParser#or(Profiles...)}
* {@link ProfilesParser#not(Profiles)}
* 最终一定会落到{@link ProfilesParser#equals(String)}中
* {@link ProfilesParser#isMatch(Predicate)}
*/
public static Predicate<Profiles> isMatch(Predicate<String> activeProfile) {
return new Predicate() {
@Override
public boolean test(Profiles profiles) {
return profiles.matches(activeProfile);
}
};
}
}
// Profile环境配置的工具类实现类
class ParsedProfiles implements Profiles {
// spring.profiles中写的表达式字符串
public final String[] expressions;
// 解析完成的表达式对象,内部包含环境配置通过表达式描述的关系
public final Profiles[] parsed;
public ParsedProfiles(String[] expressions, Profiles[] parsed) {
this.expressions = expressions;
this.parsed = parsed;
}
/**
* 使用解析好的表达式与激活配置环境的匹配器进行一一匹配
*
* @param activeProfiles 激活配置环境的匹配器
*/
public boolean matches(Predicate<String> activeProfiles) {
// 遍历解析到表达式进行逻辑匹配
for (Profiles candidate : this.parsed) {
// 使用给定的匹配器进行匹配
// 实际上,activeProfiles才是真正进行匹配的条件
// candidate是matches是根据表达式的关系进行逻辑运算,最终通过activeProfiles来处理,得到匹配结果
/**
* {@link ProfilesParser#and(Profiles...)}
* {@link ProfilesParser#or(Profiles...)}
* {@link ProfilesParser#not(Profiles)}
* 最终一定会落到{@link ProfilesParser#equals(String)}中
* {@link ProfilesParser#isMatch(Predicate)}
*/
if (candidate.matches(activeProfiles)) {
return true;
}
}
return false;
}
}
// Profile环境配置的工具类
interface Profiles {
// 解析给定的环境配置表达式
public static Profiles of(String... profiles) {
// 解析spring.profiles的值,因为该值可以是一个表达式
return ProfilesParser.parse(profiles);
}
/**
* 条件匹配
* {@link ParsedProfiles#matches(Predicate)}
* {@link ProfilesParser#and(Profiles...)}
* {@link ProfilesParser#or(Profiles...)}
* {@link ProfilesParser#not(Profiles)}
* 最终一定会落到{@link ProfilesParser#equals(String)}中
* {@link ProfilesParser#isMatch(Predicate)}
*/
boolean matches(Predicate<String> activeProfiles);
}
// 解析完的配置文件,包装为文档类型
class Document {
// 解析到配置文件的所有属性值
public final PropertySource<?> propertySource;
/**
* @see {@link ProfilesParser}
* @see {@link ParsedProfiles#matches(Predicate)}
* 从当前加载的配置文件对应的属性对象中,获取spring.profiles的属性值
* 使用(),&(and),!(not),|(or)
* (dev,pro),在环境对象中,dev和pro只要有一个设置了激活,当前document配置则保留
* dev|pro,和(dev,pro)效果一样
* dev&pro,在环境对对象中,dev和pro都设置了激活的情况下,当前document配置才保留,否则忽略该配置文件属性配置
* !dev ,在环境对象中,dev没有设置激活,则保留当前document配置
* <p>
* 总结: 当配置文件中写了spring.profiles=xxx表达式,则满足这个表达式的条件,该配置文件才会生效,否则会被排除
* 例如: application.properties中配置了spring.profiles = dev&pro,那么,只有dev和pro配置都被激活的情况下,application.properties才会被加载
*/
public String[] profiles;
// 从当前加载的配置文件对应的属性对象中,获取spring.profiles.active的属性值
public final Set<Profile> activeProfiles;
// 从当前加载的配置文件对应的属性对象中,获取spring.profiles.include的属性值
public final Set<Profile> includeProfiles;
public Document(PropertySource<?> propertySource, String[] profiles, Set<Profile> activeProfiles, Set<Profile> includeProfiles) {
this.propertySource = propertySource;
this.profiles = profiles;
this.activeProfiles = activeProfiles;
this.includeProfiles = includeProfiles;
}
// 从当前加载的配置文件对应的属性对象中,获取spring.profiles的属性值
public String[] getProfiles() {
return profiles;
}
// 解析到配置文件的所有属性值
public PropertySource<?> getPropertySource() {
return propertySource;
}
// 从当前加载的配置文件对应的属性对象中,获取spring.profiles.active的属性值
public Set<Profile> getActiveProfiles() {
return activeProfiles;
}
// 从当前加载的配置文件对应的属性对象中,获取spring.profiles.include的属性值
public Set<Profile> getIncludeProfiles() {
return includeProfiles;
}
}
// 带有过滤功能的属性配置
class FilteredPropertySource {
/**
* 执行过滤属性
*
* @param environment 环境对象
* @param propertySourceName 属性配置的名称
* @param filteredProperties 需要过滤的属性集合
* @param operation propertySourceName对应属性值的消费者
*/
public static void apply(ConfigurableEnvironment environment, String propertySourceName, Set<String> filteredProperties, Consumer<PropertySource<?>> operation) {
// 获取环境中所有的配置信息
MutablePropertySources propertySources = environment.getPropertySources();
// 获取指定名称的配置属性
PropertySource<?> original = propertySources.get(propertySourceName);
// 如果不存在对应名称的属性配置
if (original == null) {
// 直接回调消费者的方法,并且传递null给消费者消费
operation.accept(null);
return;
}
// 如果存在对应名称的属性配置,则替换原有的属性配置,使用FilteredPropertySource代替,FilteredPropertySource具有属性过滤的功能
propertySources.replace(propertySourceName, new FilteredPropertySource(original, filteredProperties));
// 将替换之前的配置属性值给消费者消费
operation.accept(original);
// 消费完成之后,再将原来的值替换回来
propertySources.replace(propertySourceName, original);
}
}
}
// 配置文件属性绑定器
class Binder {
// 标记不是Bean的类
public static final Set<Class<?>> NON_BEAN_CLASSES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(Object.class, Class.class)));
// 配置属性数据源,从这里获取数据进行绑定
public final Iterable<ConfigurationPropertySource> sources;
// 占位符解析器
public final PlaceholdersResolver placeholdersResolver;
// 类型转换器
public final ConversionService conversionService;
// 类型转换器
public final Consumer<PropertyEditorRegistry> propertyEditorInitializer;
// 绑定处理器,在绑定过程中的一些生命周期回调接口
public final BindHandler defaultBindHandler;
// 对象绑定器,将属性绑定到对象上的绑定类
public final List<DataObjectBinder> dataObjectBinders;
public Binder(Iterable<ConfigurationPropertySource> sources, PlaceholdersResolver placeholdersResolver, ConversionService conversionService, Consumer<PropertyEditorRegistry> propertyEditorInitializer, BindHandler defaultBindHandler, BindConstructorProvider constructorProvider) {
// 指定要查找的配置属性源
this.sources = sources;
this.placeholdersResolver = (placeholdersResolver != null) ? placeholdersResolver : PlaceholdersResolver.NONE;
this.conversionService = (conversionService != null) ? conversionService : ApplicationConversionService.getSharedInstance();
this.propertyEditorInitializer = propertyEditorInitializer;
// 绑定处理器,在绑定过程中的一些生命周期回调接口
this.defaultBindHandler = (defaultBindHandler != null) ? defaultBindHandler : BindHandler.DEFAULT;
// 构造方法绑定的提供这,因为有的对象只有一个构造方法,并且构造方法的参数可能就是需要绑定的属性
if (constructorProvider == null) {
constructorProvider = BindConstructorProvider.DEFAULT;
}
// 简单的值的对象绑定器
ValueObjectBinder valueObjectBinder = new ValueObjectBinder(constructorProvider);
// JavaBean对象的绑定器
JavaBeanBinder javaBeanBinder = JavaBeanBinder.INSTANCE;
// 保存值对象和JavaBean对象的绑定器
this.dataObjectBinders = Collections.unmodifiableList(Arrays.asList(valueObjectBinder, javaBeanBinder));
}
// 获取可以绑定整个环境对象的所有属性的Binder对象
public void get(Environment environment) {
Iterable<ConfigurationPropertySource> sources = ConfigurationPropertySources.get(environment) {
// 从ConfigurableEnvironment环境对象中获取到所有的属性资源
MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
// 获取附加的配置属性源configurationProperties,上面已经附加过了
ConfigurationPropertySourcesPropertySource attached = (ConfigurationPropertySourcesPropertySource) sources.get(ATTACHED_PROPERTY_SOURCE_NAME);
// 如果没有附加上,
if (attached == null) {
// 返回SpringConfigurationPropertySources
return from(sources) {
return new SpringConfigurationPropertySources(sources);
}
}
// 返回附加配置的源数据
return attached.getSource();
}
// 创建属性占位符解析器
PropertySourcesPlaceholdersResolver placeholdersResolver = new PropertySourcesPlaceholdersResolver(environment);
// 返回对象属性绑定器
// 创建属性绑定对象,该类专门用于绑定ConfigurationPropertySources中的属性
return new Binder(sources, placeholdersResolver, null, null, defaultBindHandler);
}
/**
* 获取当前对象保存的ConfigurationPropertySource: sources属性中的name对应的值,然后绑定到target对象,然后返回BindResult对象
*
* @param name 通过给定的字符串Key,使用"."进行分割,得到分割后的属性元素名称
* @param target 将给定的目标对象类型,包装为Bindable类型,内部会对简单类型进行包装成数组的第一个元素,保存了目标类的原始类型和包装类型
* @param handler 绑定处理器,在绑定过程中的一些生命周期回调接口
* @return 绑定后的结果, 存储了绑定的值的最终结果
*/
public <T> BindResult<T> bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler) {
T bound = bind(name, target, handler, false);
// 将绑定的最终结果封装为BindResul对象
return BindResult.of(bound);
}
/**
* 获取当前对象保存的ConfigurationPropertySource: sources属性中的name对应的值,然后绑定到target对象,然后返回BindResult对象
*
* @param name 通过给定的字符串Key,使用"."进行分割,得到分割后的属性元素名称
* @param target 将给定的目标对象类型,包装为Bindable类型,内部会对简单类型进行包装成数组的第一个元素,保存了目标类的原始类型和包装类型
* @param handler 绑定处理器,在绑定过程中的一些生命周期回调接口
* @return 绑定后的最终结果
*/
public <T> T bindOrCreate(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler) {
return bind(name, target, handler, true);
}
/**
* 绑定并创建,如果绑定的属性不存在,则创建默认值
*
* @param name 通过给定的字符串Key,使用"."进行分割,得到分割后的属性元素名称
* @param target 将给定的目标对象类型,包装为Bindable类型,内部会对简单类型进行包装成数组的第一个元素,保存了目标类的原始类型和包装类型
* @param handler 绑定处理器,在绑定过程中的一些生命周期回调接口
* @return 绑定后的最终结果
*/
public <T> T bindOrCreate(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler) {
return bind(name, target, handler, true);
}
/**
* 获取当前对象保存的ConfigurationPropertySource: sources属性中的name对应的值,然后绑定到target对象,然后返回BindResult对象
*
* @param name 通过给定的字符串Key,使用"."进行分割,得到分割后的属性元素名称
* @param target 将给定的目标对象类型,包装为Bindable类型,内部会对简单类型进行包装成数组的第一个元素,保存了目标类的原始类型和包装类型
* @param handler 绑定处理器,在绑定过程中的一些生命周期回调接口
* @param create 如果绑定的值为空,是否需要创建默认值
* @return 绑定后的最终结果
*/
public <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, boolean create) {
// 如果没有指定BindHandler,则使用默认的BindHandler, BindHandler.DEFAULT
handler = (handler != null) ? handler : this.defaultBindHandler;
// 创建绑定的上下文对象
Context context = new Context();
// 绑定属性,该方法不支持递归绑定属性
return bind(name, target, handler, context, false, create);
}
/**
* @param name 通过给定的字符串Key,使用"."进行分割,得到分割后的属性元素名称
* @param target 将给定的目标对象类型,包装为Bindable类型,内部会对简单类型进行包装成数组的第一个元素,保存了目标类的原始类型和包装类型
* @param handler 绑定处理器,在绑定过程中的一些生命周期回调接口
* @param context 绑定过程中的上下文对象
* @param allowRecursiveBinding 是否允许递归绑定属性
* @param create 如果绑定的值为空,是否需要创建默认值
* @return 绑定后的最终结果
*/
public <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context, boolean allowRecursiveBinding, boolean create) {
// 重置上下文绑定的配置属性
context.clearConfigurationProperty();
try {
// 执行BindHandler的onStart生命周期方法
Bindable<T> replacementTarget = handler.onStart(name, target, context);
// 如果onStart回调将目标对象返回为空了,则直接处理空的结果逻辑
// 因为默认返回的就是target
if (replacementTarget == null) {
return handleBindResult(name, target, handler, context, null, create);
}
// 将onStart回调最终的结果替换原来的目标对象类型
target = replacementTarget;
// 绑定对象,返回绑定后的值
Object bound = bindObject(name, target, handler, context, allowRecursiveBinding);
// 处理绑定结果
return handleBindResult(name, target, handler, context, bound, create);
} catch (Exception ex) {
// 处理绑定异常结果
return handleBindError(name, target, handler, context, ex);
}
}
// 处理绑定的结果,转换为最终的结果对象
public <T> T handleBindResult(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context, Object result, boolean create) throws Exception {
// 如果绑定的结果不为null
if (result != null) {
// 执行BindHandler对象的onSuccess生命周期回调
result = handler.onSuccess(name, target, context, result);
// 对绑定结果进行类型转换,将结果对象转换为目标对象类型,得到最终结果
result = context.getConverter().convert(result, target);
}
// 绑定的结果为null,并且需要给目标类型创建默认值
if (result == null && create) {
// 创建目标类型的实例对象
result = create(target, context);
// 执行BindHandler对象的onCreate生命周期回调
result = handler.onCreate(name, target, context, result);
// 对结果进行类型转换
result = context.getConverter().convert(result, target);
}
// 执行BindHandler对象的onFinish生命周期回调
// 其中,在ValidationBindHandler中,onFinish会给result结果对象进行参数校验
handler.onFinish(name, target, context, result);
// 其他情况,也就是结果为空,并且没有指定要创建默认的实例对象,直接进行类型转换
return context.getConverter().convert(result, target);
}
// 创建目标类型的默认对象
public Object create(Bindable<?> target, Context context) {
// 遍历对象绑定器,调用他们的创建方法,根据目标对象不同使用不同的创建实例的绑定器,默认存在两个
// 前面已经对简单类型做了过滤,只要是简单类型或者java开头的类,或者是Class,Object不绑定
// 下面的只处理剩下的条件
// 1: ValueObjectBinder
// 1.1. 该类不处理枚举,抽象类型
// 1.2. 之后再通过BindConstructorProvider类是否可以提供可用的构造方法
// BindConstructorProvider是一个抽象类,有不同的实现,但是作用都一样
// 就是只会处理构造方法只有一个,并且存在构造参数的情况,才会进行处理
// 2: JavaBeanBinder: ValueObjectBinder不处理的,由JavaBeanBinder创建
// 该类简单粗暴,直接使用默认的构造方法实例化
// 如果没有默认的,又不能被ValueObjectBinder处理,则会抛出异常
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
// 在ValueObjectBinder对象中,
// 在JavaBeanBinder对象中,直接返回实例化
/**
* {@link ValueObjectBinder#create,JavaBeanBinder#create}
*/
Object instance = dataObjectBinder.create(target, context);
// 返回创建的实例
if (instance != null) {
return instance;
}
}
return null;
}
// 属性绑定
public <T> Object bindObject(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context, boolean allowRecursiveBinding) {
// 遍历存储的上下文中的配置属性对象,默认为传递的Binder对象的所有配置属性集合
// 如果是聚合属性,则进行了优化,返回的是缓存在上下文中的配置属性
// 这是在聚合属性绑定的时候使用到,因为聚合属性绑定的对象,绑定的值都在同一个ConfigurationPropertySource中
// 就不需要每次去遍历所有的ConfigurationPropertySource去找,这样费性能
ConfigurationProperty property = findProperty(name, context);
// 如果不存在该属性,或者该key不存在后代属性,并且解析的深度不为0(递归绑定的情况)
if (property == null && containsNoDescendantOf(context.getSources(), name) && context.depth != 0) {
return null;
}
// 获取聚合属性绑定器,绑定数组,集合,Map的绑定类
// 如果不是聚合类型,返回null
AggregateBinder<?> aggregateBinder = getAggregateBinder(target, context);
// 聚合属性绑定器
if (aggregateBinder != null) {
// 绑定聚合属性
return bindAggregate(name, target, handler, context, aggregateBinder);
}
// 如果使用该key找到了属性
if (property != null) {
try {
// 绑定属性,返回需要绑定的属性的最终转换后的值,但是还没有绑定
return bindProperty(target, context, property);
} catch (ConverterNotFoundException ex) {
// 如果属性绑定出现异常,出现异常都是因为类型转换失败,所以再尝试一下对将整个对象重新进行绑定
Object instance = bindDataObject(name, target, handler, context, allowRecursiveBinding);
// 对象绑定成功,返回绑定成功的对象
if (instance != null) {
return instance;
}
// 否则抛出异常
throw ex;
}
}
// 数据对象绑定,将整个对象进行递归绑定
return bindDataObject(name, target, handler, context, allowRecursiveBinding);
}
// 获取聚合属性绑定器
public AggregateBinder<?> getAggregateBinder(Bindable<?> target, Context context) {
// 需要绑定的类型
Class<?> resolvedType = target.getType().resolve(Object.class);
// 如果绑定的类型是Map
if (Map.class.isAssignableFrom(resolvedType)) {
// 返回Map对应的绑定器
return new MapBinder(context);
}
// 如果是集合,返回集合对应的绑定器
if (Collection.class.isAssignableFrom(resolvedType)) {
return new CollectionBinder(context);
}
// 如果是数组,返回对应的数组绑定器
if (target.getType().isArray()) {
return new ArrayBinder(context);
}
// 不是聚合属性,返回null
return null;
}
// 绑定聚合属性
public <T> Object bindAggregate(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context, AggregateBinder<?> aggregateBinder) {
// 创建一个回调,用于聚合属性绑定
AggregateElementBinder elementBinder = (ConfigurationPropertyName itemName, Bindable<?> itemTarget, ConfigurationPropertySource source) -> {
// 是否支持递归绑定,aggregateBinder是一个抽象类,其中有Array,Collection,Map的绑定器,而Array,Collection又继承IndexAggregateBinder
// 当为Map的时候,允许递归绑定
// 当为IndexAggregateBinder的时候,则需要判断该属性数据源是不是可迭代的IterableConfigurationPropertySource类型
boolean allowRecursiveBinding = aggregateBinder.isAllowRecursiveBinding(source);
// 给定一个需要返回绑定结果对象的回调,可以获取到绑定成功之后的对象
// 该回调就是对聚合属性进行对象绑定
Supplier<?> supplier = () -> bind(itemName, itemTarget, handler, context, allowRecursiveBinding, false);
// 记录正在绑定的属性配置源并进行绑定
return context.withSource(source, supplier);
};
// 记录深度并绑定聚合属性
return context.withIncreasedDepth(() -> aggregateBinder.bind(name, target, elementBinder));
}
/**
* 查找属性是否存在
*
* @param name 属性名称
* @param context 绑定上下文
* @return 找到的属性的ConfigurationProperty对象
*/
public ConfigurationProperty findProperty(ConfigurationPropertyName name, Context context) {
// 如果不存在名称,不存在任何key
if (name.isEmpty()) {
return null;
}
// 遍历存储的上下文中的配置属性对象,默认为传递的Binder对象的所有配置属性集合
// 如果是聚合属性,则进行了优化,返回的是缓存在上下文中的配置属性
// 这是在聚合属性绑定的时候使用到,因为聚合属性绑定的对象,绑定的值都在同一个ConfigurationPropertySource中
// 就不需要每次去遍历所有的ConfigurationPropertySource去找,这样费性能
for (ConfigurationPropertySource source : context.getSources()) {
// 查找属性配置中是否存在该key的配置
ConfigurationProperty property = source.getConfigurationProperty(name);
// 如果存在,表示存在该属性值
if (property != null) {
return property;
}
}
return null;
}
/**
* 处理绑定异常
*/
public <T> T handleBindError(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context, Exception error) {
try {
// 执行BindHandler的onFailure回调
Object result = handler.onFailure(name, target, context, error);
// 对异常结果进行类型转换
return context.getConverter().convert(result, target);
} catch (Exception ex) {
// 如果异常回调没有处理或者再出问题,则抛出异常
throw new BindException(name, target, context.getConfigurationProperty(), ex);
}
}
/**
* 绑定属性,返回需要绑定的属性的最终转换后的值,但是还没有绑定
*/
public <T> Object bindProperty(Bindable<T> target, Context context, ConfigurationProperty property) {
// 将找到的对应key的属性值保存到上下文中
context.setConfigurationProperty(property);
// 获取属性的值
Object result = property.getValue();
// 解析占位符表达式
result = this.placeholdersResolver.resolvePlaceholders(result);
// 对属性值进行类型转换
result = context.getConverter().convert(result, target);
// 返回最终需要绑定的结果
return result;
}
// 数据对象绑定,将整个对象进行递归绑定
public Object bindDataObject(ConfigurationPropertyName name, Bindable<?> target, BindHandler handler, Context context, boolean allowRecursiveBinding) {
// 如果是不能绑定的Bean对象,就不绑定
// java内部的类,简单类型,Class类型,Object类型不能绑定
if (isUnbindableBean(name, target, context)) {
return null;
}
// 获取目标类型
Class<?> type = target.getType().resolve(Object.class);
// 如果不支持递归绑定,直接返回,如果当前整个上下文已经在绑定属性,则isBindingDataObject返回true
if (!allowRecursiveBinding && context.isBindingDataObject(type)) {
return null;
}
// 创建一个数据对象属性的绑定器,用于递归绑定属性中的属性
// 因为当前绑定的对象是一个内部还有属性的对象,所以还需要绑定当前对象内部的属性
// 绑定操作就是一个递归操作,属性对象内可能还有属性
DataObjectPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName), propertyTarget, handler, context, false, false);
// 给定一个需要返回绑定结果对象的回调,可以获取到绑定成功之后的对象
Supplier supplier = () -> {
// 遍历所有的数据对象绑定器
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
/**
* {@link JavaBeanBinder,ValueObjectBinder}
*/
Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
// 返回绑定好的实例对象
if (instance != null) {
return instance;
}
}
return null;
}
// 开始执行数据绑定
return context.withDataObject(type, supplier);
}
// Map类型属性的绑定
class MapBinder extends AggregateBinder<Map<Object, Object>> {
// 最终绑定的结果
public static final Bindable<Map<String, String>> STRING_STRING_MAP = Bindable.mapOf(String.class, String.class);
protected Object bindAggregate(ConfigurationPropertyName name, Bindable<?> target, AggregateElementBinder elementBinder) {
// 根据绑定的目标类型创建对应的Map对象
Map<Object, Object> map = CollectionFactory.createMap((target.getValue() != null) ? Map.class : target.getType().resolve(Object.class), 0);
//处理目标类型,如果是Properties,返回STRING_STRING_MAP对象,其他的不处理
Bindable<?> resolvedTarget = resolveTarget(target);
// 是否存在子属性
boolean hasDescendants = hasDescendants(name);
// 遍历存储的上下文中的配置属性对象,默认为传递的Binder对象的所有配置属性集合
// 如果是聚合属性,则进行了优化,返回的是缓存在上下文中的配置属性
// 这是在聚合属性绑定的时候使用到,因为聚合属性绑定的对象,绑定的值都在同一个ConfigurationPropertySource中
// 就不需要每次去遍历所有的ConfigurationPropertySource去找,这样费性能
for (ConfigurationPropertySource source : getContext().getSources()) {
if (!ConfigurationPropertyName.EMPTY.equals(name)) {
// 查找属性配置中是否存在该key的配置
ConfigurationProperty property = source.getConfigurationProperty(name);
// 如果存在属性,并且不存在子属性,直接使用该值进行类型转换并返回
if (property != null && !hasDescendants) {
return getContext().getConverter().convert(property.getValue(), target);
}
// 将属性配置源对象转换为可进行过滤的属性配置源对象
// 这样,再原来基础上的配置数据源同时有过滤的功能
source = source.filter(name::isAncestorOf);
}
// 创建Map元素绑定器
EntryBinder binder = new EntryBinder(name, resolvedTarget, elementBinder);
// 绑定键值对到创建的map元素中
binder.bindEntries(source, map);
}
// 如果没有绑定到元素,返回空,绑定到了,返回绑定完成的map
return map.isEmpty() ? null : map;
}
// 处理目标类型
public Bindable<?> resolveTarget(Bindable<?> target) {
// 如果是Properties,返回STRING_STRING_MAP对象,其他的不处理
Class<?> type = target.getType().resolve(Object.class);
if (Properties.class.isAssignableFrom(type)) {
return STRING_STRING_MAP;
}
return target;
}
// 是否可以循环绑定
protected boolean isAllowRecursiveBinding(ConfigurationPropertySource source) {
return true;
}
}
// Map中键值对的绑定器
public class EntryBinder {
// 配置的根Key
public final ConfigurationPropertyName root;
// 元素绑定器,就是递归绑定
public final AggregateElementBinder elementBinder;
// Map类型
public final ResolvableType mapType;
// Map的Key的类型
public final ResolvableType keyType;
// Map的Value类型
public final ResolvableType valueType;
EntryBinder(ConfigurationPropertyName root, Bindable<?> target, AggregateElementBinder elementBinder) {
this.root = root;
this.elementBinder = elementBinder;
this.mapType = target.getType().asMap();
this.keyType = this.mapType.getGeneric(0);
this.valueType = this.mapType.getGeneric(1);
}
// 绑定键值对
public void bindEntries(ConfigurationPropertySource source, Map<Object, Object> map) {
if (source instanceof IterableConfigurationPropertySource) {
// 遍历所有属性
for (ConfigurationPropertyName name : (IterableConfigurationPropertySource) source) {
// 获取绑定值的类型
Bindable<?> valueBindable = getValueBindable(name);
// 获取需要绑定到Map元素的Key
// 通过下面算法,找到需要保存的map中的key,要一层一层剥开这些key,来存储
ConfigurationPropertyName entryName = getEntryName(source, name);
// 获取到该名称去除根key的属性名name
// 说白了就是map的key要一层一层拨开存入,luck.id => {"luck":{"id":1}}
String keyName = getKeyName(entryName);
// 使用类型转换器,将key的类型转换为Map中key的类型
Object key = getContext().getConverter().convert(keyName, this.keyType);
// 递归执行元素绑绑定,然后将绑定结果保存到给定的结果map中
/**
* {@link Binder#bindAggregate}
*/
map.computeIfAbsent(key, (k) -> this.elementBinder.bind(entryName, valueBindable));
}
}
}
// 获取需要绑定到Map元素的Key
// 通过下面算法,找到需要保存的map中的key,要一层一层剥开这些key,来存储
public ConfigurationPropertyName getEntryName(ConfigurationPropertySource source, ConfigurationPropertyName name) {
// 获取值的类型
Class<?> resolved = this.valueType.resolve(Object.class);
// 如果是集合或者数组
if (Collection.class.isAssignableFrom(resolved) || this.valueType.isArray()) {
// 切割key,因为当前key不是在上一层的key中,那么就要回到上一层的key在进行操作
// 内部就是调用name.chop,区别只是遍历,找一个就可以
return chopNameAtNumericIndex(name);
}
// 如果当前根Key不是给定属性名称的上一层key
// 再判断该值是否允许嵌套映射,如果允许嵌套映射,或者该类是一个非标量类
// isScalarValue: 只有Map中值的类型是java.lang包下或者是枚举,并且配置属性中的值还可以进行类型转换为目标值对象,才是标量
if (!this.root.isParentOf(name) && (isValueTreatedAsNestedMap() || !isScalarValue(source, name))) {
// 切割key,因为当前key不是在上一层的key中,那么就要回到上一层的key在进行操作
return name.chop(this.root.getNumberOfElements() + 1);
}
// 返回给定的key名称
return name;
}
// 获取到该名称去除根key的name
// root: 根key只有一层 例如: luck
// name: 当前key的名称的层数 luck.id
// 在name的完整key中,luck.id元素保存方式
// [0,6] 所有用"."拼接的key的起始位集合,分别为第一组key的起始位置和第一组key的结束位置
// [4,8] 例如:luck => (0-4) id => (6,8)
// 因此,name.getElement(i, Form.ORIGINAL)就是获取第几组元素的位置,然后就知道名称
// 结果为: id
public String getKeyName(ConfigurationPropertyName name) {
StringBuilder result = new StringBuilder();
// root: 根key只有一层 例如: luck
// name: 当前key的名称的层数 luck.id
for (
int i = this.root.getNumberOfElements(); i < name.getNumberOfElements(); i++) {
// 如果有多层,使用.分割
if (result.length() != 0) {
result.append('.');
}
// 获取到该名称去除根key的name
// root: 根key只有一层 例如: luck
// name: 当前key的名称的层数 luck.id
// 在name的完整key中,luck.id元素保存方式
// [0,6] 所有用"."拼接的key的起始位集合,分别为第一组key的起始位置和第一组key的结束位置
// [4,8] 例如:luck => (0-4) id => (6,8)
// 因此,name.getElement(i, Form.ORIGINAL)就是获取第几组元素的位置,然后就知道名称
// 结果为: id
result.append(name.getElement(i, Form.ORIGINAL));
}
return result.toString();
}
// 获取绑定值的类型
public Bindable<?> getValueBindable(ConfigurationPropertyName name) {
// 如果当前根Key不是给定属性名称的上一层key,并且该值是否允许嵌套映射,则当前绑定的值又是一个Map类型
if (!this.root.isParentOf(name) && isValueTreatedAsNestedMap()) {
return Bindable.of(this.mapType);
}
// 否则返回值的类型
return Bindable.of(this.valueType);
}
/**
* 是否是标量值,只有Map中值的类型是java.lang包下或者是枚举,并且配置属性中的值还可以进行类型转换为目标值对象,才是标量
*/
public boolean isScalarValue(ConfigurationPropertySource source, ConfigurationPropertyName name) {
// 获取值的类型
Class<?> resolved = this.valueType.resolve(Object.class);
// 如果值不是java.lang,而且还不是枚举,表示该类型不是标量类型
if (!resolved.getName().startsWith("java.lang") && !resolved.isEnum()) {
return false;
}
// 如果是java.lang包下的类,或者是枚举,从配置属性中获取对应key的值
ConfigurationProperty property = source.getConfigurationProperty(name);
// 如果不存在,表示不是标量值
if (property == null) {
return false;
}
// 如果存在配置值
Object value = property.getValue();
// 先进行占位符解析
value = getContext().getPlaceholdersResolver().resolvePlaceholders(value);
// 使用类型转换器可以将解析的值转换为Map中value的值类型,表示该值是一个标量值
return getContext().getConverter().canConvert(value, this.valueType);
}
}
// 可以索引绑定的类型属性的绑定
class IndexedElementsBinder<T> extends AggregateBinder<T> {
// 开始进行下标绑定
protected final void bindIndexed(ConfigurationPropertyName name, Bindable<?> target, AggregateElementBinder elementBinder, ResolvableType aggregateType, ResolvableType elementType, IndexedCollectionSupplier result) {
// 遍历存储的上下文中的配置属性对象,默认为传递的Binder对象的所有配置属性集合
// 如果是聚合属性,则进行了优化,返回的是缓存在上下文中的配置属性
// 这是在聚合属性绑定的时候使用到,因为聚合属性绑定的对象,绑定的值都在同一个ConfigurationPropertySource中
// 就不需要每次去遍历所有的ConfigurationPropertySource去找,这样费性能
for (ConfigurationPropertySource source : getContext().getSources()) {
// 使用下标进行绑定
bindIndexed(source, name, target, elementBinder, result, aggregateType, elementType);
// 如果绑定成功,直接结束
if (result.wasSupplied() && result.get() != null) {
return;
}
}
}
// 查找属性值是否存在,如果存在,直接绑定值,不存在则需要根据下标绑定
public void bindIndexed(ConfigurationPropertySource source, ConfigurationPropertyName root, Bindable<?> target, AggregateElementBinder elementBinder, IndexedCollectionSupplier collection, ResolvableType aggregateType, ResolvableType elementType) {
// 查找属性配置中是否存在该key的配置
ConfigurationProperty property = source.getConfigurationProperty(root);
// 如果存在key对应的值
if (property != null) {
// 如果存在属性值,直接进行值绑定
// 这种情况就是string类型的数据,例如 dev,test,使用key确实可以获取到值,但是实际要接收的是数组
// 所以需要进行转换并绑定
bindValue(target, collection.get(), aggregateType, elementType, property.getValue());
} else {
// 获取配置属性的值,进行下标绑定
bindIndexed(source, root, elementBinder, collection, elementType);
}
}
// 如果存在属性值,直接进行值绑定
// 这种情况就是string类型的数据,例如 dev,test,使用key确实可以获取到值,但是实际要接收的是数组
// 所以需要进行转换并绑定
public void bindValue(Bindable<?> target, Collection<Object> collection, ResolvableType aggregateType, ResolvableType elementType, Object value) {
// 如果值为String类型吧况且是空的,不绑定
if (value instanceof String && !StringUtils.hasText((String) value)) {
return;
}
// 对stinrg的元素值进行类型转换,转换为给定的聚合类型
// 使用","等等分割,转让为聚合类型
Object aggregate = convert(value, aggregateType, target.getAnnotations());
// 获取带泛型集合的解析类型
ResolvableType collectionType = ResolvableType.forClassWithGenerics(collection.getClass(), elementType);
// 再将元素转换为带有泛型的集合类型
Collection<Object> elements = convert(aggregate, collectionType);
// 将转换后的集合元素保存
collection.addAll(elements);
}
// 正式开启下标绑定
public void bindIndexed(ConfigurationPropertySource source, ConfigurationPropertyName root, AggregateElementBinder elementBinder, IndexedCollectionSupplier collection, ResolvableType elementType) {
// 从属性配置文件中,获取这个key对应的多个值
MultiValueMap<String, ConfigurationProperty> knownIndexedChildren = getKnownIndexedChildren(source, root);
// 遍历配置文件key对应的所有的值
for (int i = 0; i < Integer.MAX_VALUE; i++) {
// 拼接属性名 luck.names[0] luck.names[i]
ConfigurationPropertyName name = root.append((i != 0) ? "[" + i + "]" : INDEX_ZERO);
/**
* 使用元素绑定器进行属性绑定,获取绑定的属性值
* {@link Binder#bindAggregate}
*/
Object value = elementBinder.bind(name, Bindable.of(elementType), source);
// 如果绑定失败
if (value == null) {
break;
}
// 绑定成功,删除元素
knownIndexedChildren.remove(name.getLastElement(Form.UNIFORM));
// 将需要绑定的属性添加到集合中
collection.get().add(value);
}
// 如果上面有元素失败,则抛出子元素绑定异常
assertNoUnboundChildren(knownIndexedChildren);
}
// 是否可以循环绑定
protected boolean isAllowRecursiveBinding(ConfigurationPropertySource source) {
return source == null || source instanceof IterableConfigurationPropertySource;
}
}
// 集合类型绑定
class CollectionBinder extends IndexedElementsBinder<Collection<Object>> {
protected Object bindAggregate(ConfigurationPropertyName name, Bindable<?> target, AggregateElementBinder elementBinder) {
// 获取到绑定的集合类型
Class<?> collectionType = (target.getValue() != null) ? List.class : target.getType().resolve(Object.class);
// 获取带有泛型的目标聚合类型
ResolvableType aggregateType = ResolvableType.forClassWithGenerics(List.class, target.getType().asCollection().getGenerics());
// 获取到集合中的元素类型
ResolvableType elementType = target.getType().asCollection().getGeneric();
// 创建一个返回Collection的Supplier对象
IndexedCollectionSupplier result = new IndexedCollectionSupplier(() -> CollectionFactory.createCollection(collectionType, elementType.resolve(), 0));
// 进行属性下标绑定
bindIndexed(name, target, elementBinder, aggregateType, elementType, result);
// 如果存在Supplier对象,上面传递了ArrayList::new,创建ArrayList对象
// 并且执行了bindIndexed进行元素绑定了
// 获取绑定后的元素集合,因为数组是不可变的,所以只能先用集合代替,最终转换为数组
if (result.wasSupplied()) {
// 返回绑定结果
return result.get();
}
return null;
}
}
// 数组类型绑定
class ArrayBinder extends IndexedElementsBinder<Object> {
// 绑定聚合属性
protected Object bindAggregate(ConfigurationPropertyName name, Bindable<?> target, AggregateElementBinder elementBinder) {
// 创建一个返回ArrayList的Supplier对象
IndexedCollectionSupplier result = new IndexedCollectionSupplier(ArrayList::new);
// 获取聚合类型
ResolvableType aggregateType = target.getType();
// 获取聚合类型中的元素类型
ResolvableType elementType = target.getType().getComponentType();
// 进行属性下标绑定
bindIndexed(name, target, elementBinder, aggregateType, elementType, result);
// 如果存在Supplier对象,上面传递了ArrayList::new,创建ArrayList对象
// 并且执行了bindIndexed进行元素绑定了
// 获取绑定后的元素集合,因为数组是不可变的,所以只能先用集合代替,最终转换为数组
if (result.wasSupplied()) {
// 获取绑定后的元素集合,因为数组是不可变的,所以只能先用集合代替,最终转换为数组
List<Object> list = (List<Object>) result.get();
// 根据元素类型和绑定的大小创建数组
Object array = Array.newInstance(elementType.resolve(), list.size());
// 将绑定到集合中的元素放到数组中
for (int i = 0; i < list.size(); i++) {
Array.set(array, i, list.get(i));
}
// 返回数组对象
return array;
}
return null;
}
}
// 配置属性的源信息
public static class ConfigurationPropertySource {
// 从配置属性中获取指定名称的属性值对象
// 获取配置属性对象,下面源码是核心的源码
public ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {
// 获取属性名称
String propertySourceName = mapping.getPropertySourceName();
// 从属性配置中获取对应属性名称对应的值
Object value = getPropertySource().getProperty(propertySourceName);
// 如果没有找到属性值,则继续找下一个配置属性来查找
if (value == null) {
continue;
}
// 获取ConfigurationPropertyName对象
ConfigurationPropertyName configurationPropertyName = mapping.getConfigurationPropertyName();
// 将当前找到的属性源对象和属性名对象保存到Origin中
// 就是记录当前属性的值是出自哪里
Origin origin = PropertySourceOrigin.get(this.propertySource, propertySourceName);
// 返回ConfigurationProperty对象
return ConfigurationProperty.of(configurationPropertyName, value, origin);
}
}
// 绑定的上下文
public static class Context {
// 当前对象绑定的深度
public int depth;
// 当前对象从哪个ConfigurationPropertySource中获取属性进行绑定
public final List<ConfigurationPropertySource> source = Arrays.asList((ConfigurationPropertySource) null);
public int sourcePushCount;
// 正在进行数据绑定的对象类型
public final Deque<Class<?>> dataObjectBindings = new ArrayDeque<>();
// 正在进行构造绑定的类型
public final Deque<Class<?>> constructorBindings = new ArrayDeque<>();
// 当前正在绑定的属性配置信息,内部包含当前绑定的key,绑定的值,该属性的来源信息
public ConfigurationProperty configurationProperty;
/**
* 开始执行数据绑定
*
* @param type 正在绑定的类型
* @param supplier 提供获取绑定成功之后结果的回调,在内部实现绑定,并且返回绑定结果
* @return
*/
public <T> T withDataObject(Class<?> type, Supplier<T> supplier) {
// 记录正在绑定的对象类型
this.dataObjectBindings.push(type);
// 记录递归绑定的深度+1
increaseDepth();
// 记录深度并绑定
T res = withIncreasedDepth(supplier);
// 绑定完成,深度-1
decreaseDepth();
// 删除正在绑定的对象类型
this.dataObjectBindings.pop();
// 返回绑定的结果
return res;
}
/**
* 是否是正在绑定的对象类型
*/
public boolean isBindingDataObject(Class<?> type) {
return this.dataObjectBindings.contains(type);
}
// 保存正在进行构造绑定的类型
public void pushConstructorBoundTypes(Class<?> value) {
this.constructorBindings.push(value);
}
// 青储正在构造绑定的类型
public void popConstructorBoundTypes() {
this.constructorBindings.pop();
}
// 是否存在嵌套绑定
public boolean isNestedConstructorBinding() {
return !this.constructorBindings.isEmpty();
}
// 清空正在绑定的属性信息
public void clearConfigurationProperty() {
this.configurationProperty = null;
}
// 获取当前正在绑定的对象从哪个ConfigurationPropertySource中获取属性绑定
public Iterable<ConfigurationPropertySource> getSources() {
// 如果是聚合属性的绑定操作,获取保存在上下文中的配置属性对象
if (this.sourcePushCount > 0) {
// 这是在聚合属性绑定的时候使用到,因为聚合属性绑定的对象,绑定的值都在同一个ConfigurationPropertySource中
// 就不需要每次去遍历所有的ConfigurationPropertySource去找,这样费性能
return this.source;
}
// 否则返会保存在Binder对象中的属性对象
return Binder.this.sources;
}
// 记录正在绑定的属性配置源并进行绑定
public <T> T withSource(ConfigurationPropertySource source, Supplier<T> supplier) {
// 如何没有提供配置数据源
if (source == null) {
// 直接回调属性的绑定操作,返回绑定成功的结果
// Supplier<?> supplier = () -> bind(itemName, itemTarget, handler, context, allowRecursiveBinding, false);
return supplier.get();
}
// 保存当前正在绑定的配置属性对象,这是一个优化操作
// 这是在聚合属性绑定的时候使用到,因为聚合属性绑定的对象,绑定的值都在同一个ConfigurationPropertySource中
// 就不需要每次去遍历所有的ConfigurationPropertySource去找,这样费性能
this.source.set(0, source);
/**
* {@link Context#getSources}
*/
// 记录集合属性绑定的深度+1
this.sourcePushCount++;
// 回调属性的绑定操作,返回绑定成功的结果
// Supplier<?> supplier = () -> bind(itemName, itemTarget, handler, context, allowRecursiveBinding, false);
T res = supplier.get();
// 绑定成功,减少聚合属性绑定的深度-1
this.sourcePushCount--;
// 返回绑定结果
return res;
}
// 记录深度并绑定
public <T> T withIncreasedDepth(Supplier<T> supplier) {
// 增加深度+1
this.depth++;
// 回调绑定操作,这个回调是处理对象,或者聚合属性的绑定操作
T res = supplier.get();
// 绑定成功,深度-1
this.depth--;
// 返回绑定结果
return res;
}
}
// 属性配置的值ConfigurationProperty
public class ConfigurationProperty {
// 属性名
public final ConfigurationPropertyName name;
// 属性值
public final Object value;
// 属性的原始对象
public final Origin origin;
class Origin {
// 属性对应的配置属性集合
public final PropertySource<?> propertySource;
// 属性名称
public final String propertyName;
}
}
// 1: ValueObjectBinder
// 1.1. 该类不处理枚举,抽象类型
// 1.2. 之后再通过BindConstructorProvider类是否可以提供可用的构造方法
// BindConstructorProvider是一个抽象类,有不同的实现,但是作用都一样
// 就是只会处理构造方法只有一个,并且存在构造参数的情况,才会进行处理
// 2: JavaBeanBinder: ValueObjectBinder不处理的,由JavaBeanBinder创建
// 该类简单粗暴,直接使用默认的构造方法实例化
// 如果没有默认的,又不能被ValueObjectBinder处理,则会抛出异常
class JavaBeanBinder implements DataObjectBinder {
// 单例对象
public static final JavaBeanBinder INSTANCE = new JavaBeanBinder();
/**
* JavaBean对象绑定
*
* @param name 属性对应的key
* @param target 需要绑定的JavaBean对象类型
* @param context 绑定上下文信息
* @param propertyBinder 对于该JavaBean中内部的属性的绑定器
* @return 绑定后JavaBean对象
*/
public <T> T bind(ConfigurationPropertyName name, Bindable<T> target, Context context, DataObjectPropertyBinder propertyBinder) {
// 是否找到了可以绑定的属性
boolean hasKnownBindableProperties = target.getValue() != null && hasKnownBindableProperties(name, context);
// 生成目标JavaBean的类描述信息,就是可以反射操作该JavaBean的信息
Bean<T> bean = Bean.get(target, hasKnownBindableProperties);
// 如果没有给定JavaBean的实例对象,并且该JavaBean不可以实例化就不能绑定
if (bean == null) {
return null;
}
// 获取JavaBean对象的实例对象提供者,会返回一个JavaBean的对象
BeanSupplier<T> beanSupplier = bean.getSupplier(target);
// 开始给该JavaBean进行绑定
boolean bound = bind(propertyBinder, bean, beanSupplier);
// 如果绑定成功,返回该JavaBean对象的实例,否则返回false
return (bound ? beanSupplier.get() : null);
}
/**
* 绑定给定的JavaBean对象
*
* @param beanSupplier JavaBean对象的提供者,会提供该JavaBean的实例对象
* @param propertyBinder 对该JavaBean内部属性的绑定器
* @param bean 该JavaBean的描述信息(反射信息)
* @return 是否绑定成功
*/
public <T> boolean bind(DataObjectPropertyBinder propertyBinder, Bean<T> bean, BeanSupplier<T> beanSupplier) {
boolean bound = false;
// 遍历该JavaBean中缓存的所有属性值
for (BeanProperty beanProperty : bean.getProperties().values()) {
// 遍历所有的属性,一一绑定
bound |= bind(beanSupplier, propertyBinder, beanProperty);
}
return bound;
}
/**
* 绑定JavaBean中的属性
*
* @param beanSupplier JavaBean对象的提供者,会提供该JavaBean的实例对象
* @param propertyBinder 对该JavaBean内部属性的绑定器
* @param property 该JavaBean中内部属性的描述信息(反射信息)
* @return 是否绑定成功
*/
public <T> boolean bind(BeanSupplier<T> beanSupplier, DataObjectPropertyBinder propertyBinder, BeanProperty property) {
// 获取属性名和属性类型
String propertyName = property.getName();
ResolvableType type = property.getType();
// 执行该JavaBean的get方法,返回获取的值
Supplier<Object> value = property.getValue(beanSupplier);
// 获取属性注解
Annotation[] annotations = property.getAnnotations();
// 使用对象的属性绑定器对该JavaBean中内部的所有属性进行绑定
// 实际上就是对内部的属性进行递归绑定
// propertyBinder的源码上下,使用上一次对象的名称+当前正在绑定的属性名称的进行递归绑定
// DataObjectPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName),propertyTarget, handler, context, false, false);
// 最终返回绑定后的属性结果对象
// 例如 A.b ==> 绑定a.b的时候,返回的是B对象
Object bound = propertyBinder.bindProperty(propertyName, Bindable.of(type).withSuppliedValue(value).withAnnotations(annotations));
// 该属性没有绑定到值
if (bound == null) {
// 绑定失败
return false;
}
// 获取到绑定的属性对象的值,并且存在set方法
if (property.isSettable()) {
// 调用set方法,设置属性值
property.setValue(beanSupplier, bound);
}
// 如果属性没有set方法,抛出异常
else if (value == null || !bound.equals(value.get())) {
throw new IllegalStateException("No setter found for property: " + property.getName());
}
return true;
}
// 描述一个JavaBean的类信息
class Bean {
// 一个JavaBean信息的缓存
public static Bean<?> cached;
// 当前Bean封装的ResolvableType类型
public final ResolvableType type;
// 当前Bean的解析类型,它正常情况都与type.getType一样,就是有一些特殊情况下,会对原始类型进行转换一下
// 所以它是解析后的类型,可以理解为就是该JavaBean的对象的类型
public final Class<?> resolvedType;
// 当前JavaBean的所有属性
public final Map<String, BeanProperty> properties = new LinkedHashMap<>();
Bean(ResolvableType type, Class<?> resolvedType) {
this.type = type;
this.resolvedType = resolvedType;
// 初始化该JavaBean的所有属性
addProperties(resolvedType);
}
// 初始化该JavaBean的所有属性
public void addProperties(Class<?> type) {
while (type != null && !Object.class.equals(type)) {
// 所有方法
Method[] declaredMethods = type.getDeclaredMethods();
// 所有字段
Field[] declaredFields = type.getDeclaredFields();
// 缓存该JavaBea的所有方法和字段信息
addProperties(declaredMethods, declaredFields);
// 解析父类
type = type.getSuperclass();
}
}
// 是否是符合条件的方法
// 私有的,Protected,Abstract,Static,Object的方法,Class的方法,代理方法都不满足条件
public boolean isCandidate(Method method) {
int modifiers = method.getModifiers();
// 私有的,Protected,Abstract,Static,Object的方法,Class的方法,代理方法都不满足条件
return !Modifier.ispublic(modifiers) && !Modifier.isProtected(modifiers) && !Modifier.isAbstract(modifiers)
&& !Modifier.isStatic(modifiers) && !Object.class.equals(method.getDeclaringClass())
&& !Class.class.equals(method.getDeclaringClass()) && method.getName().indexOf('$') == -1;
}
// 缓存该JavaBea的所有方法和字段信息
protected void addProperties(Method[] declaredMethods, Field[] declaredFields) {
for (int i = 0; i < declaredMethods.length; i++) {
if (!isCandidate(declaredMethods[i])) {
// 将该方法过滤
declaredMethods[i] = null;
}
}
// 找get/is方法,缓存到this.properties中
for (Method method : declaredMethods) {
addMethodIfPossible(method, "get", 0, BeanProperty::addGetter);
addMethodIfPossible(method, "is", 0, BeanProperty::addGetter);
}
// 找set方法,缓存到this.properties中
for (Method method : declaredMethods) {
addMethodIfPossible(method, "set", 1, BeanProperty::addSetter);
}
// 添加字段,缓存到this.properties中
for (Field field : declaredFields) {
addField(field);
}
}
// 获取JavaBean对象的实例对象提供者,会返回一个JavaBean的对象
public BeanSupplier<T> getSupplier(Bindable<T> target) {
return new BeanSupplier<>(() -> {
T instance = null;
// 如果存在JavaBean实例对象Supplier
if (target.getValue() != null) {
// 获取Supplier的JavaBean实例对象的值
instance = target.getValue().get();
}
// 如果给定了一个空的BeanSupplier,并没有在BeanSupplier返回JavaBean对象
if (instance == null) {
// 实例化该JavaBean对象
instance = (T) BeanUtils.instantiateClass(this.resolvedType);
}
// 返回JavaBean对象实例
return instance;
});
}
/**
* 获取JavaBean的包装类型Bean对象
*
* @param bindable 需要绑定的JavaBean对象的封装
* @param canCallGetValue 是否找到了可以绑定的属性值
*/
public static <T> Bean<T> get(Bindable<T> bindable, boolean canCallGetValue) {
// 获取JavaBean的类型
ResolvableType type = bindable.getType();
// 获取JavaBean的解析后的类型
Class<?> resolvedType = type.resolve(Object.class);
// 获取当前JavaBean对象的值
Supplier<T> value = bindable.getValue();
// JavaBean实例对象
T instance = null;
// 如果该对象找到了可以绑定的值,并且该JavaBean对象也不为空
if (canCallGetValue && value != null) {
// 获取到JavaBean对象
instance = value.get();
// 解析类型修改为真实类型(实例对象类型)
resolvedType = (instance != null) ? instance.getClass() : resolvedType;
}
// 如果JavaBean的实例对象为空,并且不可以实例化就不处理
if (instance == null && !isInstantiable(resolvedType)) {
return null;
}
// 是否存在该JavaBean的缓存的Bean信息
Bean<?> bean = Bean.cached;
// 如果没有缓存,或者需要绑定的类型与解析后的类型不是同一种类型
// 这两种情况都要重新缓存最新的JavaBean的类字段方法等信息
if (bean == null || !bean.isOfType(type, resolvedType)) {
// 创建Java的类描述信息对象
bean = new Bean<>(type, resolvedType);
// 缓存该Bean信息
cached = bean;
}
return (Bean<T>) bean;
}
}
// JavaBean的属性信息
public static class BeanProperty {
// 属性名
public final String name;
// 属性对应的JavaBean的类型
public final ResolvableType declaringClassType;
// 属性的get方法
public Method getter;
// 属性的set方法
public Method setter;
// 属性的字段信息
public Field field;
}
}
// 1: ValueObjectBinder
// 1.1. 该类不处理枚举,抽象类型
// 1.2. 之后再通过BindConstructorProvider类是否可以提供可用的构造方法
// BindConstructorProvider是一个抽象类,有不同的实现,但是作用都一样
// 就是只会处理构造方法只有一个,并且存在构造参数的情况,才会进行处理
// 2: JavaBeanBinder: ValueObjectBinder不处理的,由JavaBeanBinder创建
// 该类简单粗暴,直接使用默认的构造方法实例化
// 如果没有默认的,又不能被ValueObjectBinder处理,则会抛出异常
class ValueObjectBinder implements DataObjectBinder {
// 构造方法提供者
public final BindConstructorProvider constructorProvider;
ValueObjectBinder(BindConstructorProvider constructorProvider) {
this.constructorProvider = constructorProvider;
}
/**
* 通过给定的构造方法进行参数绑定
*/
@Override
public <T> T bind(ConfigurationPropertyName name, Bindable<T> target, Binder.Context context, DataObjectPropertyBinder propertyBinder) {
// 获取到绑定对象构造方法以及类型信息
DefaultValueObject<T> valueObject = DefaultValueObject.get(target, this.constructorProvider, context);
// 如果没有获取到可绑定的构造函数,则不处理
// 当前ValueObjectBinder只处理构造函数绑定的对象
if (valueObject == null) {
return null;
}
// 记录当前正在构造绑定的类型信息,这个可以判断是否存在多级构造绑定
context.pushConstructorBoundTypes(target.getType().resolve());
// 获取到构造方法对应的参数信息
List<ConstructorParameter> parameters = valueObject.getConstructorParameters();
// 参数值
List<Object> args = new ArrayList<>(parameters.size());
// 绑定状态
boolean bound = false;
// 遍历所有的构造参数信息
for (ConstructorParameter parameter : parameters) {
// 获取绑定的构造函数的值
Object arg = parameter.bind(propertyBinder) {
// name: 构造参数变量名
// type: 构造参数类型
// annotations: 构造参数上的注解信息
// 返回绑定的构造参数类型对象的值
return propertyBinder.bindProperty(this.name, Bindable.of(this.type).withAnnotations(this.annotations));
}
// 绑定成功标志
bound = bound || arg != null;
// 如果没有解析到参数,或者参数的默认值
Object defaultValue = parameter.getDefaultValue(context.getConverter()) {
// 获取参数上面是否存在@DefaultValue注解信息
for (Annotation annotation : this.annotations) {
if (annotation instanceof DefaultValue) {
// 对给定的值进行类型转换,转换为构造参数类型
return converter.convert(((DefaultValue) annotation).value(), this.type, this.annotations);
}
}
// 没有@DefaultValue注解信息,返回null
return null;
}
arg = (arg != null) ? arg : defaultValue;
// 保存绑定的构造参数
args.add(arg);
}
// 清空正在绑定的对象,因为已经绑定成功了
context.clearConfigurationProperty();
// 删除标记正在构造绑定的类型,因为已经绑定成功了
context.popConstructorBoundTypes();
// 使用构造参数实例化对象
return bound ? valueObject.instantiate(args) : null;
}
/**
* 创建对象
*/
@Override
public <T> T create(Bindable<T> target, Binder.Context context) {
// 获取到绑定对象构造方法以及类型信息
DefaultValueObject<T> valueObject = DefaultValueObject.get(target, this.constructorProvider, context);
// 如果没有获取到可绑定的构造函数,则不处理
// 当前ValueObjectBinder只处理构造函数绑定的对象
if (valueObject == null) {
return null;
}
// 获取构造函数参数
List<ConstructorParameter> parameters = valueObject.getConstructorParameters();
// 参数值
List<Object> args = new ArrayList<>(parameters.size());
// 遍历所有的参数
for (ConstructorParameter parameter : parameters) {
// 设置默认值
Object arg = parameter.getDefaultValue(context.getConverter()) {
// 获取参数上面是否存在@DefaultValue注解信息
for (Annotation annotation : this.annotations) {
if (annotation instanceof DefaultValue) {
// 对给定的值进行类型转换,转换为构造参数类型
return converter.convert(((DefaultValue) annotation).value(), this.type, this.annotations);
}
}
// 没有@DefaultValue注解信息,返回null
return null;
}
args.add(arg);
}
实例化
return valueObject.instantiate(args);
}
static class DefaultValueObject<T> {
// 实例化的构造方法
public final Constructor<T> constructor;
// 该对象的类型
public ResolvableType resolvableType;
// 变量名解析器
public static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
public DefaultValueObject(Constructor<T> constructor, ResolvableType type) {
this.constructor = constructor;
this.constructorParameters = parseConstructorParameters(constructor, type);
}
// 指定构造参数,实例化该对象
public T instantiate(List<Object> args) {
return BeanUtils.instantiateClass(this.constructor, args.toArray());
}
// 获取构造函数参数
public List<ConstructorParameter> getConstructorParameters() {
// 解析构造方法的变量名
String[] names = PARAMETER_NAME_DISCOVERER.getParameterNames(constructor);
// 获取构造函数参数名称
Parameter[] parameters = constructor.getParameters();
// 构造函数参数信息,包含了参数名,参数类型和注解信息
List<ConstructorParameter> result = new ArrayList<>(parameters.length);
// 遍历所有的参数
for (int i = 0; i < parameters.length; i++) {
String name = names[i];
// 获取参数的类型
ResolvableType parameterType = ResolvableType.forMethodParameter(new MethodParameter(constructor, i), type);
// 获取参数的注解信息
Annotation[] annotations = parameters[i].getDeclaredAnnotations();
// 将参数名,参数类型和注解信息封装成ConstructorParameter对象
result.add(new ConstructorParameter(name, parameterType, annotations));
}
return Collections.unmodifiableList(result);
}
/**
* 获取到绑定对象构造方法以及类型信息
*/
public static <T> ValueObject<T> get(Bindable<T> bindable, BindConstructorProvider constructorProvider, Binder.Context context) {
// 获取需要绑定对象的类型
Class<T> type = (Class<T>) bindable.getType().resolve();
// 如果是枚举或者抽象类不处理
if (type == null || type.isEnum() || Modifier.isAbstract(type.getModifiers())) {
return null;
}
// 使用构造方法提供者提供可用的构造方法
/**
* {@link DefaultBindConstructorProvider,ConfigurationPropertiesBindConstructorProvider}
*/
Constructor<?> bindConstructor = constructorProvider.getBindConstructor(bindable, context.isNestedConstructorBinding());
// 如果没有获取到可绑定的构造函数,则不处理
if (bindConstructor == null) {
return null;
}
// 将构造函数和当前绑定对象的类型封装为DefaultValueObject
return DefaultValueObject.get(bindConstructor, bindable.getType());
}
// 将构造函数和当前绑定对象的类型封装为DefaultValueObject
static <T> ValueObject<T> get(Constructor<?> bindConstructor, ResolvableType type) {
// 将构造函数和当前绑定对象的类型封装为DefaultValueObject
return new DefaultValueObject<>((Constructor<T>) bindConstructor, type);
}
}
}
// 默认的构造方法提供者
// 只返回该对象仅存在一个构造方法的有参构造,其他场景不处理
class DefaultBindConstructorProvider implements BindConstructorProvider {
/**
* 查找可以绑定的构造方法
*
* @param bindable 需要绑定目标对象
* @param isNestedConstructorBinding 是否支持嵌套绑定
* @return 绑定的构造方法
*/
public Constructor<?> getBindConstructor(Bindable<?> bindable, boolean isNestedConstructorBinding) {
// 获取需要绑定的类型
Class<?> type = bindable.getType().resolve();
// 如果绑定的实例对象不为空,或者绑定的类型为空,就不需要处理
// 这两种情况是: 1: 已经生成好了实例对象,所以没有必要再找构造方法
// 2. 没有获取到类型,则无法创建对象
if (bindable.getValue() != null || type == null) {
return null;
}
// 获取所有的构造方法
Constructor<?>[] constructors = type.getDeclaredConstructors();
// 如果只有一个构造方法,并且参数个数大于0,表示对象需要通过属性注入进行创建实例对象
if (constructors.length == 1 && constructors[0].getParameterCount() > 0) {
return constructors[0];
}
// 不是只有一个有参构造的情况,都返回null
return null;
}
}
// @ConfigurationProperties注解的构造方法提供者
class ConfigurationPropertiesBindConstructorProvider implements BindConstructorProvider {
// 单例对象
static final ConfigurationPropertiesBindConstructorProvider INSTANCE = new ConfigurationPropertiesBindConstructorProvider();
/**
* 查找可以绑定的构造方法
*
* @param bindable 需要绑定目标对象
* @param isNestedConstructorBinding 是否支持嵌套绑定
* @return 绑定的构造方法
*/
public Constructor<?> getBindConstructor(Bindable<?> bindable, boolean isNestedConstructorBinding) {
return getBindConstructor(bindable.getType().resolve(), isNestedConstructorBinding);
}
// 查找可以绑定的构造方法
public Constructor<?> getBindConstructor(Class<?> type, boolean isNestedConstructorBinding) {
// 查找标注了@ConstructorBinding的构造方法
Constructor<?> constructor = findConstructorBindingAnnotatedConstructor(type);
// 如果不存在@ConstructorBinding的构造方法
// 继续判断类的父类中存在该注解,或者支持嵌套构造绑定,这样就需要再次找可用的构造方法
if (constructor == null && (isConstructorBindingAnnotatedType(type) || isNestedConstructorBinding)) {
// 查找只有一个有参构造方法情况,如果有则返回,如果没有返回null
constructor = deduceBindConstructor(type);
}
return constructor;
}
// 查找标注了@ConstructorBinding的构造方法
public Constructor<?> findConstructorBindingAnnotatedConstructor(Class<?> type) {
// 获取该类的所有构造方法进行筛序
return findAnnotatedConstructor(type, type.getDeclaredConstructors());
}
// 从类中所有的构造方法中筛选标注了@ConstructorBinding的构造方法
public Constructor<?> findAnnotatedConstructor(Class<?> type, Constructor<?>... candidates) {
Constructor<?> constructor = null;
for (Constructor<?> candidate : candidates) {
if (MergedAnnotations.from(candidate).isPresent(ConstructorBinding.class)) {
// 如果存在@ConstructorBinding注解,就必须要有参数
Assert.state(candidate.getParameterCount() > 0, type.getName() + " declares @ConstructorBinding on a no-args constructor");
// constructor只有第一次进才为空,如果不为空,表示存在多个标注了@ConstructorBinding的构造方法
Assert.state(constructor == null, type.getName() + " has more than one @ConstructorBinding constructor");
// 找到了可用的@ConstructorBinding构造方法
constructor = candidate;
}
}
return constructor;
}
// 类的父类中是否存在该注解
public boolean isConstructorBindingAnnotatedType(Class<?> type) {
return MergedAnnotations.from(type, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).isPresent(ConstructorBinding.class);
}
// 查找只有一个有参构造方法情况,如果有则返回,如果没有返回null
public Constructor<?> deduceBindConstructor(Class<?> type) {
// 获取所有的构造方法
Constructor<?>[] constructors = type.getDeclaredConstructors();
// 如果构造方法只有一个有参构造方法,直接返回
if (constructors.length == 1 && constructors[0].getParameterCount() > 0) {
return constructors[0];
}
// 否则不处理
return null;
}
}
}
// 配置属性源,一般是从配置文件中加载的属性
class ConfigurationPropertySources {
// 附加"configurationProperties"的配置属性
public static void attach(Environment environment) {
// 获取上下文环境中所有的属性对象
MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
// 是否存在configurationProperties名称对应的属性对象
PropertySource<?> attached = sources.get(ATTACHED_PROPERTY_SOURCE_NAME);
// 如果存在configurationProperties名称对应的属性对象,并且之前的数据与现在要保存的数据不一样
if (attached != null && attached.getSource() != sources) {
// 删除原来的数据
sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
// 置空
attached = null;
}
// 如果没有附加上configurationProperties属性
if (attached == null) {
// 使用configurationProperties作为name,保存一个ConfigurationPropertySourcesPropertySource属性源,并且source数据为SpringConfigurationPropertySources
sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME, new SpringConfigurationPropertySources(sources)));
}
}
public static Iterable<ConfigurationPropertySource> from(Iterable<PropertySource<?>> sources) {
// 返回普通的Spring属性配置源
return new SpringConfigurationPropertySources(sources);
}
public static Iterable<ConfigurationPropertySource> from(PropertySource<?> source) {
SpringConfigurationPropertySource propertySource = SpringConfigurationPropertySource.from(source) {
// 如果当前配置元素是可枚举迭代的
if (isFullEnumerable(source)) {
// 返回可以迭代的ConfigurationPropertySource
return new SpringIterableConfigurationPropertySource((EnumerablePropertySource<?>) source, mapper);
}
// 返回普通的Spring属性配置源
return new SpringConfigurationPropertySource(source);
}
return Collections.singleton(propertySource);
}
}
SpringBoot的配置文件是如何解析的,实现原理
最新推荐文章于 2024-06-19 15:09:37 发布