标签:修改 lap 持久 prope script ring bcp visit display
背景:在使用持久化配置中心时,用到一个组件,该组件支持在代码中直接通过@DynamicValue(“指定的KEY名称”)方式,来直接获取配置的key对应的Value值。
占位符格式为${property-name},占位符在运行时,会被替换为propetry-value。一般环境相关的属性会用到占位符,属性以key=value格式定义在xxx.properties文件中,来减少对部署代码的更改。
应用场景有:数据库URLS、密码配置。
<!-- Spring2.5中引入的context namespace,property-placeholder属性配置属性文件location。--> <context:property-placeholder location="classpath:placeholder.properties"/> <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean>
先从UML图认识下PropertySourcesPlaceholderConfigurer,下图中,比较重要的两个接口:BeanFactoryPostProcessor, Ordered。
BeanFactoryPostProcessor 能读取Bean配置元数据、在IOC容器实例化Bean之前修改其配置元数据。即将Bean中的占位符替换掉。
Ordered 能控制多个BeanFactoryPostProcessor的执行顺序。
围绕着重要接口继续展开UML图如下,从下图可以看出:
BeanFactoryPostProcessor接口是具体实现是在PropertySourcesPlaceholderConfigurer类中,PropertySourcesPlaceholderConfigurer.postProcessBeanFactory方法。
Ordered接口是具体实现在PropertyResourceConfigurer类中,PropertyResourceConfigurer.getOrder方法。
PropertySourcesPlaceholderConfigurer.postProcessBeanFactory 方法源码解析如下。除了主流程外,流程中出现较多的是各种valueResolver, 见名知意先不用分析,后面可以分析下其设计模式。
/** * 用configurer的PropertySource集合,来替换Bean定义中的占位符${...} * PropertySource包含以下内容: * 1. 所有的environment property source,即Environment属性 * 2. 合并后的local properties,可通过#setLocation\#setLocations\#setProperties\setPropertiesArray等方法指定值 * 3. 通过调用#setPropertySources方法设置的ProperySources,若该方法被调用environment、local properties会被忽略,这个方法设计目标是为用户提供细粒度的控制。一旦设置,不会添加其他的sources. */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 创建PropertySource, 加载Environment属性、加载local properties if (this.propertySources == null) { this.propertySources = new MutablePropertySources(); if (this.environment != null) { // 加载Environment属性 this.propertySources.addLast( new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) { @Override public String getProperty(String key) { return this.source.getProperty(key); } } ); } try { // 加载local properties,#mergeProperties()方法,加载了用户指定的属性文件,并进行了合并 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; } /** * 访问给定bean factory的每个类定义,并用propertyResolver解析的值替换占位符${...} */ protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, final ConfigurablePropertyResolver propertyResolver) throws BeansException { // 可以自己指定placeholder的前缀、后缀,比如从${...} 替换为 $[...] propertyResolver.setPlaceholderPrefix(this.placeholderPrefix); propertyResolver.setPlaceholderSuffix(this.placeholderSuffix); propertyResolver.setValueSeparator(this.valueSeparator); StringValueResolver valueResolver = new StringValueResolver() { @Override public String resolveStringValue(String strVal) { String resolved = ignoreUnresolvablePlaceholders ? propertyResolver.resolvePlaceholders(strVal) : propertyResolver.resolveRequiredPlaceholders(strVal); return (resolved.equals(nullValue) ? null : resolved); } }; // 处理占位符 doProcessProperties(beanFactoryToProcess, valueResolver); } protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) { // 创建BeanDefinitionVisitor,将指定的valueResolver应用于所有Bean的元数据 BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver); // 遍历beanFactory中定义的所有bean的名字(不能包含当前BeanFactoryPostProcessor实例) 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 { // 遍历所有的bean定义中的名称、方法、属性等,替换其中的占位符 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); }
PropertyResourceConfigurer.getOrder方法源码解析如下。
// 默认最低优先级,等同于未排序 private int order = Ordered.LOWEST_PRECEDENCE; /** * 需要排序的话,设置该值 * @see PriorityOrdered */ public void setOrder(int order) { this.order = order; } @Override public int getOrder() { return this.order; }
背景:在使用持久化配置中心时,用到了同事写的组件。 该组件支持在代码中直接通过@DynamicValue(“指定的KEY名称”)方式,来直接获取配置的key对应的Value值。
标签:修改 lap 持久 prope script ring bcp visit display
原文地址:https://www.cnblogs.com/dameiwujaing/p/14422689.html