IoC容器的实现
IoC容器和依赖反转模式
许多非凡的应用(比HelloWorld.java更加优美、复杂)都是有两个或多个类通过彼此的合作来实现业务逻辑,这使得每个对象都需要与其合作的对象(也即是它所依赖的对象)的引用。
如果这个获取过程要靠自身实现,那么如你所见,这将导致大妈高度耦合并难以测试。
关于如何反转对依赖的控制,把控制权从具体的业务对象手中转交到平台或框架中,是解决面向对象系统设计复杂性和提高面向对象系统可测试性的一个有效解决方案。
应用控制反转后,当对象被创建时,有一个调控系统内的所有对象的外界实体将其所依赖的对象的引用传递给它。依赖被注入到对象中。所以,控制反转是关于一个对象如何获取它所依赖的对象的引用的。
对象之间的相互依赖关系由IoC容器进行管理,并有容器完成对象的注入。
把应用从复杂的对象依赖关系管理中解放出来。
在面向对象编程中常常需要执行的诸如新建对象、给对象引用赋值等操作交由容器统一完成。
这些散落在不同代码中的功能相同的部分就集中成为容器的一部分。
Spring的IoC容器系列
BeanFactory和ApplicationContext都可以看成容器的具体实现形式。
IoC容器实际上代表着一系列功能各异的容器产品,只是容器功能有大有小、有各自的特点。
BeanFactory体现了Spring为用户使用IoC容器所设定的最基本功能规范。
BeanFactory作为一个最基本的接口类出现在Spring的IoC容器体系中。
Spring通过定义BeanDefinition来管理Spring应用中各种对象以及它们之间的相互依赖关系。
BeanDefinition抽象了我们对Bean的定义,是让容器起作用的主要数据类型。
BeanFactory对IoC容器的功能定义
提供了IoC容器所应该遵守的最基本的服务契约;同时,这也是我们使用IoC容器所应遵守的最底层的和最基本的编程规范。
1、用户使用容器的时候,可以使用转义符“&”来得到FactoryBean本身,用来区分通过容器获得FactoryBean产生的对象和获取FactoryBean本身。
/** * Used to dereference a instance and distinguish it from * beans created by the FactoryBean. */ String FACTORY_BEAN_PREFIX = "&";
IoC容器XmlBeanFactory的工作原理
继承了DefaultListableBeanFactory(默认的完整功能的IoC容器来使用),是一个与XML相关的BeanFactory,也就是说它可以读取以XML文件方式定义的BeanDefinition的一个IoC容器。
在XmlBeanFactory中,初始化了一个XmlBeanDefinitionReader对象,有了这个Reader对象,那些以XML的方式定义的BeanDefinition就有了处理的地方。对这些XML形式的信息的处理实际上是由这个XMLBeanDefinitionReader来实现的。
构建XmlBeanFactory这个IoC容器时,需要指定BeanDefinition的信息来源,而这个信息来源需要封装成Spring中的Resource类来给出。
Resource是Spring用来封装IO操作的类。
ClassPathResource res = new ClassPathResource("bean.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(res);
ApplicationContext的特点
可以通过编程的方式控制这些配置和容器建立过程,但是,在Spring中系统已经为用户提供了许多定义好的容器实现,而不需要开发人员事必躬亲。
1、支持不同的信息源,扩展了MessageResource
2、访问资源
3、支持应用事件,继承了接口ApplicationEventPublisher
IoC容器的初始化
BeanDefinition的Resource定位、载入和注册
Spring在实现中把这三个过程分开并使用不同的模块完成的,可以让用户更加灵活地对这三个过程进行剪裁和扩展。
定位:有ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用提供了统一接口。
载入:表示成IoC容器的内部数据结构BeanDefinition。
注册:向IoC容器注册这些BeanDefinition的过程。
在IoC容器内部,是通过一个HashMap来持有这些BeanDefinition数据的。
NOTE:
1、IoC容器和上下文初始化一般不包括Bean依赖注入的实现。一般而言,依赖注入发生在应用第一次向容器通过getBean索取Bean时。
2、有一个预实例化的过程,是可以配置的。具体来说就是通过在Bean定义信息中lazyinit属性来设定;有了这个预实例化的特性,用户可以对容器初始化过程作一个微小的调控