首页 > 代码库 > spring技术内幕读书笔记之IoC容器的学习
spring技术内幕读书笔记之IoC容器的学习
第一篇:概念和设计原理
IoC容器的实现作为Spring的核心内容之一非常有必要拿来研究一下
1、概念
IoC(Inversion of Control,控制反转)必须思考的问题:哪些方面的控制被反转了?
对于这个问题,Martin Flower给出结论是:依赖对象的获得被反转了。基于此,他为控制反转创造了一个更好的名字:依赖注入。
SpringIoC模块是这一思想的一种实现,IoC容器把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,降低了组件之间的耦合度,利于功能复用,方便进行测试。
2、IoC容器的设计思想与实现
SpringIoC容器设计中有两个主要的容器系列:
① 实现了BeanFactory接口的简单容器系列,此类容器实现了容器最基本的功能。
② ApplicationContext应用上下文,视为容器的最高形态存在,在实现简单容器的基础上增加了许多面向框架的特性,对应用环境做了许多适配。
spring中IoC容器的设计可参考下图:
接下来对这两类容器进行详细分析,看他们是如何设计并实现的。
首先是BeanFactory
BeanFactory作为Spring最底层的一个IOC容器,只具备了对Bean管理的最基本的功能。
BeanFactory的定义:
public interface BeanFactory { //用 & 区分通过容器来获取BeanFactory产生的对象和获取FactoryBean本身 StringFACTORY_BEAN_PREFIX = "&"; //根据name取得IoC容器中管理的bean ObjectgetBean(String name) throws BeansException; <T>T getBean(String name, Class<T> requiredType) throws BeansException; <T>T getBean(Class<T> requiredType) throws BeansException; ObjectgetBean(String name, Object... args) throws BeansException; //判断是否有指定名字的bean booleancontainsBean(String name); //判断指定名字的bean是否是单例 booleanisSingleton(String name) throws NoSuchBeanDefinitionException; //判断指定名字的bean是否是prototype类型的 booleanisPrototype(String name) throws NoSuchBeanDefinitionException; //判断指定名字的bean是否是特定的class类型 booleanisTypeMatch(String name, Class<?> targetType) throwsNoSuchBeanDefinitionException; //获取指定名称bean的class类型 Class<?>getType(String name) throws NoSuchBeanDefinitionException; //获取指定名字bean的所有别名 String[]getAliases(String name); }
从BeanFactory的定义中可以看到容器的基本管理功能有哪些。
使用XmlBeanFactory进一步分析此类容器是如何实现的,先看XmlBeanFactory是如何定义:
public class XmlBeanFactory extendsDefaultListableBeanFactory { privatefinal XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); publicXmlBeanFactory(Resource resource) throws BeansException { this(resource,null); } publicXmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throwsBeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); } }
可以看到XmlBeanFactory继承了DefaultListableBeanFactory。
DefaultListableBeanFactory是AbstractAutowireCapableBeanFactory的子类,而AbstractAutowireCapableBeanFactory实现了AutowireCapableBeanFactory接口,正是AutowireCapableBeanFactory继承了BeanFactory。
DefaultListableBeanFactory包含了基本IoC容器所具有的重要功能,很多地方会用到,像ApplicationContext,在spring中实际上是把DefaultListableBeanFactory作为一个默认功能完整的IoC容器来使用。
继续说XmlBeanFactory,根据名称我们可以知道,XmlBeanFactory除了实现基本功能外,还增加了读取以XML文件定义的BeanDefeinition的功能。但XML文件定义的文件信息的处理并不是由XmlBeanFactory直接完成,而是在XmlBeanFactory中初始化了一个XmlBeanDefinitionReader,靠reader对象来处理。另外在构造XmlBeanFactory时需要指定BeanDefinition的来源,此来源需要封装成spring中的Resource类,Resource是spring中用来封装I/O操作的类,比如BeanDefinition信息是以XML的形式定义,那么可以使用像ClassPathResource res = new ClassPathResource("beans.xml");的方法构造Resource,然后传递给XmlBeanFactory的构造器,这样IoC容器就可以定位到需要的BeanDefinition信息来完成容器的初始化和依赖注入过程。
ClassPathResource res = newClassPathResource("SpringBeans.xml"); XmlBeanFactory factory = newXmlBeanFactory(res); User user =(User)factory.getBean("userBean");
这就是此类容器的设计与实现了,但实际应用中我们通常不会采用这类容器(XmlBeanFactory甚至已经Deprecated),一般会采用较高级的ApplicationContext容器。
在ApplicationContext的设计中,一方面它继承了BeanFactory体系中的ListableBeanFactory,AutowrieCapableBeanFactory,HirearchicableBeanFactory等接口,具备了BeanFactory的基本功能,另一方面它通过继承MessageSource,resourceLoader,ApplicationEventPublisher接口,让它拥有更高级的IoC容器特性。
使用FileSystemXmlApplicationContext这一常用类分析此类容器。
先看FileSystemXmlApplicationContext的定义:
public classFileSystemXmlApplicationContext extends AbstractXmlApplicationContext { publicFileSystemXmlApplicationContext() { } ... publicFileSystemXmlApplicationContext(String[] configLocations, boolean refresh,ApplicationContext parent)throws BeansException { super(parent); setConfigLocations(configLocations); if(refresh) { refresh(); } } @Override protectedResource getResourceByPath(String path) { if(path != null && path.startsWith("/")) { path= path.substring(1); } returnnew FileSystemResource(path); } }
代码中省略了一些构造器。
ApplicationContext应用上下文的主要内容已经在基类AbstractXmlApplicationContext中实现,在FileSystemXmlApplicationContext中,作为一个具体的应用上下文,需要实现与它自身相关的两个功能:
一个功能是,如果应用直接使用FileSystemXmlApplicationContext,对实例化这个应用上下文的支持,同时启动IoC容器的refresh()过程,这个refresh会牵涉一些列复杂操作,而且不同的容器实现这些操作是相似的,所以封装在基类中,这里直接调用。也是由此方法启动IoC容器的初始化过程。
另一个功能是FileSystemXmlApplicationContext怎样从系统文件中加载XML的bean定义资源有关。不同的应用上下文实现对应着不同放入读取BeanDefinition的方式。重写的getResourceByPath可以说明这一点。
具体的refresh和getResourceByPath方法是如何调用的,以及像上面例子中xml文件如何处理的将在下一节IoC容器初始化中会有详细的过程讲解。
那么此类容器使用起来很容易:
ApplicationContext context = new FileSystemXmlApplicationContext("SpringBeans.xml"); User user = (User) context.getBean("userBean");
第二篇:IoC容器的初始化>>
spring技术内幕读书笔记之IoC容器的学习