一 Spring Framework的核心:IoC
1 依赖反转模式和IoC容器
1.1 什么是依赖反转?
在面向对象系统中,对象封装了数据和对数据的处理,对象的依赖关系常常体现在对数据和方法的依赖上。
许多应用都是由一个或多个类通过彼此合作来实现业务逻辑的,这使得每个对象都需要与其合作的对象(也就是它所依赖的对象)的引用。如果这个过程要靠自身来实现,将会导致代码的高度耦合并且难以测试。
如果这些合作对象的引用和依赖关系的管理由另一个系统来控制和完成,就叫做依赖反转。
控制反转是关于一个对象如何获取它所依赖的对象的引用的。在这里,反转指责任的反转。
1.2 IoC容器
在Java语言里,Spring中的IoC容器就是对这种依赖控制反转的实现。
通过使用IoC容器,对象依赖关系的管理被反转了,转到IoC容器来了,对象之间的相互依赖关系由IoC容器进行管理,并由容器完成对象的注入。
1.3 具体描述
Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。
采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定。
2 Spring的IoC容器系列
2.1 入门容器
1)BeanFactory:定义了最基本的IoC容器的功能,也就是顶级父类。(就像水桶里最基本的规范 )
2)BeanDefinition:对依赖反转模中管理的对象依赖关系的数据抽象,是实现依赖反转功能的核心数据结构。(就像水桶里的水,有了这些基本数据,容器才能发挥作用)
ps:
IoC容器内部的数据结构,实际上是POJO对象在IoC容器中的抽象,定义了一系列的数据使得IoC容器能够方便地对POJO对象也就是Spring的Bean进行管理,即BeanDefinition就是Spring的领域对象。
如定义singleton、prototype、Aliase等。
3)XmlBeanFactory:此IoC容器可以读取以XML形式定义的BeanDefinition,是其直接父类DefaultListableBeanFactory的增强版。
XmlBeanFactory读取的原理:
类中初始化了一个XmlBeanDefinitionReader对象,对XML形式的信息进行处理。构造XmlBeanFactory这个IoC容器的时候,需要指定BeanDefinition的信息来源,而这个信息来源需要封装成Spring中的Resource类给出(Resource类是Spring用来封装I/O操作的类)。而我们的BeanDefinition信息是以xml文件形式存在的,那么可以用ClassPathResource cpr=new ClassPathResource("bean.xml");最后XmlBeanDefinitionReader对象调用loadBeanDefinitions从Resource中载入BeanDefinitions。
而DefaultListableBeanFactory不能直接使用各种定义的Resource,需要Spring通过BeanDefinitionReader处理这些信息。只是一个纯粹的IoC容器,但有利也有弊,使用DefaultListableBeanFactory这种更底层的IoC容器,能提高我们定制IoC容器的灵活性。
4)ApplicationContext:高级形态的IoC容器,除了那些简单拓展BeanFactory的功能。
还有以下附加服务:
①支持不同的信息源。(扩展了MessageSource接口)
②访问资源。体现在对ResourceLoader和Resource的支持上,这样从不同地方得到Bean定义的资源。(一般来说,具体ApplicationContext都继承了DefaultResourceLoader的子类)
③支持应用事件,事件与Bean的生命周期的结合为Bean的管理提供了便利。(继承了接口ApplicationEventPublisher)
④在ApplicationContext中提供的附加服务。
注:一般建议在开发应用时使用ApplicationContext作为IoC容器的基本形式。
2.2 IoC基本功能(即BeanFactory的功能实现)
转移符“&”:得到FactoryBean本身,而不是FactoryBean产生出来的对象。
containsBean:判断容器中是否存在指定名字的Bean。
isSington:判断指定了名字的Bean是否是Singleton类型的Bean。
isPrototype:判断指定了名字的Bean是否是Prototype类型的Bean。
isTypeMatch:判断指定了名字的Bean的Class类型是否是特定的Class类型。
getType:得到指定了名字的Bean的Class类型。
getAliases:得到指定了名字的Bean的所有别名。
2.3 IoC容器的初始化
1)定位
BeanDefinition的资源定位由ResourceLoader通过统一的Resource接口完成,这个Resource对各种形式的BeanDefinition的使用提供了统一接口。(水桶装水,先找水)
FileSystemResource:spring在文件系统中寻找以文件形式存在的Bean定义信息。
ClassPathResource:spring在类路径中寻找以文件形式存在的Bean定义信息
2)载入
将用户定义好的Bean表示成IoC容器内部的数据结构,即BeanDefinition。
3)注册
向IoC容器注册这些BeanDefinition的过程。通过调用BeanDefinitionRegistry接口的实现来完成,这个注册工程把载入过程中解析得到的BeanDefinition向IoC容器进行注册。IoC容器内部,是通过使用一个HashMap来持有这些BeanDefinition数据。
注意:
IoC容器和上下文的初始化一般不包含Bean依赖注入的实现。
一般情况下,依赖注入发生在应用第一次向容器通过getBean索取Bean时。
例外,在使用IoC容器时有一个预实例化的配置,这个预实例化时可以配置的,具体来说可以通过在Bean定义信息中的lazyinit属性来预设;有了这个预实例化特性,用户可以对容器初始化过程做一个微小的控制;从而改变这个被设置了lazyinit属性的Bean依赖注入的发生,使得这个Bean的依赖注入在IoC容器初始化时就预先完成了、
|
|