为了账号安全,请及时绑定邮箱和手机立即绑定

Spring&SpringBoot properties

标签:
SpringBoot

先看看原情况以及效果图

webp

image.png

说到乱码问题,其实目前遇到的乱码问题原因可以归根为读取协议不对等,例如使用GBK文件格式去读取UTF-8文件格式的内容肯定会出现乱码,那么我们解决问题的整体思路也就是使用合适的读取格式去读取文件内容

本篇学习笔记代码地址在simple-spring 的spring-learn模块的bpp文件夹中

Properties 文件读取

在之前的学习笔记中Spring Properties属性获取 源码学习,也曾经介绍过如何读取@Value("${XXX}")在属性文件中XXX对应的值。

PropertySourcesPlaceholderConfigurer 类是实现BeanFactoryPostProcessor接口的,在执行postProcessBeanFactory方法的时候,会进行属性文件的读取并且把键值对信息存储到PropertySourcesPlaceholderConfigurer类本身的容器中

在抽象类PropertiesLoaderSupport的protected void loadProperties(Properties props) throws IOException方法去完成属性文件内容的读取

最后来到了PropertiesLoaderUtils工具类中

    static void fillProperties(Properties props, EncodedResource resource, PropertiesPersister persister)
            throws IOException {

        InputStream stream = null;
        Reader reader = null;        try {
            String filename = resource.getResource().getFilename();            // 获取文件名称
            if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {                  // 1处 文件名不为null,而且是xml结尾
                stream = resource.getInputStream();
                persister.loadFromXml(props, stream);
            }            else if (resource.requiresReader()) {                  // 2处 如果resource中的encoding字段或者charset字段不为空
                    // 就会使用encoding内的字符编码或者charset设置的字符编码格式读取属性文件
                reader = resource.getReader();
                persister.load(props, reader);
            }            else {                   // 3处 否则就是使用默认的字符编码获取IO流
                stream = resource.getInputStream();
                persister.load(props, stream);
            }
        }

所以现在能够解决当前问题只有2处了,需要设置resource对象的encoding、charset字段值,而此resource生成是使用了new EncodedResource(location, this.fileEncoding)实现的

现在解决方案已经非常明了了,也就是设置PropertySourcesPlaceholderConfigurerbean的fileEncoding字段值即可

fileEncoding 字段值填充

xml配置的方法还是很简单的,直接设置bean的基本参数,然后在bean实例完之后参数填充即可

webp

image

现在讨论的是另一种情况,没有对外直接的file-encoding字段设置能力

上面已经说了,调用postProcessBeanFactory方法,会进行属性文件的读取(也就意味着PropertySourcesPlaceholderConfigurer是一个实现了BeanFactoryPostProcessor和PriorityOrdered接口的特殊BPP类),那么就必须在这个方法调用前完成参数的注入

重点关注BPP处理的核心类PostProcessorRegistrationDelegate

可以提出两种解决方案

  • 实现BeanDefinitionRegistryPostProcessor 接口

  • 实现BeanFactoryPostProcessor、PriorityOrdered 接口(排序超过PropertySourcesPlaceholderConfigurer)

至于为啥是这两种方案,可以看看之前写的Spring 钩子之BeanFactoryPostProcessor和BeanPostProcessor的源码学习再谈Spring BeanPostProcessor

例如如下自定义的BPP(具方法可看github内的代码)

@Componentpublic class PriorityOrderedBeanFactoryPostProcessor implements BeanFactoryPostProcessor,        PriorityOrdered {    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
        Map map = beanFactory.getBeansOfType(PropertySourcesPlaceholderConfigurer.class);        // 可能存在多个PropertySourcesPlaceholderConfigurerbean的情况
        Iterator<Map.Entry<String, PropertySourcesPlaceholderConfigurer>> it = map.entrySet().iterator();        while (it.hasNext()) {
            Map.Entry<String, PropertySourcesPlaceholderConfigurer> entry = it.next();
            PropertySourcesPlaceholderConfigurer pp = entry.getValue();
            pp.setFileEncoding("UTF-8");            // 终于获取到了设置文件编码类型的地方了
            // 这也是最关键的地方
        }
    }    @Override
    public int getOrder() {        // 排序规则,具体可以看看OrderComparator的排序规则
        // PropertySourcesPlaceholderConfigurer的排序order是最低的,所以设置一个0完全可以满足要求
        return 0;
    }
}



作者:jwfy
链接:https://www.jianshu.com/p/1e61bea64e62


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消