PropertyPlaceholderConfigurer类源码解析理解
来源:互联网 发布:淘宝店铺代运营 编辑:程序博客网 时间:2024/06/05 15:07
今天在github上下载了一个《分布式配置管理平台XXL-CONF》,客户端核心配置,XxlConfPropertyPlaceholderConfigurer类无非继承了PropertyPlaceholderConfigurer类,并重写了processProperties方法,以前也一直有用到PropertyPlaceholderConfigurer类,但一直没研究过spring是如何通过PropertyPlaceholderConfigurer将配置文件中的值设置到bean对象中的。
这里先不得不说一下BeanFactoryPostProcessor接口,这个接口中只有一个实现方法postProcessBeanFactory,processProperties正是在postProcessBeanFactory实现中被调用。
实现BeanFactoryPostProcessor接口,以在spring的bean创建之前,修改bean的定义属性。Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改。
若想详细了解请参考:http://blog.csdn.NET/caihaijiang/article/details/35552859
总之,PropertySourcesPlaceholderConfigurer在bean初始化前会执行postProcessBeanFactory方法来配置bean的元数据。
我们来看PropertyResourceConfigurer.postProcessBeanFactory方法
/** * {@linkplain #mergeProperties Merge}, {@linkplain #convertProperties convert} and * {@linkplain #processProperties process} properties against the given bean factory. * @throws BeanInitializationException if any properties cannot be loaded */public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { try { //加载locations属性中配置的所有properties文件中的属性 Properties mergedProps = mergeProperties(); //prop做key,value转换 convertProperties(mergedProps); //解析el表达式中的属性,获取值,并加载到bean属性中 processProperties(beanFactory, mergedProps); } catch (IOException ex) { throw new BeanInitializationException("Could not load properties", ex); }}
/** * Visit each bean definition in the given bean factory and attempt to replace ${...} property * placeholders with values from the given properties. */@Overrideprotected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException { StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props); this.doProcessProperties(beanFactoryToProcess, valueResolver);}
StringValueResolver接口是一个通配符解析接口,默认解析替换${}中的值。
我们再进到doProcessProperties方法中看一下。
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) { //注册StringValueResolver解析器 BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver); //从BeanFactory中获取注册的beanNames 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))) { //初始化bean实例(自己除外) BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName); try { //设置元数据 visitor.visitBeanDefinition(bd); } 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. beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);}
这段代码很好理解
1.注册StringValueResolver解析器
2.从BeanFactory中获取注册的beanNames
3.初始化bean实例(自己除外)
4.调用visitor.visitBeanDefinition(bd);方法设置元数据。
我们再继续跟到visitBeanDefinition(bd)中去。
/** * Traverse the given BeanDefinition object and the MutablePropertyValues * and ConstructorArgumentValues contained in them. * @param beanDefinition the BeanDefinition object to traverse * @see #resolveStringValue(String) */public void visitBeanDefinition(BeanDefinition beanDefinition) { visitParentName(beanDefinition); visitBeanClassName(beanDefinition); visitFactoryBeanName(beanDefinition); visitFactoryMethodName(beanDefinition); visitScope(beanDefinition); visitPropertyValues(beanDefinition.getPropertyValues()); ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues(); visitIndexedArgumentValues(cas.getIndexedArgumentValues()); visitGenericArgumentValues(cas.getGenericArgumentValues());}
我们继续跟到visitPropertyValues(beanDefinition.getPropertyValues())方法里
/** * Resolve the given String value, for example parsing placeholders. * @param strVal the original String value * @return the resolved String value */ 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); }
跟到StringValueResolver.resolveStringValue(String strVal)方法中
protected String parseStringValue( String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) { StringBuilder result = new StringBuilder(strVal); int startIndex = strVal.indexOf(this.placeholderPrefix); 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.add(originalPlaceholder)) { throw new IllegalArgumentException( "Circular placeholder reference '" + originalPlaceholder + "' in property definitions"); } // Recursive invocation, parsing placeholders contained in the placeholder key. placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); // Now obtain the value for the fully resolved key... // 返回配置文件中对应属性的value值 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()); } 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 string value \"" + strVal + "\""); } visitedPlaceholders.remove(originalPlaceholder); } else { startIndex = -1; } } return result.toString(); }
大致逻辑,递归调用解析出${}中的字符串
通过String propVal = placeholderResolver.resolvePlaceholder(placeholder);方法从prop对象中获取到配置文件中对应的value。
返回配置文件中的value值到BeanDefinition对象中的MutablePropertyValues对象中
protected void visitPropertyValues(MutablePropertyValues pvs) { PropertyValue[] pvArray = pvs.getPropertyValues(); for (PropertyValue pv : pvArray) { Object newVal = resolveValue(pv.getValue()); if (!ObjectUtils.nullSafeEquals(newVal, pv.getValue())) { pvs.add(pv.getName(), newVal); } } }
pvs.add(pv.getName(), newVal);完成BeanDefinition的MutablePropertyValues对象设置。
大致代码原理如此。
- PropertyPlaceholderConfigurer类源码解析理解
- PropertyPlaceholderConfigurer源码解析
- Spring里用PropertyPlaceholderConfigurer类来解析java properties
- spring源码分析,聊聊PropertyPlaceholderConfigurer
- Spring PropertyPlaceholderConfigurer解析及应用
- [Spring]PropertyPlaceholderConfigurer类相关
- spring中的PropertyPlaceholderConfigurer类
- PropertyPlaceholderConfigurer类使用
- spring之PropertyPlaceholderConfigurer类
- PropertyPlaceholderConfigurer
- PropertyPlaceholderConfigurer
- PropertyPlaceholderConfigurer
- propertyplaceholderconfigurer
- PropertyPlaceholderConfigurer
- PropertyPlaceholderConfigurer
- PropertyPlaceholderConfigurer
- PropertyPlaceholderConfigurer
- opencv源码解析之:CommandLineParser类的简单理解
- Tomcat容器管理安全的几种验证方式
- 断点调试原理
- org.json.JSONException: Value ok of type java.lang.String cannot be converted to JSONObject:
- Web渗透测试求职问答大全
- javaweb基本的分页功能实现
- PropertyPlaceholderConfigurer类源码解析理解
- 【译】什么是 web 框架?
- 121.Best Time to Buy and Sell Stock
- Centos 6.5 安装JDK 和 tomcat
- python入门(三十四):socket
- DataBind的初步使用
- Java基础拾粹
- Add More Zero
- Java-D进制的A+B (20)