起因
今天在跑tomcat源码的时候在控制台出现了乱码,但是又是部分乱码,部分中文正常显示,但是部分中文显示异常
这就很奇怪了,首先可以肯定的是,日志输出的编码肯定是没有问题的,因为前面的“信息”都是显示正常的,那么问题出在哪里呢?我就到打印这条日志的类去看了一下。
日志在这里打印的,看起来没有毛病,我们将sm.getString()获取出来的结果打印了一下,发现是乱码的,根源找到了,给日志打印器的字符串就是乱码的,所以控制台乱码了。
sm这变量是StringManager的实例,我们跟进去看看
又出现了一个getString()方法,当我尝试输出在该方法之后输出value的时候出现了乱码 ,也就是根据这个key获取出来的value是乱码的,继续跟下去,发现其利用了ResourceBundle这个类去加载key对应的value
也就是说,是因为ResourceBundle这个类加载出来的值不对才导致的乱码
解析RecourceBundle
这个类的作用是加载属性文件,根据给定的属性文件的名称去加载对应的属性文件,他与Properties的区别是什么呢?
RecourceBundle只能加载项目下的属性文件,如果你的属性文件在org.apache.tomcat包下,那你使用RecourceBundle去加载的时候就应该是getBundle("org.apache.tomcat.属性文件名"),这也就有点像我们的类名了
他能根据Locale去加载不同语言对象的属性文件,这也就是国际化了
但是我们的属性文件要满足一定的格式,比如说像下面这样
假如我们现在使用 ResourceBundle.getBundle("LocalStrings")去加载对应的属性文件,注意.properties不用加。
在其方法内部
他获取了默认的Locale,然后就能根据该Locale去加载对应的语言的属性文件,比如说我们本地的编码是zh-Cn,那么他加载的属性文件就是LocalStrings_zh_CN.properties。当然你也可以给他设置Locale。
所以上面tomcat使用ResourceBundle的时候,就会去加载zh_CN结尾的属性文件,我找到对应的属性文件,发现里面的中文是正常的,怎么回事?
重要的点
ResourceBundle加载属性文件的时候使用的默认的编码方式ISO-8859-1,所以我们的中文加载出来是乱码的,要转换文件的编码
new String(bundle.getString("a").getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
这样就能正确的显示中文了
tomcat中乱码也是这个原因,但是我平时用tomcat都没有出现乱码,但是搞源码的时候怎么就出现乱码了?
我到我本地安装的tomcat去看了以下,在他打包的那些jar下面发现了问题,我们安装的tomcat中是没有其他语言支持的属性文件的,只有一个默认的英文的,也就是说没有像上面那张图片一样,一个属性文件对应多种不同的语言,他只有一个LocalStrings.properties。所以ResourceBundle只能加载到英文的属性文件,他就不管你的Locale是什么了,所以就不会出现乱码问题
那怎么解决tomcat源码的乱码的问题呢?
1.将本地的Locale改成英文的,那ResourceBundle每次就会去加载英文的属性文件
2.删除多余的属性文件,ResourceBundle就只能加载英文的属性文件了
3.像上面展示的代码那样,对tomcat中每一个从属性文件获取出来的字符串进行编码转换