avatar

springContext配置

概述

用于描述springxml关于context的ns部分在源码中的实现,以及其使用场景,该ns对应的NamespaceHandler如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ContextNamespaceHandler extends NamespaceHandlerSupport {

@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}

}

compoent-scan

代码逻辑

ComponentScanBeanDefinitionParser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    public BeanDefinition parse(Element element, ParserContext parserContext) {
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

// Actually scan for bean definitions and register them
//调用该Scanner来处理
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
//返回在对应的classPath 正确注解的bean
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
//给当前BeanFactory中添加一些后处理器,此处的功能和annotation-config类似
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}

总结

  • ClassPathBeanDefinitionScanner:这个才是实际扫描路径并创建的sbd的类
    spring处理注解@ComponentScan注解最终也要用到该类,外层是ComponentScanAnnotationParser
    具体注解处理的代码分析可以参考,springBoot学习一.

annotation-config

  • 代码逻辑
AnnotationConfigBeanDefinitionParser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    
public class AnnotationConfigBeanDefinitionParser implements BeanDefinitionParser {

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);

// Obtain bean definitions for all relevant BeanPostProcessors.
//AnnotationConfigUtils该类在许多springContext都用到了
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);

// Register component for the surrounding <context:annotation-config> element.
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);

// Nest the concrete beans in the surrounding component.
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));
}

// Finally register the composite component.
parserContext.popAndRegisterContainingComponent();

return null;
}

}

对于AnnotationConfigUtils参考context相关

load-time-weaver

  • 代码逻辑
LoadTimeWeaverBeanDefinitionParser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public static final String ASPECTJ_WEAVING_ENABLER_BEAN_NAME =
"org.springframework.context.config.internalAspectJWeavingEnabler";

private static final String ASPECTJ_WEAVING_ENABLER_CLASS_NAME =
"org.springframework.context.weaving.AspectJWeavingEnabler";

private static final String DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME =
"org.springframework.context.weaving.DefaultContextLoadTimeWeaver";

private static final String WEAVER_CLASS_ATTRIBUTE = "weaver-class";

private static final String ASPECTJ_WEAVING_ATTRIBUTE = "aspectj-weaving";


//返回DefaultContextLoadTimeWeaver beanClass,具体逻辑要看AbstractSingleBeanDefinitionParser逻辑
@Override
protected String getBeanClassName(Element element) {
if (element.hasAttribute(WEAVER_CLASS_ATTRIBUTE)) {
return element.getAttribute(WEAVER_CLASS_ATTRIBUTE);
}
return DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME;
}


//返回LTW bean Name
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
return ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME;
}

//解析标签,创建一个AspectJWeavingEnabler bean
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

if (isAspectJWeavingEnabled(element.getAttribute(ASPECTJ_WEAVING_ATTRIBUTE), parserContext)) {
if (!parserContext.getRegistry().containsBeanDefinition(ASPECTJ_WEAVING_ENABLER_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ASPECTJ_WEAVING_ENABLER_CLASS_NAME);
parserContext.registerBeanComponent(
new BeanComponentDefinition(def, ASPECTJ_WEAVING_ENABLER_BEAN_NAME));
}

if (isBeanConfigurerAspectEnabled(parserContext.getReaderContext().getBeanClassLoader())) {
new SpringConfiguredBeanDefinitionParser().parse(element, parserContext);
}
}
}

总结

创建DefaultContextLoadTimeWeaverGBD和AspectJWeavingEnabler
简单来说LWT就是载入时织入,与spring aop实现点不同,后者是运行时织入

property-

property-placeholderproperty-override,前者用来提供处理bd中${}的功能,后者用来替换bean对应的属性

  • xml解析器

这是一个AbstractSingleBeanDefinitionParser子类,参考NamespaceHandler

property-placeholder

代码逻辑

AbstractPropertyLoadingBeanDefinitionParser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
abstract class AbstractPropertyLoadingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

@Override
protected boolean shouldGenerateId() {
return true;
}
//处理共有属性
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String location = element.getAttribute("location");
if (StringUtils.hasLength(location)) {
location = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(location);
String[] locations = StringUtils.commaDelimitedListToStringArray(location);
builder.addPropertyValue("locations", locations);
}

String propertiesRef = element.getAttribute("properties-ref");
if (StringUtils.hasLength(propertiesRef)) {
builder.addPropertyReference("properties", propertiesRef);
}

String fileEncoding = element.getAttribute("file-encoding");
if (StringUtils.hasLength(fileEncoding)) {
builder.addPropertyValue("fileEncoding", fileEncoding);
}

String order = element.getAttribute("order");
if (StringUtils.hasLength(order)) {
builder.addPropertyValue("order", Integer.valueOf(order));
}

builder.addPropertyValue("ignoreResourceNotFound",
Boolean.valueOf(element.getAttribute("ignore-resource-not-found")));

builder.addPropertyValue("localOverride",
Boolean.valueOf(element.getAttribute("local-override")));

builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
}
}
//具体的属性
class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {

private static final String SYSTEM_PROPERTIES_MODE_ATTRIBUTE = "system-properties-mode";

private static final String SYSTEM_PROPERTIES_MODE_DEFAULT = "ENVIRONMENT";


@Override
@SuppressWarnings("deprecation")
protected Class<?> getBeanClass(Element element) {
// As of Spring 3.1, the default value of system-properties-mode has changed from
// 'FALLBACK' to 'ENVIRONMENT'. This latter value indicates that resolution of
// placeholders against system properties is a function of the Environment and
// its current set of PropertySources.
if (SYSTEM_PROPERTIES_MODE_DEFAULT.equals(element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE))) {//这个属性实际上是dtd决定的
return PropertySourcesPlaceholderConfigurer.class; //3.0之后
}

// The user has explicitly specified a value for system-properties-mode: revert to
// PropertyPlaceholderConfigurer to ensure backward compatibility with 3.0 and earlier.
// This is deprecated; to be removed along with PropertyPlaceholderConfigurer itself.
return org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.class; //3.0之前
}

@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);

builder.addPropertyValue("ignoreUnresolvablePlaceholders",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));

String systemPropertiesModeName = element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE);
if (StringUtils.hasLength(systemPropertiesModeName) &&
!systemPropertiesModeName.equals(SYSTEM_PROPERTIES_MODE_DEFAULT)) {
builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_" + systemPropertiesModeName);
}

if (element.hasAttribute("value-separator")) {
builder.addPropertyValue("valueSeparator", element.getAttribute("value-separator"));
}
if (element.hasAttribute("trim-values")) {
builder.addPropertyValue("trimValues", element.getAttribute("trim-values"));
}
if (element.hasAttribute("null-value")) {
builder.addPropertyValue("nullValue", element.getAttribute("null-value"));
}
}

}

实现原理

PropertySourcesPlaceholderConfigurer是提供将bd的${}转化为对应属性的BFP

  • 代码逻辑
PropertySourcesPlaceholderConfigurer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport implements EnvironmentAware {
@Nullable
private MutablePropertySources propertySources;//包含解析的properties文件属性

@Nullable
private PropertySources appliedPropertySources;

@Nullable
private Environment environment; //通过aware接口获取的
//处理器函数
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//[1] 若ps中为空,则从env中获取
if (this.propertySources == null) {
this.propertySources = new MutablePropertySources();
if (this.environment != null) {
this.propertySources.addLast(
new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
@Override
@Nullable
public String getProperty(String key) {
return this.source.getProperty(key);
}
}
);
}
try {
PropertySource<?> localPropertySource =
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties()); //合并localtion中,即用户定义的properties顺序ing
if (this.localOverride) {
this.propertySources.addFirst(localPropertySource);
}
else {
this.propertySources.addLast(localPropertySource);
}
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
//[1!]
//使用PropertyResolver来完成对于bd中${}的处理
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));//创建了一个PropertySourcesPropertyResolver
this.appliedPropertySources = this.propertySources;
}
//设置resolver属性
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
final ConfigurablePropertyResolver propertyResolver) throws BeansException {

propertyResolver.setPlaceholderPrefix(this.placeholderPrefix);//${
propertyResolver.setPlaceholderSuffix(this.placeholderSuffix);//$}
propertyResolver.setValueSeparator(this.valueSeparator);//:
//这个valueResolver和形参propertyResolver是关键
StringValueResolver valueResolver = strVal -> {
String resolved = (this.ignoreUnresolvablePlaceholders ? //若未定义该属性,则调用抛出异常的
propertyResolver.resolvePlaceholders(strVal) :
propertyResolver.resolveRequiredPlaceholders(strVal));
if (this.trimValues) {
resolved = resolved.trim();
}
return (resolved.equals(this.nullValue) ? null : resolved);
};

doProcessProperties(beanFactoryToProcess, valueResolver);//父类调用
}
//----------------------PlaceholderConfigurerSupport父类调用---------------------
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) {

BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver); //创建vistor

String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
for (String curName : beanNames) { //避免处理本身这个处理器
// Check that we're not parsing our own bean definition,
// to avoid failing on unresolvable placeholders in properties file locations.
if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
try {
visitor.visitBeanDefinition(bd);//调用vistor
}
catch (Exception ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
}
}
}

// New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
//处理别名
beanFactoryToProcess.resolveAliases(valueResolver);

// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
//加入到bf中,实际AutoWire..Post会调用到,来处理@Value注解
beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}
}

BeanDefinitionVisitor

该类的作用是通过内部的StringValueResolver来对bd的部分属性做一次处理,实际上就是说在bd中
不仅仅是pv可以使用${},在这里出现的都一定程度上可以使用

  • 代码逻辑
BeanDefinitionVisitor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
public class BeanDefinitionVisitor {
//Value解析器
private StringValueResolver valueResolver;

public void visitBeanDefinition(BeanDefinition beanDefinition) {
//[0]resolverStringValue类型
visitParentName(beanDefinition);
visitBeanClassName(beanDefinition);
visitFactoryBeanName(beanDefinition);
visitFactoryMethodName(beanDefinition);
visitScope(beanDefinition);
//[0!]
//[1]resolveValue类型
if (beanDefinition.hasPropertyValues()) {
visitPropertyValues(beanDefinition.getPropertyValues());
}
if (beanDefinition.hasConstructorArgumentValues()) {
ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
visitIndexedArgumentValues(cas.getIndexedArgumentValues());
visitGenericArgumentValues(cas.getGenericArgumentValues());
}
//[1!]
}
//-----------------------resolverStringValue类型--------------------------
protected String resolveStringValue(String strVal) {
if (this.valueResolver == null) {
throw new IllegalStateException("No StringValueResolver specified - pass a resolver " +
"object into the constructor or override the 'resolveStringValue' method");
}
String resolvedValue = this.valueResolver.resolveStringValue(strVal);
// Return original String if not modified.
return (strVal.equals(resolvedValue) ? strVal : resolvedValue);
}

protected void visitParentName(BeanDefinition beanDefinition) {
String parentName = beanDefinition.getParentName();
if (parentName != null) {
String resolvedName = resolveStringValue(parentName);
if (!parentName.equals(resolvedName)) {
beanDefinition.setParentName(resolvedName);
}
}
}
//.........

//-----------------------resolveValue类型--------------
protected Object resolveValue(@Nullable Object value) {
if (value instanceof BeanDefinition) {
visitBeanDefinition((BeanDefinition) value);
}
else if (value instanceof BeanDefinitionHolder) {
visitBeanDefinition(((BeanDefinitionHolder) value).getBeanDefinition());
}
else if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
String newBeanName = resolveStringValue(ref.getBeanName());
if (newBeanName == null) {
return null;
}
if (!newBeanName.equals(ref.getBeanName())) {
return new RuntimeBeanReference(newBeanName);
}
}
else if (value instanceof RuntimeBeanNameReference) {
RuntimeBeanNameReference ref = (RuntimeBeanNameReference) value;
String newBeanName = resolveStringValue(ref.getBeanName());
if (newBeanName == null) {
return null;
}
if (!newBeanName.equals(ref.getBeanName())) {
return new RuntimeBeanNameReference(newBeanName);
}
}
else if (value instanceof Object[]) {
visitArray((Object[]) value);
}
else if (value instanceof List) {
visitList((List) value);
}
else if (value instanceof Set) {
visitSet((Set) value);
}
else if (value instanceof Map) {
visitMap((Map) value);
}
else if (value instanceof TypedStringValue) {
TypedStringValue typedStringValue = (TypedStringValue) value;
String stringValue = typedStringValue.getValue();
if (stringValue != null) {
String visitedString = resolveStringValue(stringValue);
typedStringValue.setValue(visitedString);
}
}
else if (value instanceof String) {
return resolveStringValue((String) value);
}
return value;
}
}

PropertySourcesPropertyResolver

该类真正的完成了对${}表达式的处理

PropertyResolver

将内部的PropertySource转换为对应的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
//包装实现,调用内部源
boolean containsProperty(String key);
String getProperty(String key);
String getProperty(String key, String defaultValue);
//解析
<T> T getProperty(String key, Class<T> targetType);
<T> T getProperty(String key, Class<T> targetType, T defaultValue);
String getRequiredProperty(String key) throws IllegalStateException;
<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;
//处理${}表达式
//前者抛出异常,后者不抛异常
String resolvePlaceholders(String text);
String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
ConfigurablePropertyResolver

可以配置前后缀,分隔符,以及转换器

ConfigurablePropertyResolver
1
2
3
4
5
6
7
8
9
public interface ConfigurablePropertyResolver extends PropertyResolver {
//转换器
ConfigurableConversionService getConversionService();
void setConversionService(ConfigurableConversionService conversionService);
//前后缀
void setPlaceholderPrefix(String placeholderPrefix);
void setPlaceholderSuffix(String placeholderSuffix);
void setValueSeparator(@Nullable String valueSeparator);
}
AbstractPropertyResolver

定义了内部一些属性,实现通过函数

  • 代码逻辑
AbstractPropertyResolver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
protected final Log logger = LogFactory.getLog(getClass());

@Nullable
private volatile ConfigurableConversionService conversionService;

//用来处理${name}占位符
@Nullable
private PropertyPlaceholderHelper nonStrictHelper;

@Nullable
private PropertyPlaceholderHelper strictHelper;

private boolean ignoreUnresolvableNestedPlaceholders = false;

private String placeholderPrefix = SystemPropertyUtils.PLACEHOLDER_PREFIX;

private String placeholderSuffix = SystemPropertyUtils.PLACEHOLDER_SUFFIX;

@Nullable
private String valueSeparator = SystemPropertyUtils.VALUE_SEPARATOR;

private final Set<String> requiredProperties = new LinkedHashSet<>();
//处理占位符函数
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
if (this.strictHelper == null) {
this.strictHelper = createPlaceholderHelper(false);
}
return doResolvePlaceholders(text, this.strictHelper);
}
public String resolvePlaceholders(String text) {
if (this.nonStrictHelper == null) {
this.nonStrictHelper = createPlaceholderHelper(true);
}
return doResolvePlaceholders(text, this.nonStrictHelper);
}
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
return helper.replacePlaceholders(text, this::getPropertyAsRawString); //注意这里传递一个了子类实现的函数引用
}
protected <T> T convertValueIfNecessary(Object value, @Nullable Class<T> targetType) {
if (targetType == null) {
return (T) value;
}
ConversionService conversionServiceToUse = this.conversionService;
if (conversionServiceToUse == null) {
// Avoid initialization of shared DefaultConversionService if
// no standard type conversion is needed in the first place...
if (ClassUtils.isAssignableValue(targetType, value)) {
return (T) value;
}
conversionServiceToUse = DefaultConversionService.getSharedInstance();
}
return conversionServiceToUse.convert(value, targetType); //cs进行转换
}
PropertyPlaceholderHelper

处理${}逻辑,实际前后缀分割符都可以定义

  • 嵌套:${${}}
  • 多值:${xxx:xxx}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

public class PropertyPlaceholderHelper {
protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) { //第二个参数实际被充当与函数接口使用
//[1]判断前缀
int startIndex = value.indexOf(this.placeholderPrefix);
if (startIndex == -1) {
return value;
}
//[1!]
StringBuilder result = new StringBuilder(value);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(result, startIndex); //后缀
if (endIndex != -1) {
//[1] placeholderResolver若没有提供,则说明没有能力解析${}中内容
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
if (visitedPlaceholders == null) {
visitedPlaceholders = new HashSet<>(4);
}
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
//[1]
// Recursive invocation, parsing placeholders contained in the placeholder key.
//[2] 递归处理${${}}
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
// Now obtain the value for the fully resolved key...
//[3] 处理含有分割符的
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
if (propVal == null && this.valueSeparator != null) {
int separatorIndex = placeholder.indexOf(this.valueSeparator);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (logger.isTraceEnabled()) {
logger.trace("Resolved placeholder '" + placeholder + "'");
}
startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
}
//[3]
else if (this.ignoreUnresolvablePlaceholders) { //如果没有成功转换,则判断是否忽略
// Proceed with unprocessed value.
startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
else {
throw new IllegalArgumentException("Could not resolve placeholder '" +
placeholder + "'" + " in value \"" + value + "\"");
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}
return result.toString();
}
}
PropertySourcesPropertyResolver
PropertySourcesPropertyResolver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
private final PropertySources propertySources; //数据源
//抽象调用的,最终会被PropertyPlaceholderHelper调用
protected String getPropertyAsRawString(String key) {
return getProperty(key, String.class, false);
}
public String getProperty(String key) {
return getProperty(key, String.class, true);
}

@Override
@Nullable
public <T> T getProperty(String key, Class<T> targetValueType) {
return getProperty(key, targetValueType, true);
}

@Override
@Nullable
protected String getPropertyAsRawString(String key) {
return getProperty(key, String.class, false);
}
//该类实现的转换逻辑
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) { //key就是${}内部的值
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
if (logger.isTraceEnabled()) {
logger.trace("Searching for key '" + key + "' in PropertySource '" +
propertySource.getName() + "'");
}
Object value = propertySource.getProperty(key);//从property中获取value
if (value != null) {
if (resolveNestedPlaceholders && value instanceof String) {
value = resolveNestedPlaceholders((String) value); //由于helper的递归逻辑,如果是help调用到这里,这个value一定不是${}这样的格式
}
logKeyFound(key, propertySource, value);
return convertValueIfNecessary(value, targetValueType); //根据占位符处理结果,进行类型转换
}
}
}
if (logger.isTraceEnabled()) {
logger.trace("Could not find key '" + key + "' in any property source");
}
return null;
}
}
总结
  • 实际使用了PropertySourcesPropertyResolver完成了占位符逻辑处理,从property获取vlaue,然后进行String->String的转换(实际上会直接返回)
  • PropertySourcesPropertyResolver实际可以做到更多类型转换,这里仅仅使用了功能的子集
  • 关于${}占位符的解析逻辑就是如此实现的

@PropertySource

该注解常见于配置类型的项目,具体用来见该类注解,简单来说该类引入properties,并在’@Configration’类中使用

Environment

该类本身比较简单,其构建者一般都是能够触及context的对象,如SpringApplication,以及ConfigurationClassPostProcessor处理器
为了处理@Configration也会创建

上文中提到的PropertySourcesPropertyResolver#getProperty实际上会在此中使用,作为包装类内部属性

property-override

使用propertis中的beanName.value=newValue,来替换bf中的对应beanName.value的pv属性,当然中间有string到对应类型的转换

例子

  • 配置文件
1
test.password=123
  • xml文件
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:property-override location="context/over.properties"></context:property-override>
<bean id="test" class="context.property.PropertyBean"></bean>
</beans>
  • 输出结果
    PropertyBean{name='null', password='123'}

代码逻辑

PropertyOverrideBeanDefinitionParser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {

@Override
protected Class<?> getBeanClass(Element element) {
return PropertyOverrideConfigurer.class;
}

@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);

builder.addPropertyValue("ignoreInvalidKeys",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));

}

}

实现原理

  • 代码逻辑
PropertyOverrideConfigurer.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class PropertyOverrideConfigurer extends PropertyResourceConfigurer {
//父类postProcessBeanFactory()调用
protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
throws BeansException {

for (Enumeration<?> names = props.propertyNames(); names.hasMoreElements();) {//遍历props文件
String key = (String) names.nextElement();
try {
processKey(beanFactory, key, props.getProperty(key));
}
catch (BeansException ex) {
String msg = "Could not process key '" + key + "' in PropertyOverrideConfigurer";
if (!this.ignoreInvalidKeys) {
throw new BeanInitializationException(msg, ex);
}
if (logger.isDebugEnabled()) {
logger.debug(msg, ex);
}
}
}
}

protected void processKey(ConfigurableListableBeanFactory factory, String key, String value)
throws BeansException {

int separatorIndex = key.indexOf(this.beanNameSeparator);
if (separatorIndex == -1) {
throw new BeanInitializationException("Invalid key '" + key +
"': expected 'beanName" + this.beanNameSeparator + "property'");
}
String beanName = key.substring(0, separatorIndex);//propertis文件中beanname
String beanProperty = key.substring(separatorIndex + 1);//beanname.key
this.beanNames.add(beanName);
applyPropertyValue(factory, beanName, beanProperty, value); //beanmane.key=vlaue
if (logger.isDebugEnabled()) {
logger.debug("Property '" + key + "' set to value [" + value + "]");
}
}

protected void applyPropertyValue(
ConfigurableListableBeanFactory factory, String beanName, String property, String value) {

BeanDefinition bd = factory.getBeanDefinition(beanName);
BeanDefinition bdToUse = bd;
while (bd != null) {
bdToUse = bd;
bd = bd.getOriginatingBeanDefinition();
}
PropertyValue pv = new PropertyValue(property, value); //创建新的属性
pv.setOptional(this.ignoreInvalidKeys);
bdToUse.getPropertyValues().addPropertyValue(pv);
}
}
文章作者: fancylight
文章链接: https://www.fancylight.top/2020/04/08/springContext%E9%85%8D%E7%BD%AE/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 博客
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论