首页 > 代码库 > 《Spring揭秘》——IOC梳理3(资源加载,国际化)
《Spring揭秘》——IOC梳理3(资源加载,国际化)
资源访问
JDK提供的访问资源的类并不能很好的满足各类资源访问需求,Spring提供了Resource接口以实现更强大的访问底层资源的能力。
Resource具体实现类:
ByteArrayResource :二进制数组表示的资源,二进制数组资源可以在内存中通过持续构造;
ClassPathResource :类路径下的资源,资源以相对于类路径的方式表示;
FileSystemResource :文件系统资源,资源以文件系统路径的方式表示;
UrlResource :封装了java.net.URL,使用户能够访问任何可以通过URL表示的资源;
InputStreamResource :以输入流返回表示的资源;
ServletContextResource:为访问Web容器上下文中的资源而设计的类,负责Web应用根目录的路径加载资源;
Resource res1 = new FileSystemResource("D:/c3/file.txt"); Resource res2 = new ClassPathResource("conf/file.txt"); InputStream ins1 = res1.getInputStream(); InputStream ins2 = res2.getInputStream();
//资源文件默认采用系统编码读取资源内容,若要采用特殊编码格式,则使用EncodeResource对象资源进行编码 EncodedResource encRes = new EncodedResource(res2, "UTF-8");
资源地址表达式:
- classpath:从类路径加载资源。classpath*则是指若在多个jar包或文件吸引类路径都拥有一个相同的包名,classpath只会在第一个加载的包下查找,而classpath*会扫描所有类路径下出现的该路径。(注意:ClassPathXmlApplicationContext在即使没有指明classpath情况下,默认从classpath中加载bean定义配置文件。而FileSystemXmlApplicationContext默认从文件系统中加载,若增加classpath:前缀会明确指定从classpath中加载bean定义的配置文件。)
- file:从文件系统目录加载资源,可采用绝对路径或相对路径;
- http:// :从Web服务器中加载资源
- ftp:// :从FTP服务器中装载资源
- 没有前缀:根据ApplicationContext具体实现类采用对应的类型的Resource
Ant风格资源地址表达式:
- ?:匹配文件名中的一个字符;
- *:匹配文件名中的任意个字符;
- **:匹配多层路径;
资源加载
查找和定位资源可使用ResourceLoader,其getResource方法可以根据一个资源地址加载文件资源(仅支持带资源类型前缀的表达式,不支持Ant风格的资源路径表达式)。
ResourcePatternResolver扩展ResourceLoader接口,其getResource方法支持带资源类型前缀及Ant风格的资源路径表达式。PathMatchingResourcePatternResolver是其标准实现类。
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources("classpath*:com/abc/**/*.xml");
要注意的是:在构造PathMatchingResourcePatternResolver实例时,若不指定ResourceLoader,其内部会默认构造一个DefaultResourceLoader实例,内部会将匹配后确定的资源路径委派给他的ResourceLoader来查找和定位资源。可以通过传入其他类型的ResourceLoader来替换内部默认使用的DefaultResourceLoader,从而改变其默认行为,如使用FileSystemResourceLoader ,使PathMatchingResourcePatternResolver的行为跟FileSystemResourceLoader一样。
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(new FileSystemResourceLoader());
此外,如果一个类需要使用ResourceLoader,需要进行ResourceLoader注入时,可以让该类实现ResourceLoaderAware或者ApplicationContextAware接口。(具体参照P91)
总结(p89)
ApplicationContext与ResourceLoader
ApplicationContext继承了ResourcePatternResolver,间接实现了ResourceLoader接口。 所以ApplicationContext支持Spring内统一资源加载策略。
AbstractApplicationContext继承了DefaultResourceLoader,它的getResource(String)直接用DefaultResourceLoader的了。
AbstractApplicationContext类的内部声明有一个resourcePatternResolver,类型是ResourcePatternResolver,对应的实例类型为PathMatchingResourcePatternResolver 。
这样,整个ApplicationContext的实现类就完全可以支持ResourceLoader或者ResourcePatternResolver接口。
国际化(i18n)
“国际化信息”也称为“本地化信息”,包括“语言类型”和“国家/地区的类型”,中文(zh)、英语(en)、中国大陆(CN)、中国台湾(TW)、英国(EN)、美国(US)。
表示语言和国家/地区信息的本地化类为java.lang.Locale。创建本地化对象的示例:
Locale locale1 = Locale.getDefault(); Locale locale2 = Locale.CHINA; Locale locale3 = new Locale("zh", "CN");
此外,JDK中提供了几个支持本地化的格式化操作工具类:NumberFormat、DateFormat、MessageFormat。
//NumberFormat Locale locale = Locale.getDefault(); NumberFormat curFmt = NumberFormat.getCurrencyInstance(locale); System.out.println(curFmt.format(123.4)); //DateFormat DateFormat df = DateFormat.getDateInstance(DateFormat.LONG,locale); System.out.println(df.format(new Date())); //MessageFormat:提供了占位符字符串的格式化功能 String pattern1 = "hello,{0},{1}"; Object[] argu = {"Joey",new GregorianCalendar().getTime()}; System.out.println(MessageFormat.format(pattern1, argu)); //使用默认本地化对象格式化信息 MessageFormat mf = new MessageFormat(pattern1, Locale.US); System.out.println(mf.format(argu)); //使用指定的本地化对象格式化信息
ResourceBundle
Java提供了用于加载本地化资源文件的类ResourceBoundle,其为加载及访问资源文件提供了便捷的操作,从类路径加载名为resource的本地化资源文件:
ResourceBundle rb1 = ResourceBundle.getBundle("com/test/resource",Locale.CHINA); ResourceBundle rb2 = ResourceBundle.getBundle("com/test/resource",Locale.US); System.out.println(rb1.getString("greeting.common")); System.out.println(rb2.getString("greeting.common"));
关于本地化资源文件:
若资源名为resource,若语言为英文,国家为美国,则对应的本地化资源文件为resource_en_US.properties。中国大陆地区为resource_zh_CN.properties。
如果指定的本地化资源文件不存在,按以下顺序尝试加载其他资源:本地系统默认本地化对象对应的资源(比如想要加拿大的但没有,系统默认为中国,则使用resource_zh_CN.properties)—>默认的资源(resource.properties)。若依然不存在则会抛出MissingResourceException异常。
MessageSource
Spring定义了访问国际化信息的MessageSource接口,并提供了几个易用的实现类:
- ResourceBundleMessageSource (最为常用,用于正式生产,对于参数化信息和非参数化信息的处理进行优化);
- StaticMessageSource (多用于测试,不应该用于正式的生产环境);
- ReloadableResourceBundleMessageSource(主要可以定期刷新并检查底层资源文件是否已经改变) ;
ResourceBundleMessageSource
允许用户通过beanName指定一个资源名或通过beanNames指定一组资源名。
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>com/ioc/test</value> </list> </property> </bean>
一般使用时,id可以是其他(比如myResource),通过ctx.getBean("myResource")获得MessageSource,紧接着对MessageSource操作即可。但ApplicationContext实现了MessageSource接口。默认情况下,ApplicationContext将委派容器中一个名称为messageSource的MessageSource接口实现来完成MessageSource应该完成的职责,如果找不到则ApplicationContext内部会默认实例化一个不包含任何内容的StaticMessageSource实例。(所以,若直接使用ApplicationContext处理国际化资源时,上面配置文件的id必须为messageSource。
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); String message = ctx.getMessage("greeting.common", null, Locale.CHINA); Object[] params = {...}; //若greeting.common中使用到占位符 String message = ctx.getMessage("greeting.common", params, Locale.CHINA);
ReloadableResourceBundleMessageSource
与ResourceBundleMessageSource唯一区别就是其定时刷新资源文件,已便在应用程序不重启的情况下感知资源文件的变化,避免重启带来的负面影响。注意:cacheSounds默认值为-1表示永不刷新。
使用ReloadableResourceBundleMessageSource时,应该避免将信息资源文件放到classpath中,因为这无助于ReloadableResourceBundleMessageSource定期加载文件变更。(api文档:Since application servers typically cache all files loaded from the classpath, it is necessary to store resources somewhere else (for example, in the "WEB-INF" directory of a web app).
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>com/test/test</value>
</list>
</property>
<property name="cacheSeconds" value="http://www.mamicode.com/3"></property>
</bean>
MessageSource类层次结构如下图(p98)
《Spring揭秘》——IOC梳理3(资源加载,国际化)