【Spring系列】- ApplicationContext

【Spring系列】- ApplicationContext


ApplicationContext构建于BeanFactory之上,除了拥有BeanFactory支持的所有功能之外,还进一步扩展了基本容器的功能,包括BeanFactoryPostProcessor、BeanPostProcessor以及其他特殊类型bean的自动识别、容器启动后bean实例的自动初始化、国际化的信息支持、容器内事件发布等

  • Spring为基本的BeanFactory类型容器提供了XmlBeanFactory实现。相应地,它也为ApplicationContext类型容器提供了以下几个常用的实现:
    • FileSystemXmlApplicationContext:从文件系统加载bean定义及相关资源的ApplicationContext实现
    • ClassPathXmlApplicationContext:从Classpath加载bean定义及相关资源的ApplicationContext实现
    • XmlWebApplicationContext:Spring提供的用于Web应用程序的ApplicationContext实现

一、统一资源加载策略

URL全名是Uniform Resource Locator(统一资源定位器),但有些名不副实

  • 说是统一资源定位,但基本实现却只限于网络形式发布的资源的查找和定位工作,基本上只提供了基于HTTP、FTP、File等协议(sun.net.www.protocol包下所支持的协议)的资源定位功能

    资源这个词的范围比较广义,资源可以任何形式存在,如以二进制对象形式存在、以字节流形式存在、以文件形式存在等;而且,资源也可以存在于任何场所,如文件系统中、Java应用的Classpath中,甚至存在于URL可以定位的地方

  • 其次,Java SE提供的标准类java.net.URL类的功能职责划分不清,资源的查找和资源的表示没有一个清晰的界限。当前情况是,资源查找后返回的形式多种多样,没有一个统一的抽象。理想情况下,资源查找完成后,返回给客户端的应该是一个统一的资源抽象接口,客户端要对资源进行什么样的处理,应该由资源抽象接口来界定,而不应该成为资源的定位者和查找者同时要关心的事情。

所以,针对于此,Spring提出了一套基于org.springframework.core.io.Resource和org.springframework.core.io.ResourceLoader接口的资源抽象和统一资源加载策略

二、Spring中的Resource

Spring框架内部使用Resource接口作为抽象了所有资源的 资源访问接口。该接口定义了7个方法,可以帮助我们查询资源状态、访问资源内容,甚至根据当前资源创建新的相对资源

可以根据资源的不同类型或资源所处的不同场合,给出相应的对Resource接口的具体实现。Spring框架提供了一些实现类:

  • ByteArrayResource: 将字节数组提供的数据作为一种资源进行封装,如果通过InputStream形式访问该类型的资源,该实现会根据字节数组的数据,构造相应的ByteArrayInputStream并返回

  • ClassPathResource: 该实现从Java应用程序的ClassPath中加载具体资源并进行封装,可以使用指定的类加载器进行资源加载,如: BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("..."));

  • FileSystemResource: 对java.io.File类型的封装,可以以文件或者URL的形式对该类型资源进行访问,只要能跟File打的交道,基本上跟FileSystemResource也可以

  • UrlResource: 通过java.net.URL进行的具体资源查找定位的实现类,内部委派URL进行具体的资源操作

  • InputStreamResource: 将给定的InputStream视为一种资源的Resource实现类,较为少用。可能的情况下,以ByteArrayResource以及其他形式资源实现代之

如果以上这些资源实现还不能满足要求,那么还可以根据相应场景自己实现Resource接口的实现类

三、ResourceLoader,“更广义的URL”

资源有了后,通过ResourceLoader来查找和定位这些资源,org.springframework.core.io.ResourceLoader接口是资源查找定位策略的统一抽象,具体的资源查找定位策略则由相应的ResourceLoader实现类给出

ResourceLoader实现类中,最主要的就是Resource getResource(String location);方法,通过它可以根据指定的资源位置,定位到具体的资源实例

1. 可用的 ResourceLoader

  • DefaultResourceLoader

    作为ResourceLoader默认的实现类,该类默认的资源查找处理逻辑如下:

    • 首先检查资源路径是否以classpath:前缀打头,如果是,则尝试构造ClassPathResource类型资源并返回
    • 否则,(a) 尝试通过URL,根据资源路径来定位资源,如果没有抛出MalformedURLException,有则会构造UrlResource类型的资源并返回;(b)如果还是无法根据资源路径定位指定的资源,则委派DefaultResourceLoader的getResourceByPath(String)方法来定位,构造一个实际上并不存在的ClassPathResource类型的资源并返回
  • FileSystemResourceLoader

    FileSystemResourceLoader继承自DefaultResourceLoader,但覆写了getResourceByPath(String)方法,使之从文件系统加载资源并返回FileSystemResource类型的资源

    避免了DefaultResourceLoader在最后getResourceByPath(String)方法上的不恰当处理,使我们可以取得预想的资源类型

2. ResourcePatternResolver,批量查找的ResourceLoader

  • ResourcePatternResolver接口是ResourceLoader接口的扩展(继承了),ResourceLoader每次只能根据资源路径返回确定的单个Resource实例,而ResourcePatternResolver则可以根据指定的资源路径匹配模式,每次返回多个Resource实例
  • ResourcePatternResolver引入了Resource[] getResources(String)方法定义,以支持根据路径匹配模式返回多个Resources的功能。它同时还引入了一种新的协议前缀classpath*:,针对这一点的支持,将由相应的子类实现给出
  • ResourcePatternResolver最常用的一个实现是PathMatchingResourcePatternResolver,该实现类支持ResourceLoader级别的资源加载,支持基于Ant风格的路径匹配模式(类似于**/.suffix之类的路径形式),支持ResourcePatternResolver新增加的classpath:前缀等
  • 在构造PathMatchingResourcePatternResolver实例的时候,可以指定一个ResourceLoader,如果不指定的话,则PathMatchingResourcePatternResolver内部会默认构造一个DefaultResourceLoader实例。PathMatchingResourcePatternResolver内部会将匹配后确定的资源路径,委派给它的ResourceLoader来查找和定位资源。这样,如果不指定任何ResourceLoader的话,PathMatchingResourcePatternResolver在加载资源的行为上会与DefaultResourceLoader基本相同,只存在返回的Resource数量上的差异

3. Spring的统一资源加载策略

在这里插入图片描述

三、ApplicationContext与 ResourceLoader

  • ApplicationContext支持Spring内统一资源加载策略的的原因:

    ApplicationContext继承了ResourcePatternResolver,当然就间接实现了ResourceLoader接口。故任何的ApplicationContext实现类都可以看作是一个ResourceLoader甚至ResourcePatternResolver

  • 通常,所有的ApplicationContext实现类会直接或者间接地继承AbstractApplicationContext

  • AbstractApplicationContext又继承了DefaultResourceLoader,它的getResource(String)自然用的DefaultResourceLoader;AbstractApplicationContext类的内部声明有一个resourcePatternResolver,类型是ResourcePatternResolver,对应的实例类型为PathMatchingResourcePatternResolver,PathMatchingResourcePatternResolver构造时,直接填的AbstractApplicationContext自身作为ResourceLoader

在这里插入图片描述

说白了,ApplicationContext的实现类在作为ResourceLoader或者ResourcePatternResolver时的行为,完全就是委派给了DefaultResourceLoader和PathMatchingResourcePatternResolver来做

故ApplicationContext可以有如下新功能:

1. 用于扮演 ResourceLoader

  • 既然ApplicationContext可以作为ResourceLoader或者ResourcePatternResolver来使用,故可以通过ApplicationContext的实现类来加载任何Spring支持的Resource类型

2. 用于 ResourceLoader类型的注入

  • 在大部分情况下,如果某个bean需要依赖于ResourceLoader来查找定位资源,我们可以为其注入容器中声明的某个具体的ResourceLoader实现。该bean也无需实现任何接口,直接通过构造方法注入或者setter方法注入规则声明依赖即可
  • 不过,ApplicationContext容器本身就是一个ResourceLoader,单独提供一个resourceLoader实例有些多于了。如果不介意bean定义依赖于Spring的API,那可以用Spring提供的几个对ApplicationContext特定的Aware接口,包括ResourceLoaderAware和ApplicationContextAware接口
    • Foo类通过实现上述接口之一,即可将当前的ApplicationContext容器作为ResourceLoader注入Foo类
    • 现在,容器启动时,ApplicationContext类型容器可以自动识别Aware接口,并将当前ApplicationContext容器本身注入到Foo类中

3. 用于 Resource类型的注入

  • 容器可以将bean定义文件中的字符串形式表达的信息,正确地转换成具体对象定义的依赖类型。对于那些Spring容器提供的默认的PropertyEditors无法识别的对象类型,我们可以提供自定义的PropertyEditor实现并注册到容器中,以供容器做类型转换的时候使用
  • BeanFactory容器不会为Resource类型提供相应的PropertyEditor,所以,如果想注入Resource类型的bean定义,就需要注册自定义的PropertyEditor到BeanFactory容器
  • 不过,对于ApplicationContext,无需这么做,因为ApplicationContext容器可以正确识别Resource类型并转换后注入相关对象,只需配置Resource依赖到配置文件就行了
  • 原因在于: ApplicationContext启动伊始,会通过一个ResourceEditorRegistrar来注册Spring提供的针对Resource类型的PropertyEditor实现到容器中,这个PropertyEditor叫做ResourceEditor。这样, ApplicationContext就可以正确地识别Resource类型的依赖了
  • ResourceEditor的实现:把配置文件中的路径让ApplicationContext作为ResourceLoader来定位一下

4. 特定情况下,ApplicationContext的 Resource加载行为

  • 特定的ApplicationContext容器实现,在作为ResourceLoader加载资源时,会有其特定的行为

  • 对于URL所接受的资源路径来说,通常开始都会有一个协议前缀,比如file:、http:、ftp:等。既然Spring使用UrlResource对URL定位查找的资源进行了抽象,那么,同样也支持这样类型的资源路径,在这个基础上,Spring还扩展了协议前缀的集合

    • ResourceLoader中增加了一种新的资源路径协议classpath:,ResourcePatternResolver增加了classpath*:
    • 这样就可以通过这些资源路径协议前缀,明确告知Spring容器要从classpath中加载资源,代码中配置中都能用
  • ApplicationContext容器的两种实现类ClassPathXmlApplicationContext和FileSystemXmlApplicationContext在处理资源加载时的默认行为有所不同

    • 当ClassPathXmlApplicationContext在实例化的时候,即使没有指明classpath:classpath*:等前缀,它会默认从classpath中加载bean定义配置文件,即以下两种实例化方式效果是相同的:
    ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml"); 
    ApplicationContext ctx = new 
        				ClassPathXmlApplicationContext("classpath:conf/appContext.xml"); 
    
    • 而FileSystemXmlApplicationContext则有些不同,如果代码中只有"conf/appContext.xml",而没有classpath:,它会尝试从文件系统中加载bean定义文件;增加classpath:前缀后才从classpath中加载bean定义的配置文件
    • 这时它对应的才是ClassPathResource类型的资源,而不是默认的FileSystemResource类型资源。FileSystemXmlApplicationContext之所以如此,是因为它与FileSystemResourceLoader一样,也覆写了DefaultResourceLoader的getResourceByPath(String)方法
  • 当容器实例化并启动完毕,要用相应容器作为ResourceLoader来加载其他资源时,各种ApplicationContext容器的实现类依然会有不同的表现

    • 对于ClassPathXmlApplicationContext,如果不指定路径之前的前缀,它会从Classpath中加载资源
    • 对于FileSystemXmlApplicationContext,它将从文件系统中加载该文件。但是,也可以在这个时候用classpath:前缀强制指定从Classpath中加载该文件
    <bean id="..." class="..."> 
    	<property name="..." value="classpath:conf/appContext.xml"/> 
    </bean>
    

四、国际化信息支持 I18n

要让我们的应用程序可以供全世界不同国家和地区的人们使用,应用程序就必须支持它所面向的国家和地区的语言文字,为不同的国家和地区的用户提供他们各自的语言文字信息

程序的国际化涉及许多的内容,如货币形式的格式化、时间的表现形式、各国家和地区的语言文字等

对于Java中的国际化信息处理,主要涉及两个类,即java.util.Locale和java.util.ResourceBundle

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值