栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring:property-override

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring:property-override

文章目录
  • property-override
    • 作用
    • 类图
    • 解析
      • properties-ref
      • order
      • ignore-resource-not-found
      • ignore-unresolvable
      • local-override
      • BeanDefinition
    • 运行
      • 属性加载
      • 属性转换
      • 属性设置

property-override 作用

允许我们使用属性文件(.properties)的形式对bean的属性进行替换。下面是一个简单的demo:

定义如下的属性文件(property.properties):

student.name=dog

格式为: bean名字.属性名字=值。由如下的bean:


    
    

进行如下的配置:


运行如下的代码:

public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
    SimpleBean bean = SimpleBean.class.cast(context.getBean(SimpleBean.class));
    System.out.println(bean.getStudent().getName());
    context.close();
}

打印的便是dog,而不是skywalker。

类图

具体的实现类是PropertyOverrideBeanDefinitionParser,其类图如下:

解析

解析的原理是将此配置相关的信息保存到BeanDefinition中,更准确的说是一个GenericBeanDefinition。解析的源码:

AbstractPropertyLoadingBeanDefinitionParser.doParse:

@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
    String location = element.getAttribute("location");
    if (StringUtils.hasLength(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);
}
properties-ref

此属性允许我们直接引用一个java.util.Properties类型的bean作为数据源,示例:


    

    
        
            cat
        
    

这样便可以看到结果。

order

此属性用以指定其优先级,假设配置了多个context:property-override并且里面有相同的字段,那么将依赖order决定结果。

ignore-resource-not-found

如果设为true,那么对于没有找到的属性文件将会忽略,否则会抛出异常,默认为false,抛异常。

ignore-unresolvable

如果设为true,那么对于没有找到对应的key将会忽略,否则抛出异常,默认false。

local-override

这个属性让我很迷惑。Spring说是此选项决定"local"的属性是否可以覆盖属性文件中的值。正如下面说的,实际上属性文件被解析到了PropertyOverrideConfigurer对象,其父类PropertiesLoaderSupport有一个字段:

protected Properties[] localProperties;


public void setProperties(Properties properties) {
    this.localProperties = new Properties[] {properties};
}

可以看出,这应该就是Spring所说的"local"属性。好,我们来注入一下:




    
        
            
                cat
            
        
    

然而Spring在注册PropertyOverrideConfigurer的时候根本没有检查容器中是否已经有此类型的BeanDefinition存在,这就导致容器中会同时存在两个!在此种情况下local-override根本没什么卵用,因为后面的PropertyOverrideConfigurer始终会覆盖前一个,local-override是针对一个PropertyOverrideConfigurer来说的,那么问题来了,除此之外如何通过XML向"local"注入?(context:property-override不允许子标签存在)

BeanDefinition

保存的BeanDefinition的beanClass为PropertyOverrideConfigurer,其类图:

运行

入口当然是BeanFactoryPostProcessor.postProcessBeanFactory(PropertyResourceConfigurer):

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    try {
         // 属性加载
        Properties mergedProps = mergeProperties();

        // Convert the merged properties, if necessary.
        convertProperties(mergedProps);

        // Let the subclass process the properties.
        processProperties(beanFactory, mergedProps);
    }
    catch (IOException ex) {
        throw new BeanInitializationException("Could not load properties", ex);
    }
}
属性加载

PropertiesLoaderSupport.mergeProperties:

protected Properties mergeProperties() throws IOException {
    Properties result = new Properties();
    if (this.localOverride) {
        // Load properties from file upfront, to let local properties override.
        loadProperties(result);
    }
    if (this.localProperties != null) {
        for (Properties localProp : this.localProperties) {
            CollectionUtils.mergePropertiesIntoMap(localProp, result);
        }
    }
    if (!this.localOverride) {
        // Load properties from file afterwards, to let those properties override.
        loadProperties(result);
    }
    return result;
}

可以看出,对local-override的支持是通过改变local和文件两者的加载顺序来实现的。

属性转换

convertProperties是个空实现,因为这里并不需要,在bean实际生成的时候才会转换。

属性设置

就是逐个属性调用PropertyOverrideConfigurer.applyPropertyValue:

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

    BeanDefinition bd = factory.getBeanDefinition(beanName);
    while (bd.getOriginatingBeanDefinition() != null) {
        bd = bd.getOriginatingBeanDefinition();
    }
    PropertyValue pv = new PropertyValue(property, value);
    pv.setOptional(this.ignoreInvalidKeys);
    bd.getPropertyValues().addPropertyValue(pv);
}

addPropertyValue会遍历PropertyValue链表,找到name相同的进行value替换。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/328974.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号