Spring IOC 总览
最近这几个月的时间一直在看 Spring
的源码,学习的过程本身就是一个输入输出,反复循环的过程,经过这一段时间的学习,从以前只是使用的阶段到现在 Spring
的理解又有了一些新的认识。通过之后的文章来记录学习的过程。
在开始 Spring
IoC 之前,先来了解一下 控制反转与依赖倒置的设计思想。
控制反转,是指依赖对象的获得反转,也就是说这是一个解耦的过程。对象之间的依赖关系管理由具体对象来完成,会导致代码之间的耦合程度增强。因此对象之间的依赖关系,交由一个地方统管理(Ioc 容器)。
依赖倒置,控制反转将对象之间依赖关系的管理权交了出去,对象不需要自己维护依赖关系,而是通过 IoC 容器来完成。从对象的角度来说,依赖对象的获取从自己主动区创建,变成从容器中去获取。
控制反转的实现有很多种方式。经常会听到依赖查找和依赖注入。在Spring
中,IoC容器是实现这个模式的载体,依赖注入是主要的实现方式。所谓依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。在对象生成或者初始化的时候将数据注入到对象中(完成数据的注入),也可以通过将依赖对象的引用注入到对象的数据域中(通过对象的引用完成方法的调用)。
Spring 实现IoC 的思路和方法
IoC 统一集中处理对象之间的依赖关系。Spring
实现IOC的思路是提供一些配置信息用来描述类之间的依赖关系,然后有容器去解析这些配置信息,继而维护对象之间的依赖关系,前提是对象之间的依赖关系必须在类中定义好。
方法:
- 应用程序中提供类,提供依赖关系(属性或者构造方法)
- 把需要交给容器管理的对象通过配置信息告诉容器(xml,annotation、javaconfig)
- 把各个类之间的依赖关系通过配置信息告诉容器
Spring IoC 设计
Ioc被理解为一个容器,在Spring
中提供了一系列功能不同的容器,它们有不同的实现,完成不同的功能。当然Spring
中也提供的最基础容器,为IoC容器设定了最基本的功能规范。下面通过IoC接口设计图来一探究竟。
BeanFactory接口设计路径.jpg
上述图片中标注出两条BeanFactory接口的设计路径,一条是蓝色线条表示,一条红色线条表示。
-
从接口
BeanFactory
到HierarchicalBeanFactory
,再到ConfigurableBeanFactory
,是一条BeanFactory
设计路径。在BeanFactory
中定义了最基本的 IoC 容器的功能,包含有getBean()
IoC 中最基础的方法; 在HierarchicalBeanFactory
中继承了BeanFactory
接口,并增加了getParentBeanFactory()
的接口功能,使BeanFactory
具备了双亲 IoC 容器的管理功能;在ConfigurableBeanFactory
接口中,定义了一些BeanFactory
的配置功能,比如setParentBeanFactory()
设置双亲IoC容器,通过addBeanPostProcessor()
配置 Bean 后置处理器,等等。 -
从
BeanFactory
到ListableBeanFactory
,再到ApplicationContext
。这条路径是另一条主要的设计路径。ListableBeanFactory
和HierarchicalBeanFactory
两个接口连接BeanFactory
接口定义和ApplicationContext
应用上线文的接口定义。在ListableBeanFactory
中 细化了许多BeanFactory
的功能,如getBeanDefinitionNames()
接口方法;HierarchicalBeanFactory
如上所述。
从上图中可以看到 BeanFactory
是 IoC 容器的最基本的实现,是所有 IoC 容器实现的基类,其中规范的 IoC 容器 最基本的功能。 反观 ApplicationContext
是 IoC 容器的一种接口,是 BeanFactory
的子接口,但是他继承了 ResourcePatternResolver
、EnvironmentCapable
、MessageSource
、ApplicationEventPublisher
接口,在 BeanFactory
的基础上添加一些功能,使得容器可以支持一些更高级的特性。
依赖注入的方式
-
接口注入
-
setter注入
setter注入也称设值注入,IoC容器通过成员变量的setter方法来注入被依赖的对象。这种注入方式 简单、直观,因而在Spring的依赖注入中大量使用。
-
构造器注入
通过构造器来完成成员变量的注入,就是驱动Spring在底层以反射的方式执行带指定参数的构造器,当执行带 参数的构造器时,就可以利用构造器参数对成员变量执行初始化。
在 Spring Framework
中,仅使用构造函数和 setter 注入。下面先对这两张注入方式做一个简单的比较。
构造函数注入 | setter 注入 |
---|---|
没有部分注入 | 有部分注入 |
不会覆盖 setter 属性 | 会覆盖 setter 属性 |
任意修改都会创建一个新实例 | 任意修改不会创建一个新实例 |
适用于设置很多属性 | 适用于设置少量属性 |
BeanFactory
是 Spring
IoC 中最基础的类,在BeanFactory
中提供了最基本的IoC容器的功能,定义了IoC容器最基本的形式,并且提供了IoC 容器所应该遵循的最基本的原则。在Spring
中,BeanFactory
只是一个接口类,对IoC的基本功能做了封装。其实现 类,如DefaultListableBeanFactory
、XmlBeanFactory
、ApplicationContext等
都可以看成是IoC容器附加某种功能的具体实现。接下来从源码的角度看看,在这个接口类中都做了什么:
public interface BeanFactory {
/**
* 使用转义符"&"来得到 FactoryBean本身。用来区分通过容器获取 FactoryBean 产生的对象,和 FactoryBean 本身
* 举例:
* myObject 得到一个 FactoryBean (产生)修饰的对象
* &myObject 得到的是 FactoryBean 的工厂,用来产生 FactoryBean 的对象
* 区分 FactoryBean 和 BeanFactory
* FactoryBean 是对象,是一个能产生或者修饰对象生成的工厂 Bean
* BeanFactory 是对象工厂 也是就 IOC 容器,所有的 Bean 都是由 BeanFactory 进行管理
*/
String FACTORY_BEAN_PREFIX = "&";
/**
* 通过指定的名字获取Bean
*/
Object getBean(String name) throws BeansException;
/**
* 通过Bean的名称 和 类型 获取 Bean
*/
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
/**
* 通过Bean的名称 和 构造参数 获取 Bean
*/
Object getBean(String name, Object... args) throws BeansException;
/**
* 通过Bean的类型
*/
<T> T getBean(Class<T> requiredType) throws BeansException;
/**
* 通过Bean的类型 和 构造参数
*/
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
/**
* 方法用于获取指定bean的提供者,可以看到它返回的是一个ObjectProvider,其父级接口是ObjectFactory
*/
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
/**
* 通过ResolvableType获取ObjectProvider
*/
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
/**
* 通过指定的名字判断 工厂中是否定义 或者 已经注册了 一个 BeanDefinition
*/
boolean containsBean(String name);
/**
* 用来出查询指定名字的 bean 是否是单例(singleton)的,单例属性 是在 BeanDefinition 指定的
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
* 用来出查询指定名字的 bean 是否是原型(prototype)的,原型属性 是在 BeanDefinition 指定的
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
* 判断指定名字的 Bean 的 Class 类型是否是特定的 Class 类型
*/
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
/**
* 判断指定名字的 Bean 的 Class 类型是否是特定的 Class 类型
*/
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
/**
* 查询指定名字的 Bean 的 Class 类型
*/
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
/**
* 获取指定的名字的 Bean 的所有别名,别名是用户在 BeanDefinition 中自己定义的
*/
String[] getAliases(String name);
}
BeanFactory
接口设计了getBean()
方法,这个方法是IoC容器API的主要方法,通过这个方法, 可以取得IoC容器中管理的Bean
,Bean
的取得是通过指定的名字来索引的。如果需要在获取Bean
的时候对Bean
的类型 进行检查,BeanFactory
接口定义了带有参数的getBean()
方法,这个方法的使用与不带参数的方式类似,不同的是增加了对Bean
检索的类型的要求。