- 场景:yml配置变量值是null 解析得到的是" "
- tip: 这篇最好结合
MBP中yml属性注入及逻辑删除过程
一起看下
- 下面就来分析下原因:
- yml解析过程中进行了默认处理
分析这部分代码一定要搞清楚Iterator逻辑 因为内部增强for默认使用Iterator遍历的
最好知悉Iterator及Iterable 两者区别 - 设置yml属性值时进行了默认处理(@Value是通过setter操作的 还是是直接反射字段赋值的)-反射字段赋值的
结果是: 1
org.springframework.boot.env.OriginTrackedYamlLoader.OriginTrackingConstructor#getValue:
private Object getValue(Object value) {
return (value != null) ? value : "";
}
null:
“null”:
-
- yml|yaml解析及默认处理的部分流程如下:
- org.springframework.boot.SpringApplication#run(java.lang.String...)
- org.springframework.boot.SpringApplication#prepareEnvironment
- org.springframework.boot.SpringApplicationRunListeners#environmentPrepared
- org.springframework.boot.context.event.EventPublishingRunListener#environmentPrepared
- org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent)
- org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
- org.springframework.context.event.SimpleApplicationEventMulticaster#invokeListener
- org.springframework.context.event.SimpleApplicationEventMulticaster#doInvokeListener
- org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEvent
- org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEnvironmentPreparedEvent
- org.springframework.boot.context.config.ConfigFileApplicationListener#postProcessEnvironment
- org.springframework.boot.context.config.ConfigFileApplicationListener#addPropertySources
- org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load()
- org.springframework.boot.context.config.FilteredPropertySource#apply
- org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load()
- org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load(org.springframework.boot.context.config.ConfigFileApplicationListener.Profile, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentFilterFactory, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentConsumer)
- org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load(java.lang.String, java.lang.String, org.springframework.boot.context.config.ConfigFileApplicationListener.Profile, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentFilterFactory, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentConsumer)
- org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#loadForFileExtension
- org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load(org.springframework.boot.env.PropertySourceLoader, java.lang.String, org.springframework.boot.context.config.ConfigFileApplicationListener.Profile, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentFilter, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentConsumer)
- org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#loadDocuments
- org.springframework.boot.env.YamlPropertySourceLoader#load
- org.springframework.boot.env.OriginTrackedYamlLoader#load
- org.springframework.beans.factory.config.YamlProcessor#process(org.springframework.beans.factory.config.YamlProcessor.MatchCallback)
- org.springframework.beans.factory.config.YamlProcessor#process(org.springframework.beans.factory.config.YamlProcessor.MatchCallback, org.yaml.snakeyaml.Yaml, org.springframework.core.io.Resource)
- java.util.Iterator#next
- org.yaml.snakeyaml.constructor.BaseConstructor#getData
- org.yaml.snakeyaml.constructor.BaseConstructor#constructDocument
- org.springframework.boot.env.OriginTrackedYamlLoader.OriginTrackingConstructor#constructObject
- org.yaml.snakeyaml.constructor.BaseConstructor#constructObject
- org.yaml.snakeyaml.constructor.BaseConstructor#constructObjectNoCheck
- org.yaml.snakeyaml.constructor.SafeConstructor.ConstructYamlMap#construct
- org.yaml.snakeyaml.constructor.BaseConstructor#constructMapping
- org.yaml.snakeyaml.constructor.SafeConstructor#constructMapping2ndStep
- org.yaml.snakeyaml.constructor.BaseConstructor#constructMapping2ndStep
- org.springframework.boot.env.OriginTrackedYamlLoader.OriginTrackingConstructor#constructObject
- org.yaml.snakeyaml.constructor.BaseConstructor#constructObject
....
在org.springframework.boot.env.OriginTrackedYamlLoader.OriginTrackingConstructor#getValue 打个断点 观察具体的调用栈信息
-
-
@Value注解赋值的过程部分流程如下:
-
结论:@Value是通过反射字段赋值的 并没有进行null的处理操作
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}