概述
用于描述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); ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element); Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages); 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); Set<BeanDefinitionHolder> processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source); CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source); parserContext.pushContainingComponent(compDefinition); for (BeanDefinitionHolder processorDefinition : processorDefinitions) { parserContext.registerComponent(new BeanComponentDefinition(processorDefinition)); } 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" ;@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; } @Override protected String resolveId (Element element, AbstractBeanDefinition definition, ParserContext parserContext) { return ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME; } @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); } } }
总结
创建DefaultContextLoadTimeWeaver
GBD和AspectJWeavingEnabler
简单来说LWT就是载入时织入,与spring aop实现点不同,后者是运行时织入
property-
property-placeholder
和property-override
,前者用来提供处理bd中${}
的功能,后者用来替换bean对应的属性
这是一个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) { if (SYSTEM_PROPERTIES_MODE_DEFAULT.equals(element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE))) { return PropertySourcesPlaceholderConfigurer.class ; } return org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.class ; } @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;@Nullable private PropertySources appliedPropertySources;@Nullable private Environment environment; public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException { 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()); if (this .localOverride) { this .propertySources.addFirst(localPropertySource); } else { this .propertySources.addLast(localPropertySource); } } catch (IOException ex) { throw new BeanInitializationException("Could not load properties" , ex); } } processProperties(beanFactory, new PropertySourcesPropertyResolver(this .propertySources)); this .appliedPropertySources = this .propertySources; } protected void processProperties (ConfigurableListableBeanFactory beanFactoryToProcess, final ConfigurablePropertyResolver propertyResolver) throws BeansException { propertyResolver.setPlaceholderPrefix(this .placeholderPrefix); propertyResolver.setPlaceholderSuffix(this .placeholderSuffix); propertyResolver.setValueSeparator(this .valueSeparator); 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); } protected void doProcessProperties (ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) { BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver); String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames(); for (String curName : beanNames) { if (!(curName.equals(this .beanName) && beanFactoryToProcess.equals(this .beanFactory))) { BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName); try { visitor.visitBeanDefinition(bd); } catch (Exception ex) { throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex); } } } beanFactoryToProcess.resolveAliases(valueResolver); 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 {private StringValueResolver valueResolver;public void visitBeanDefinition (BeanDefinition beanDefinition) { visitParentName(beanDefinition); visitBeanClassName(beanDefinition); visitFactoryBeanName(beanDefinition); visitFactoryMethodName(beanDefinition); visitScope(beanDefinition); if (beanDefinition.hasPropertyValues()) { visitPropertyValues(beanDefinition.getPropertyValues()); } if (beanDefinition.hasConstructorArgumentValues()) { ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues(); visitIndexedArgumentValues(cas.getIndexedArgumentValues()); visitGenericArgumentValues(cas.getGenericArgumentValues()); } } 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 (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); } } } 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;@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 ) { if (ClassUtils.isAssignableValue(targetType, value)) { return (T) value; } conversionServiceToUse = DefaultConversionService.getSharedInstance(); } return conversionServiceToUse.convert(value, targetType); }
PropertyPlaceholderHelper
处理${}
逻辑,实际前后缀分割符都可以定义
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) { int startIndex = value.indexOf(this .placeholderPrefix); if (startIndex == -1 ) { return value; } StringBuilder result = new StringBuilder(value); while (startIndex != -1 ) { int endIndex = findPlaceholderEndIndex(result, startIndex); if (endIndex != -1 ) { 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" ); } placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); 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 ) { 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()); } else if (this .ignoreUnresolvablePlaceholders) { 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; 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) { 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); if (value != null ) { if (resolveNestedPlaceholders && value instanceof String) { value = resolveNestedPlaceholders((String) 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 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 { protected void processProperties (ConfigurableListableBeanFactory beanFactory, Properties props) throws BeansException { for (Enumeration<?> names = props.propertyNames(); names.hasMoreElements();) { 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); String beanProperty = key.substring(separatorIndex + 1 ); this .beanNames.add(beanName); applyPropertyValue(factory, beanName, beanProperty, value); 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); } }