目前Spring体系下基础技术栈有SpringMVC、SpringBoot(以及SpringCloud)两种,在读取配置文件的方式上有些差异,但是整体保持一致。最近遇到在读取配置文件时发生乱码的问题,其实解决方式也比较简单。
1)对于properties文件,无论何种配置方式,Spring底层均使用Resource方式进行加载,最终基于JAVA本身的“classLoader.getResourceAsStream()”读取信息,编码默认为“ISO-8859-1”,编码方式可以通过配置指定。
参见ConfigurationClassParser.java、ClassPathResource.java等。
2)对于yml、xml文件,即配置文件的后缀以“yml”、“yaml”、“xml”(包括“properties”)结尾的配置文件,这种类型的配置目前只能在springboot技术栈中支持,编码方式为“UTF-8”,参见PropertiesPropertySourceLoader.java、YamlPropertySourceLoader.java。
所以,对于编码问题,我们对于properties文件要特别注意,需要强制指定编码为“UTF-8”,否则可能出现本地环境运行正常、但是发布环境总是乱码的奇怪问题。
一、基于XML方式
SpringMVC环境下,通常可以使用Bean-XML和注释两种方式来获取Properties属性,我们假定在resources目录下已存在“test.properties”文件:
test.name=Hi,你好,世界!
Bean XML方式(一)
1、Spring-Context.xml
<context:annotation-config /> <context:property-placeholder location="classpath:test.properties" ignore-unresolvable="true" file-encoding="UTF-8"/>
2、TestService.java
@Service public class TestService { @Value("${test.name}") private String testName; ... }
Bean XML方式(二)
1、Spring-Context.xml
<bean id="globalProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="fileEncoding" value="UTF-8"/> <property name="locations"> <array> <value>classpath:test2.properties</value> </array> </property> </bean>
2、TestService.java
@Service public class TestService { @Value("#{globalProperties['test.name']}") private String testName; ... }
我们需要特别注意,如果在SpringMVC的Web项目中@Controllor层需要使用@Value注入属性时,我们需要将上述配置放在Servlet相关的Spring文件中,这个文件名通常与下属配置一致:
<servlet> <servlet-name>spring-mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-web.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
以此例,那么@Controller需要使用Properties属性时,它们的配置信息应该放置在spring-web.xml中,你放置在Spring-context.xml等类似于的文件是不可行的,因为SpringMVC中“Servlet容器”和“Spring组件容器”来自不同的BeanFactory,所以@Controllor和@Service、@Component、@Resource等需要区别对待。
为了避免乱码,我们需要在所有声明properties加载的地方,都强制指定encoding,此外建议大家将spring基线版本升级到4.3.X+。
二、基于注释
Spring 3.1+提供了一个比较便捷的注解,@PropertySource,可以帮助我们在springMVC、springBoot环境下直接使用。
@PropertySource(value = "classpath:test3.properties",encoding = "UTF-8") @Controller public class IndexController { @Value("${test.name}") private String testName; .... }
@PropertySource注意可以在任意Spring Bean组件中使用;但是还是那句话,@Controller和@Service、@Component等可能需要各自配置;此外建议创建@Configuration的配置管理类,将这些Properties只加载一次、以Bean的方式export以供所有组件共享使用。不要忘记“encoding”属性。