Spring6(五):Resources、i18n、Validation(1)+https://developer.aliyun.com/article/1556723
7.5 ResourceLoaderAware 接口
ResourceLoaderAware接口实现类的实例将获得一个ResourceLoader的引用,ResourceLoaderAware接口也提供了一个setResourceLoader()方法,该方法将由Spring容器负责调用,Spring容器会将一个ResourceLoader对象作为该方法的参数传入。
如果把实现ResourceLoaderAware接口的Bean类部署在Spring容器中,Spring容器会将自身当成ResourceLoader作为setResourceLoader()方法的参数传入。由于ApplicationContext的实现类都实现了ResourceLoader接口,Spring容器自身完全可作为ResorceLoader使用。
实验:演示ResourceLoaderAware使用
第一步 创建类,实现ResourceLoaderAware接口
package com.atguigu.spring6.resouceloader; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.ResourceLoader; public class TestBean implements ResourceLoaderAware { private ResourceLoader resourceLoader; //实现ResourceLoaderAware接口必须实现的方法 //如果把该Bean部署在Spring容器中,该方法将会有Spring容器负责调用。 //SPring容器调用该方法时,Spring会将自身作为参数传给该方法。 public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } //返回ResourceLoader对象的应用 public ResourceLoader getResourceLoader(){ return this.resourceLoader; } }
第二步 创建bean.xml文件,配置TestBean
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="testBean" class="com.atguigu.spring6.resouceloader.TestBean"></bean> </beans>
第三步 测试
package com.atguigu.spring6.resouceloader; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; public class Demo3 { public static void main(String[] args) { //Spring容器会将一个ResourceLoader对象作为该方法的参数传入 ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); TestBean testBean = ctx.getBean("testBean",TestBean.class); //获取ResourceLoader对象 ResourceLoader resourceLoader = testBean.getResourceLoader(); System.out.println("Spring容器将自身注入到ResourceLoaderAware Bean 中 ? :" + (resourceLoader == ctx)); //加载其他资源 Resource resource = resourceLoader.getResource("atguigu.txt"); System.out.println(resource.getFilename()); System.out.println(resource.getDescription()); } }
7.6 使用Resource 作为属性
前面介绍了 Spring 提供的资源访问策略,但这些依赖访问策略要么需要使用 Resource 实现类,要么需要使用 ApplicationContext 来获取资源。实际上,当应用程序中的 Bean 实例需要访问资源时,Spring 有更好的解决方法:直接利用依赖注入。从这个意义上来看,Spring 框架不仅充分利用了策略模式来简化资源访问,而且还将策略模式和 IoC 进行充分地结合,最大程度地简化了 Spring 资源访问。
归纳起来,如果 Bean 实例需要访问资源,有如下两种解决方案:
- 代码中获取 Resource 实例。
- 使用依赖注入。
对于第一种方式,当程序获取 Resource 实例时,总需要提供 Resource 所在的位置,不管通过 FileSystemResource 创建实例,还是通过 ClassPathResource 创建实例,或者通过 ApplicationContext 的 getResource() 方法获取实例,都需要提供资源位置。这意味着:资源所在的物理位置将被耦合到代码中,如果资源位置发生改变,则必须改写程序。因此,通常建议采用第二种方法,让 Spring 为 Bean 实例依赖注入资源。
实验:让Spring为Bean实例依赖注入资源
第一步 创建依赖注入类,定义属性和方法
package com.atguigu.spring6.resouceloader; import org.springframework.core.io.Resource; public class ResourceBean { private Resource res; public void setRes(Resource res) { this.res = res; } public Resource getRes() { return res; } public void parse(){ System.out.println(res.getFilename()); System.out.println(res.getDescription()); } }
第二步 创建spring配置文件,配置依赖注入
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="resourceBean" class="com.atguigu.spring6.resouceloader.ResourceBean" > <!-- 可以使用file:、http:、ftp:等前缀强制Spring采用对应的资源访问策略 --> <!-- 如果不采用任何前缀,则Spring将采用与该ApplicationContext相同的资源访问策略来访问资源 --> <property name="res" value="classpath:atguigu.txt"/> </bean> </beans>
第三步 测试
package com.atguigu.spring6.resouceloader; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Demo4 { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); ResourceBean resourceBean = ctx.getBean("resourceBean",ResourceBean.class); resourceBean.parse(); } }
7.7 应用程序上下文和资源路径
不管以怎样的方式创建ApplicationContext实例,都需要为ApplicationContext指定配置文件,Spring允许使用一份或多分XML配置文件。当程序创建ApplicationContext实例时,通常也是以Resource的方式来访问配置文件的,所以ApplicationContext完全支持ClassPathResource、FileSystemResource、ServletContextResource等资源访问方式。
ApplicationContext确定资源访问策略通常有两种方法:
(1)使用ApplicationContext实现类指定访问策略。
(2)使用前缀指定访问策略。
7.7.1 ApplicationContext实现类指定访问策略
创建ApplicationContext对象时,通常可以使用如下实现类:
(1) ClassPathXMLApplicationContext : 对应使用ClassPathResource进行资源访问。
(2)FileSystemXmlApplicationContext : 对应使用FileSystemResource进行资源访问。
(3)XmlWebApplicationContext : 对应使用ServletContextResource进行资源访问。
当使用ApplicationContext的不同实现类时,就意味着Spring使用响应的资源访问策略。
效果前面已经演示
7.7.2 使用前缀指定访问策略
实验一:classpath前缀使用
package com.atguigu.spring6.context; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.core.io.Resource; public class Demo1 { public static void main(String[] args) { /* * 通过搜索文件系统路径下的xml文件创建ApplicationContext, * 但通过指定classpath:前缀强制搜索类加载路径 * classpath:bean.xml * */ ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:bean.xml"); System.out.println(ctx); Resource resource = ctx.getResource("atguigu.txt"); System.out.println(resource.getFilename()); System.out.println(resource.getDescription()); } }
实验二:classpath通配符使用
classpath * :前缀提供了加载多个XML配置文件的能力,当使用classpath*:前缀来指定XML配置文件时,系统将搜索类加载路径,找到所有与文件名匹配的文件,分别加载文件中的配置定义,最后合并成一个ApplicationContext。
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:bean.xml"); System.out.println(ctx);
当使用classpath * :前缀时,Spring将会搜索类加载路径下所有满足该规则的配置文件。
如果不是采用classpath * :前缀,而是改为使用classpath:前缀,Spring则只加载第一个符合条件的XML文件
注意 :
classpath * : 前缀仅对ApplicationContext有效。实际情况是,创建ApplicationContext时,分别访问多个配置文件(通过ClassLoader的getResource方法实现)。因此,classpath * :前缀不可用于Resource。
使用三:通配符其他使用
一次性加载多个配置文件的方式:指定配置文件时使用通配符
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:bean*.xml");
Spring允许将classpath*:前缀和通配符结合使用:
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:bean*.xml");
8. 国际化:i18n
国际化也称作i18n,其来源是英文单词 internationalization的首末字符i和n,18为中间的字符数。由于软件发行可能面向多个国家,对于不同国家的用户,软件显示不同语言的过程就是国际化。通常来讲,软件中的国际化是通过配置文件来实现的,假设要支撑两种语言,那么就需要两个版本的配置文件。
8.1 Java国际化
(1)Java自身是支持国际化的,java.util.Locale用于指定当前用户所属的语言环境等信息,java.util.ResourceBundle用于查找绑定对应的资源文件。Locale包含了language信息和country信息,Locale创建默认locale对象时使用的静态方法:
/** * This method must be called only for creating the Locale.* * constants due to making shortcuts. */ private static Locale createConstant(String lang, String country) { BaseLocale base = BaseLocale.createInstance(lang, country); return getInstance(base, null); }
(2)配置文件命名规则:
basename_language_country.properties
必须遵循以上的命名规则,java才会识别。其中,basename是必须的,语言和国家是可选的。这里存在一个优先级概念,如果同时提供了messages.properties和messages_zh_CN.propertes两个配置文件,如果提供的locale符合en_CN,那么优先查找messages_en_CN.propertes配置文件,如果没查找到,再查找messages.properties配置文件。最后,提示下,所有的配置文件必须放在classpath中,一般放在resources目录下
(3)实验:演示Java国际化
第一步 创建子模块spring6-i18n,引入spring依赖
第二步 在resource目录下创建两个配置文件:messages_zh_CN.propertes和messages_en_GB.propertes
messages_en_GB.properties内容
test=GB test
messages_zh_CN.properties内容
test=China test
第三步 测试
package com.atguigu.spring6.javai18n; import java.util.Locale; import java.util.ResourceBundle; public class ResourceI18n { public static void main(String[] args) { ResourceBundle bundle1 = ResourceBundle.getBundle("messages", new Locale("zh", "CN")); String value1 = bundle1.getString("test"); System.out.println(value1); ResourceBundle bundle2 = ResourceBundle.getBundle("messages", new Locale("en","GB")); String value2 = bundle2.getString("test"); System.out.println(value2); } }
测试结果:
Spring6(五):Resources、i18n、Validation(3)+https://developer.aliyun.com/article/1556729