Spring总结之IOC篇

Spring

1.Spring演进:

  1. Spring框架所倡导的基于POJO(Plain Old Java Object,简单Java对象)的轻量级开发理念,就是从实际出发,立足于最基础的POJO(就好像我们的地球)。为了能够让这些基础的POJO构建出健壮而强大的应用,Spring框架就好像那包裹地球的大气层一样,为构筑应用的POJO提供了各种服务,进而创造了一套适宜用POJO进行轻量级开发的环境。
  2. 整个Spring框架构建在Core核心模块之上,它是整个框架的基础。AOP模块提供了一个轻便但功能强大的
    AOP框架,让我们可以AOP的形式增强各POJO的能力,进而补足OOP/OOSD之缺憾。
  3. Spring框架在Core核心模块和AOP模块的基础上,为我们提供了完备的数据访问和事务管理的抽象和集成服务。Spring框架中的事务管理抽象层是Spring AOP的最佳实践,它直接构建在Spring AOP的基础之上,为我们提供了编程式事务管理和声明式事务管理的完备支持。
  4. 为了简化各种Java EE服务(像JNDI、JMS以及JavaMail等)的使用,Spring框架为我们提供了针
    对这些Java EE服务的集成服务。
  5. 最后要提到的就是Web模块。在该模块中,Spring框架提供了一套自己的Web MVC框架,职责分
    明的角色划分让这套框架看起来十分地“醒目”。

不要只将Spring看作是一个IoC容器,也不要只将Spring与AOP挂钩Spring提供的远比这些东西要多得多。

Spring不仅仅是一个简化Java EE开发的轻量级框架,它更应该是一个简化任何Java应用的开发框架。

2.IOC

2.1. IOC概念:

  • Inversion of Control(控制反转),别名依赖注入(Dependency Injection)。IoC的理念就是,
    让别人为你服务!

在这里插入图片描述

通常,被注入对象会直接依赖于被依赖对象。但是,在IoC的场景中,二者之间通过IoC Service
Provider来打交道,所有的被注入对象和依赖对象现在由IoC Service Provider统一管理。被注入对象需要
什么,直接跟IoC Service Provider招呼一声,后者就会把相应的被依赖对象注入到被注入对象中,从而
达到IoC Service Provider为被注入对象服务的目的。IoC Service Provider在这里就是通常的IoC容器所充
当的角色。

在这里插入图片描述

2.2. IOC依赖注入的方式:

  • 三种依赖注入的方式,即构造方法注入(constructor injection)、setter方法注入(setter injection)以及接口注入(interface injection)。
  • 构造方法注入:被注入对象可以通过在其构造方法中声明依赖对象的参数列表,让外部(通常是IoC容器)知道它需要哪些依赖对象。IoC 会检查被注入对象的构造方法,取得它所需要的依赖对象列表,进而为其注
    入相应的对象。同一个对象是不可能被构造两次的,因此,被注入对象的构造乃至其整个生命周期,
    应该是由IoC 容器来管理的。
  • setter方法注入:对于JavaBean对象来说,通常会通过 setXXX() 和 getXXX() 方法来访问对应属性。这些 setXXX() 方法统称为setter方法, getXXX() 当然就称为getter方法。通过setter方法,可以更改相应的对象属性,通过getter方法,可以获得相应属性的状态。setter方法注入虽不像构造方法注入那样,让对象构造完成后即可使用,但相对来说更宽松一些,可以在对象构造完成后再注入。
  • 被注入对象如果想要IoC Service Provider 为其注入依赖对象,就必须实现这个接口。这个接口提供一个方法,用来为其注入以来对象。实现的接口和接口中声明的方法名都不重要,重要的是接口中声明方法的参数类型,必须是“被注入对象所依赖的类型”。

在这里插入图片描述

IoC是一种可以帮助我们解耦各业务对象间依赖关系的对象绑定方式!

3. IoC Service Provider之IOC容器:

  • 职责:业务对象的构建管理和业务对象间的依赖绑定
  • 如何管理对象间的依赖关系:IoC Service Provider同样需要知道自己所管理和掌握的被注入
    对象和依赖对象之间的对应关系。
  • 如何记录记录诸多对象之间的对应关系:1.直接编码 2. 配置文件 3. 注解(属性,构造器)

在这里插入图片描述

4. IOC容器之BeanFactory:

4.1. BeanFactory和ApplicationContext的区别:

  • Beanfactory

基础类型IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管对象的时候,才对 该受管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限。对于资源有限,并且功能要求不是很严格的场景, BeanFactory 是比较合适的IoC容器选择。

  • ApplicationContext:

    在 BeanFactory 的基础上构建,是相对比较高级的容器实现, ApplicationContext 所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。在那些系统资源充足,并且要求更多功能的场景中, ApplicationContext 类型的容器是比较合适的选择。

在这里插入图片描述

4.2. BeanFactory 的对象注册与依赖绑定方式:

  • BeanFactory中的方法:

    在这里插入图片描述

    ​ BeanFactory 接口只定义如何访问容器内管理的Bean的方法,各个 BeanFactory 的具体实现类负责具体Bean的注册以及管理工作。BeanDefinitionRegistry 接口定义抽象了Bean的注册逻辑。如下:

    在这里插入图片描述

  1. BeanFactory 相当于图书馆、BeanDefinition相当于图书,BeanDefinitionRegistry相当于书架。
  2. BeanDefinition 的实例(instance)与对象相对应,该BeanDefinition 的实例负责保存对象的所有必要信息,当客户端向 BeanFactory 请求相应对象的时候, BeanFactory 会通过这些信息为客户端返回一个完备可用的对象实例。
4.2.1 外部配置文件方式

支持Properties文件格式和XML文件格式。

通常情况下,需要根据不同的外部配置文件格式,给出相应的 BeanDefinitionReader 实现类,由 BeanDefinitionReader 的相应实现类负责将相应的配置文件内容读取并映射到 BeanDefinition ,然后将映射后的 BeanDefinition 注册到一个 BeanDefinitionRegistry ,之后, BeanDefinitionRegistry 即完成Bean的注册和加载。

BeanDefinitionRegistry beanRegistry = <某个BeanDefinitionRegistry 实现类,通常为
DefaultListableBeanFactory>;
BeanDefinitionReader beanDefinitionReader = new BeanDefinitionReaderImpl(beanRegistry);
beanDefinitionReader.loadBeanDefinitions("配置文件路径");
// 现在我们就取得了一个可用的BeanDefinitionRegistry实例
  • Properties配置格式的加载

  • XML配置文件的加载: 首先给出相应的BeanDefinitionReader 实现类 ,由 BeanDefinitionReader 的相应实

public static void main(String[] args)
{
	DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
	BeanFactory container = (BeanFactory)bindViaXMLFile(beanRegistry);
	FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");
	newsProvider.getAndPersistNews();
}
public static BeanFactory bindViaXMLFile(BeanDefinitionRegistry registry)
{
	XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry); 
	reader.loadBeanDefinitions("classpath:../news-config.xml");
	return (BeanFactory)registry;
	// 或者直接
	//return new XmlBeanFactory(new ClassPathResource("../news-config.xml"));
}
4.2.2 注解方式

@Autowired 是这里的主角,它的存在将告知Spring容器需要为当前对象注入哪些依赖对象。而
@Component 则是配合Spring 2.5中新的classpath-scanning功能使用的。

  • 使用时需要加入“触发器”:

    <context:component-scan base-package="cn.spring21.project.base.package"/>

< context:component-scan/> 会到指定的包(package)下面扫描标注有 @Component 的类,如果
找到,则将它们添加到容器进行管理,并根据它们所标注的 @Autowired 为这些类注入符合条件的依
赖对象。

4.3 BeanFactory 中 XML的使用

4.3.1 和

是XML配置文件中最顶层的元素,它下面可以包含0或者1个和多个以及或者。

在这里插入图片描述

  • 是XML配置文件中最顶层的文件, 可以设置如下几个属性:

    1. default-lazy-init 。默认值为 false,是否对所有的 进行延迟初始化
    2. default-autowire。 默认取值为 no ,可以 byName 、 byType 、 constructor 以及 autodetect
    3. default-dependency-check 。默认值为 none ,即不做依赖检查。
    4. default-init-method 。
    5. default-destroy-method 。
  • <bean id="djNewsListener" class="..impl.DowJonesNewsListener"
      name="/news/djNewsListener,dowJonesNewsListener">
    </bean>
    
    1. id: 唯一标志
    2. name: 别名,可以使用 id 不能使用的一些字符
    3. class 属性
  • 中构造方法注入

    1. 两种写法
    <bean id="djNewsProvider" class="..FXNewsProvider">
    	<constructor-arg>
    		<ref bean="djNewsListener"/>
    	</constructor-arg>
        <constructor-arg ref="djNewsPersister"/>
    </bean>
    
    1. type属性

    如果是想调用的是传入int类型的构造方法,怎么做呢?

    <bean id="mockBO" class="..MockBusinessObject">
    	<constructor-arg type="int">
    		<value>111111</value>
    	</constructor-arg>
    /bean>
    
    1. index属性

    当构造方法同时传入了多个类型相同的参数时,可以这样:

    <bean id="mockBO" class="..MockBusinessObject">
    	<constructor-arg value="11111"/>
    	<constructor-arg value="22222"/>
    </bean>
    

    或者

    <bean id="mockBO" class="..MockBusinessObject">
    	<constructor-arg index="1" value="11111"/>
    	<constructor-arg index="0" value="22222"/>
    </bean>
    

    此时,第一个属性的值是22222, 第二个属性的值是11111.

  • 中setter方法注入

<bean id="djNewsProvider" class="..FXNewsProvider">
	<property name="newsListener">
		<ref bean="djNewsListener"/>
	</property>
	<property name="newPersistener" ref="djNewsPersister"/>
</bean>

property 属性:name:指定该 将会注入的对象所对应的实例变量名称

​ ref/value:具体的依赖对象引用或者值

setter注入和构造器注入可以同时用

  • 和中可用的配置项

可配置:bean、ref、idref、value、null、list、set、map、props

value: 注入简单的数据类型

ref:指定引用对象的beanName

idref:为当前对象注入所依赖的对象的名称

内部bean: 只有当前一个对象引用时使用

  • depends-on

没有通过类似 < ref> 的元素明确指定对象A依赖于对象B的话,如何让容器在实例化对象A之前首先实例化对象B?

使用depengs-on:

<bean id="classAInstance" class="...ClassA" depends-on="configSetup"/>
<bean id="configSetup" class="SystemConfigurationSetup"/>
  • autowire

Spring根据bean定义的某些特点将相互依赖的某些bean直接自动绑定的功能

5中模式: no 、 byName 、 byType 、 constructor 和 autodetect

示例: byName:

public class Foo
{
private Bar emphasisAttribute;
	...
	// 相应的setter方法定义
}
public class Bar
{
	...
}
<bean id="fooBean" class="...Foo" autowire="byName">
</bean>
<bean id="emphasisAttribute" class="...Bar">
</bean>

第二个bean定义的 id 为 emphasisAttribute ,与 Foo 类中的实例变量名称相同。

  • dependency-check 依赖检查

  • lazy-init 延迟初始化( lazy-init ),主要针对ApplicationContext 容器, 设置某一个bean延迟初始化,但是还是得看有没有bean依赖它。

    我们还可以通过beans设置同意得延迟初始化:< beans default-lazy-init=“true” >


4.3.2 bean定义中的继承

使用继承关系配置的FXNewsProvider和SpecificFXNewsProvider,在声明subNewsProvider的时候,使用了parent属性,将其值定义为superNewsProvider,这样就继承了superNewsProvider定义的默认值,只需要将其特定的属性进行更改,而不要全部又重新定义一遍。

<bean id="superNewsProvider" class="..FXNewsProvider">
    <property name="newsListener">
        <ref bean="djNewsListener"/>
    </property>
    <property name="newPersistener">
        <ref bean="djNewsPersister"/>
    </property>
</bean>
<bean id="subNewsProvider" parent="superNewsProvider"
      class="..SpecificFXNewsProvider">
<property name="newsListener">
    <ref bean="specificNewsListener"/>
</property>
</bean>

使用模板化配置形式配置FXNewsProvider和SpecificFXNewsProvider,newsProviderTemplate的bean定义通过abstract属性声明为true,说明这个bean定义不需要实例化。该bean定义只是一个模板,不对应任何对象。superNewsProvider和subNewsProvider通过parent指向这个模板定义,就拥有了该模板定义的所有属性配置。

<bean id="newsProviderTemplate" abstract="true">
    <property name="newPersistener">
        <ref bean="djNewsPersister"/>
    </property>
</bean>
<bean id="superNewsProvider" parent="newsProviderTemplate"
        class="..FXNewsProvider">
    <property name="newsListener">
        <ref bean="djNewsListener"/>
    </property>
</bean>
<bean id="subNewsProvider" parent="newsProviderTemplate"
        class="..SpecificFXNewsProvider">
    <property name="newsListener">
        <ref bean="specificNewsListener"/>
    </property>
</bean>
4.3.3 bean的scope(single 和 prototype的作用范围)

scope用来声明容器中的对象所应该处的限定场景或者说该对象的存活时间

  • 使用:
DTD:
<bean id="mockObject1" class="...MockBusinessObject" singleton="false"/>
XSD:
<bean id="mockObject2" class="...MockBusinessObject" scope="prototype"/>
  • singleton

单例,Spring的IoC容器中只存在一个实例,所有对该对象的引用将共享这个实例。

该实例从容器启动,并因为第一次被请求而初始化之后,将一直存活到容器退出,也就是说,它与IoC容器“几乎”拥有相同的“寿命”。

  • protorype

原型, 容器在接到该类型对象的请求的时候,会每次都重新生成一个新的对象实例给请求方。

但是,只要对象实例返回给请求方时, 容器就不再拥有当前返回对象的引用,请求方需要自己负责当前返回对象的后继生命周期的管理工作,包括该对象的销毁。

对于那些请求方不能共享使用的对象类型,应该将其bean定义的scope设置为prototype,通常,声明
为prototype的scope的bean定义类型,都是一些有状态的,比如保存每个顾客信息的对象。

  • 其他用在网络中的,request、session和global session
4.3.4. 工厂方法和FactoryBean:
  • 针对使用工厂方法模式实例化对象的方式,Spring的IoC容器同样提供了对应的集成支持。

  • FactoryBean 是Spring容器提供的一种可以扩展容器对象实例化逻辑的接口。,它本身与其他注册到容器的对象一样,只是一个Bean而已,只不过,这种类型的Bean本身就是生产对象的工厂 (Factory)。

  • 当某些对象的实例化过程过于烦琐,通过XML配置过于复杂,使我们宁愿使用Java代码来完成这 个实例化过程的时候,或者,某些第三方库不能直接注册到Spring容器的时候,就可以实现 org.spring.framework.beans.factory.FactoryBean 接口,给出自己的对象实例化逻辑代码。

使用FactoryBean:
package org.springframework.beans.factory;

public interface FactoryBean<T> {
    T getObject() throws Exception;

    Class<?> getObjectType();

    boolean isSingleton();
}
  • getObject() 方法会返回该 FactoryBean “生产”的对象实例,我们需要实现该方法以给出自己
    的对象实例化逻辑;

使用实例:

  1. 继承FactoryBean
public class NextDayDateFactoryBean implements FactoryBean {
 public Object getObject() throws Exception {
	return new DateTime().plusDays(1);
 }
 public Class getObjectType() {
	return DateTime.class;
 }
 public boolean isSingleton() {
	return false;
 }
}
  1. XML定义
<bean id="nextDayDateDisplayer" class="...NextDayDateDisplayer">
	<property name="dateOfNextDay">
		<ref bean="nextDayDate"/>
	</property>
</bean>
<bean id="nextDayDate" class="...NextDayDateFactoryBean">
</bean>
  1. 可能上面看不到FactoryBean 的魔力到底在哪。 NextDayDateDisplayer 的定义如下:
public class NextDayDateDisplayer
{
	private DateTime dateOfNextDay;
	// 相应的setter方法
	// ...
}

NextDayDateDisplayer 所声明的依赖 dateOfNextDay 的类型为 DateTime ,而不是NextDayDateFactoryBean 。

  1. 如果一定要取得 FactoryBean 本身的话,可以通过在bean定义的 id 之前加前缀 & 来达到目的。
Object nextDayDate = container.getBean("nextDayDate");
assertTrue(nextDayDate instanceof DateTime);

Object factoryBean = container.getBean("&nextDayDate");
assertTrue(factoryBean instanceof FactoryBean);
assertTrue(factoryBean instanceof NextDayDateFactoryBean);
4.3.5. 方法注入和方法替换(偷梁换柱)
  • 方法注入:方法申明符合,的name属性指定需要注入的方法名,bean属性指定需要注入的对象。

    <public|protected> [abstract] <return-type> theMethodName(no-arguments);
    
    <bean id="newsBean" class="..domain.FXNewsBean" singleton="false">
    </bean>
    <bean id="mockPersister" class="..impl.MockNewsPersister">
    	<lookup-method name="getNewsBean" bean="newsBean"/>
    </bean>
    
  • 使用 BeanFactoryAware 接口

    让当前类中拥有一个BeanFactory的引用。

  • 使用ObjectFactoryCreatingFactoryBean

  • 方法替换:体现在方法的实现层面上,灵活替换或者说以新的方法实现覆盖掉原来某个方法的实现逻辑。

4.3. 容器背后的秘密

在这里插入图片描述

  • Spring的IoC容器所起的作用:它会以某种方式加载ConfigurationMetadata(通常也就是XML格式的配置信息),然后根据这些信息绑定整个系统的对象,最终组装成一个可用的基于轻量级容器的应用系统。 可以划分为两个阶段:容器启动阶段Bean实例化阶段。 Spring充分运用了这两个实现阶段的不同特点,在每个阶段都加入了相应的容器扩展点,以便我们可以根据具体场景的需要加入自定义的扩展逻辑。

在这里插入图片描述

  • 容器启动阶段可以使用BeanFactoryPostProcessor,该机制允许我们在容器实例化相应对象之前,对注册到容器的 BeanDefinition 所保存的信息做相应的修改。

4.4 了解Bean的一生

  • BeanFactory的getBean()方法可以显示调用和隐式调用,隐式调用有如下两种情况:
    1. 对于BeanFactory 来说,对象实例化默认采用延迟初始化。对象A第一次实例化的时候,会先实例化
      对象A所依赖的对象。
    2. ApplicationContext 启动之后会实例化所有的bean定义,即在启动阶段的活动完成之后,紧接着调用注册到该容器的所有bean定义的实例化方法getBean() 。可以查看AbstractApplicationContext 的refresh()方法。
  • Bean的实例化过程如下:

在这里插入图片描述

4.4.1 Bean的实例化 与 BeanWrapper
  • Bean的实例化(如何初始化bean实例):

    1. 使用“策略模式”来决定采用何种方式初始化bean实例。
    2. 通过反射或者CGLIB动态字节码生成来初始化相应的bean实例或者动态生成其子类 。
    3. org.springframework.beans.factory.support.InstantiationStrategy 定义是实例化策略的抽象接口,

    其直接子类 SimpleInstantiationStrategy 实现了简单的对象实例化功能,可以通过 反射来实例化对象实例,但不支持方法注入方式的对象实例化。 CglibSubclassingInstantiationStrategy 继承了 SimpleInstantiationStrategy 的以反射方式实例化对象的功能,并且通过CGLIB的动态字节码生成功能,该策略实现类可以动态生成某个类的子类,进而满足了方法注入所需的对象实例化需求。默认情况下,容器内部采用的是 CglibSubclassingInstantiationStrategy 。

  • BeanWrapper接口(Bean容器内部是如何设置对象属性):

    1. BeanWrapper 接口通常在Spring框架内部使用,它有一个实现类 org.springframework.beans.
      BeanWrapperImpl 。
    2. 作用: 对某个bean进行“包裹”,然后对这个“包裹”的bean进行操作,比如设置设置或者获取bean的相关属性值。
    3. 操作如下:
    Object provider = Class.forName("package.name.FXNewsProvider").newInstance();
    Object listener = Class.forName("package.name.DowJonesNewsListener").newInstance();
    Object persister = Class.forName("package.name.DowJonesNewsPersister").newInstance();
    
    BeanWrapper newsProvider = new BeanWrapperImpl(provider);
    newsProvider.setPropertyValue("newsListener", listener);
    newsProvider.setPropertyValue("newPersistener", persister);
    
4.4.2 BeanPostProcessor
  • 与 BeanFactoryPostProcessor 通常会处理容器内所有符合条件的 BeanDefinition 类似, BeanPostProcessor 会处理容器内所有符合条件的实例化后的对象实例。
  • 两个方法,postProcessBeforeInitialization 和 postProcessAfterInitialization, 前置处理和后置处理。
public interface BeanPostProcessor
{
	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
	Object postProcessAfterInitialization(Object bean, String beanName) throws 	BeansException;
}
  • 是对象实例化阶段强大的拓展点,需要拓展(?????)

4.4.3. InitializingBean 和 init-method

  • 接口:
public interface InitializingBean { 
	void afterPropertiesSet() throws Exception;
}
  • 作用:在对象实例化过程调用过“ BeanPostProcessor 的前置处理”之后,会接着检测当前对象是否实现了 InitializingBean 接口,如果是,则会调用其 afterPropertiesSet() 方法进一步调整对象实例的状态。
  • xml方式使用:可以降低侵入性, 使用 < bean> 的 init-method 属性。
  • 使用场景: 某些情况,某个业务对象实例化后,还不能处于可以使用状态。这个时候就可以让该业务对象实现该接口,并在方法 afterPropertiesSet()中完成对该业务对象的后续处理。
4.4.4. DisposableBean 与 destroy-method
  • 自定义的对象销毁方法,使用方法:实现DisposableBean 接口或者通过 < bean> 的 destroy-method 属性。
  • 如果实现了,就会为该对象注册一个用于对象销毁的回调(callback)。以便在这些singleton类型的对象实例销毁之前,执行销毁逻辑。
  • ApplicationContext 容器, addShutdownHook() 方式来调用相应bean对象的销毁逻辑。

5. IOC容器之ApplicationContext:

ApplicationContext 在 BeanFactory 的基础上构建,是相对比较高 级的容器实现,除了拥有 BeanFactory 的所有支持, ApplicationContext 还提供了其他高级特性,比如事件发布、国际化信息支持等,这些会在后面详述。ApplicationContext 所管理 的对象,在该类型容器启动之后,默认全部初始化并绑定完成。ApplicationContext在启动时就完成所有初始化,容器启动时间较之 BeanFactory 也会长一些。

  • 几个常规的实现: FileSystemXmlApplicationContext 、ClassPathXmlApplicationContext、XmlWebApplicationContext

5.1统一资源加载策略

  • Spring提出了一套基于 org.springframework.core.io.Resource 和org.springframework.core.io.ResourceLoader 接口的资源抽象和加载策略
5.1.1 Spring中的Resource

Spring框架内部使用 org.springframework.core.io.Resource 接口作为所有资源的抽象和访
问接口,如下:

在这里插入图片描述

该接口的方法可以帮助我们查询资源状态、访问资源内容,甚至根据当前资源创建新的相对资源。

Resource 接口可以根据资源的不同类型,或者资源所处的不同场合,给出相应的具体实现,Spring实现了一些如下:

  • ByteArrayResource
  • ClassPathResource
  • FileSystemResource
  • UrlResource
  • InputStreamResource
5.1.2 ResourceLoader 更广义的URL

作用: 查找、定位资源。 org.springframework.core.io.ResourceLoader 接口是资源查找定位策略的统一抽象

public interface ResourceLoader {
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
	Resource getResource(String location);
	ClassLoader getClassLoader();
}

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

  • DefaultResourceLoader实现类:

默认的的实现类,该类默认的资源查找逻辑如下:

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

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

  • ResourcePatternResolver ——批量查找的 ResourceLoader

    ResourcePatternResolver 则可以根据指定的资源路径匹配模式,每次返回多个 Resource 实例。而ResourceLoader只能返回一个

    1. 接口实现如下:
    public interface ResourcePatternResolver extends ResourceLoader {
    	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
    	Resource[] getResources(String locationPattern) throws IOException;
    }
    
  • 回顾与展望:

在这里插入图片描述

5.1.3 ApplicationContext 与 ResourceLoader

  • ApplicationContext 继承了 ResourcePatternResolver,所以,任何的 ApplicationContext 实现都可以看作是一个ResourceLoader 甚至 ResourcePatternResolver 。
  • 现在可以去回顾下图4.2, 可以看到AbstractApplicationContext继承了 DefaultResourceLoader,所以说它的getResouce(String)就是直接用的DefaultResourceLoader的了, AbstractApplicationContext 类的内部声明有一个 resourcePatternResolver,对应的实例类型为
    PathMatchingResourcePatternResolver ,之前说过PathMatchingResourcePatternResolver 构造的时候会接受一个 ResourceLoader ,那么现在直接把自己传进去就行了。
  • 根据以上, ApplicationContext 的实现类在作为 ResourceLoader 或者 ResourcePatternResolver 时候的行为,完全就是委派给了 PathMatchingResourcePatternResolver 和 DefaultResourceLoader 来做。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/gkq_tt/article/details/86637589