一、IOC接口设计

IOC容器设计的源码主要在spring-beans.jar、spring-context.jar这两个包中。IOC容器主要接口设计如下:

这里的接口设计有两条主线:BeanFactory和ApplicationContext

1、BeanFactory-->HierarchicalBeanFactory-->ConfigurableBeanFactory:这是BeanFactory的设计路线,BeanFactory定义了基本的IOC容器规范,HierarchicalBeanFactory中增加了getParentBeanFactory方法,具备了双亲IOC容器的管理功能;ConfigurableBeanFactory中新增一些配置功能。

2、ApplicationContext应用上下文接口:继承了HierarchicalBeanFactory、ListableBeanFactory等BeanFactory的子接口,这条分支使得ApplicationContext具备了IOC容器的基本功能;在继承MessageSource、ApplicationEventPublisher等接口的时候,使得ApplicationContext这个简单的IOC容器添加了许多高级容器的特性。ApplicationContext的子接口有ConfigurableApplicationContext以及在WEB环境下使用的WebApplicationContext。

二、BeanFactory的设计原理

public abstract interface BeanFactory
{
public static final String FACTORY_BEAN_PREFIX = "&"; public abstract Object getBean(String paramString)
throws BeansException; public abstract <T> T getBean(String paramString, Class<T> paramClass)
throws BeansException; public abstract <T> T getBean(Class<T> paramClass)
throws BeansException; public abstract Object getBean(String paramString, Object[] paramArrayOfObject)
throws BeansException; public abstract boolean containsBean(String paramString); public abstract boolean isSingleton(String paramString)
throws NoSuchBeanDefinitionException; public abstract boolean isPrototype(String paramString)
throws NoSuchBeanDefinitionException; public abstract boolean isTypeMatch(String paramString, Class<?> paramClass)
throws NoSuchBeanDefinitionException; public abstract Class<?> getType(String paramString)
throws NoSuchBeanDefinitionException; public abstract String[] getAliases(String paramString);
}

BeanFactory只是定义了IOC容器的基本轮廓,并没有给出容器的具体实现(这个后面详细介绍)。

先来讨论下BeanFactory和FactoryBean之间的区别

1、前者很好理解,就是Spring的一个类工厂,用它可以创建各种类型的Bean,最主要的方法就是getBean(String paramString)。而创建的各种类型的Bean中有一种比较特殊的Bean就是FactoryBean。

2、Spring容器中管理里两种Bean,一种是标准的Java Bean,从容器中获取的是类本身的实例;另外一种就是FactoryBean即工厂Bean,从容器中获取Bean的时候,返回的并不是类的一个实例,而是工厂Bean中getObject方法返回的对象。工厂Bean必须实现接口FactoryBean

工厂Bean---->SayHelloFactoryBeanImpl

public class SayHelloFactoryBeanImpl implements FactoryBean
{ public Object getObject()
throws Exception
{
return new UserBean();
} public Class getObjectType()
{
return UserBean.class;
} public boolean isSingleton()
{
return false;
}
}

工厂Bean返回的对象:UserBean

public class UserBean
{
public void show()
{
System.out.println("春天来了");
}
}

Spring配置文件:

<bean id="sayHelloBean" class="SayHelloFactoryBeanImpl"></bean>

测试类:

    ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Object bean = ctx.getBean("sayHelloBean");
Object bean1 = ctx.getBean("&sayHelloBean");
System.out.println(bean);
System.out.println(bean1);

执行结果:

UserBean@7225790e
SayHelloFactoryBeanImpl@54a097cc

从正常的情况下,从容器中获取ID为“sayHelloBean”的对象应该是SayHelloFactoryBeanImpl。但由于SayHelloFactoryBeanImpl实现了接口FactoryBean,这是一个工厂Bean,所以通过ID获取到的Bean是SayHelloFactoryBeanImpl类中getObject方法返回的对象。如果要获取FactoryBean自身的一个实例,必须通过&+BeanID的形式去获取。

网上有许多对工厂Bean总结归纳,如:工厂Bean是实现了FactoryBean接口的bean  它不是一个简单的Bean 而是一个生产或修饰对象生成的工厂Bean。这里我先Mark一下:为什么Spring要设计这种类型的Bean。

三、XmlBeanFactory的解读

XmlBeanFactory是IOC容器系列最底层的实现,它继承自DefaultListableBeanFactory这个类。而后者是Spring中非常重要的一个类,它是Spring容器中一个基本产品,可以把它当做一个默认的功能完整的IOC容器来使用。

XmlBeanFactory除了从DefaultListableBeanFactory继承到IOC容器基本功能之外,还新增了一些其他功能,从名称就可以猜测出来,它是一个可以读取以XML文件方式定义BeanDefinition的容器。

XmlBeanFactory源码如下:

 public class XmlBeanFactory extends DefaultListableBeanFactory
{
private final XmlBeanDefinitionReader reader; public XmlBeanFactory(Resource resource)
throws BeansException
{
this(resource, null);
} public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)
throws BeansException
{
super(parentBeanFactory); this.reader = new XmlBeanDefinitionReader(this); this.reader.loadBeanDefinitions(resource);
}
}

实际上,实现XML读取功能并不是直接由XmlBeanFactory来完成的。而是由XmlBeanFactory内部定义的XmlBeanDefinitionReader来进行处理的。在构造XmlBeanFactory容器的时候,需要给出BeanDefinition的信息来源,而这个信息来源需要封装成Spring中的Resource类的形式给出。

来看下一个基本的IOC容器的初始化过程:

1、创建IOC配置文件的抽象资源,也就是源码中的Resource,这个Resource中包含了BeanDefinition的定义信息。

2、通过构造函数创建一个BeanFactory。

3、创建一个载入BeanDefinition的读取器,即源码中的reader。这里使用XmlBeanDefinitionReader来载入XML文件形式的BeanDefinition。

4、调用reader的loadBeanDefinitions方法,来完成从Resource中载入BeanDefinition信息,从而完成IOC容器的初始化。

我们可以将上面的源码做简化,使用编程式的方式来表达IOC容器的初始化:

总结:DefaultListableBeanFactory是IOC容器的一个基类,XmlBeanFactory是在其基础上扩展而来的。而其他的IOC容器,例如ApplicationContext,它的实现原理和XmlBeanFactory类似,也是通过扩展DefaultListableBeanFactory来获取基本的IOC容器功能的。

四、ApplicationContext的设计原理

接口设计图:

1、ApplicationContext继承接口ListableBeanFactory、HierarchicalBeanFactory,实现了IOC容器的基本功能。

2、继承接口MessageSource:支持不同信息源,支持国际化的实现。

3、继承接口ResourceLoader:支持该容器可以从不同I/O途径得到Bean的定义信息。

4、继承接口ApplicationEventPublisher:在上下文中引入了事件机制。这些事件机制和Bean的生命周期结合为Bean的管理提供了便利。

ApplicationContext增加了这些附加功能,使得基本IOC容器的功能更加丰富,所以建议在开发应用的时候使用ApplicationContext作为IOC容器的基本形式。

ApplicationContext的设计原理

以子类FileSystemXmlApplicationContext的实现为例说明其设计原理。接口设计图如下:

这个接口设计中,ApplicationContext应用上下文的主要功能已经在FileSystemXmlApplicationContext的基类AbstractXmlApplicationContext中实现了,而FileSystemXmlApplicationContext作为一个具体的IOC容器,只需要实现和其本身相关的功能即可。

源码片段:

   public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException
{
super(parent);
setConfigLocations(configLocations);
if (refresh)
refresh();
} protected Resource getResourceByPath(String path)
{
if ((path != null) && (path.startsWith("/"))) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}

这里面有两个主要的方法:refresh()、getResourceByPath(String path)

1、refresh涉及到IOC容器启动的一系列操作,由于这个启动过程对于不同类型的容器来说都是相似的,所以这个启动过程被封装在基类中,具体的容器只需要调用即可。refresh方法后面会有详细介绍。

2、getResourceByPath这个方法是跟FileSystemXmlApplicationContext区别于其他具体容器的功能。通过这个方法可以让容器在文件系统中读取以XML形式存在的BeanDefinition。

Spring源码解析一:IOC容器设计的更多相关文章

  1. spring源码解析之IOC容器(一)

    学习优秀框架的源码,是提升个人技术水平必不可少的一个环节.如果只是停留在知道怎么用,但是不懂其中的来龙去脉,在技术的道路上注定走不长远.最近,学习了一段时间的spring源码,现在整理出来,以便日后温 ...

  2. spring源码解析之IOC容器(二)------加载和注册

    上一篇跟踪了IOC容器对配置文件的定位,现在我们继续跟踪代码,看看IOC容器是怎么加载和注册配置文件中的信息的.开始之前,首先我们先来了解一下IOC容器所使用的数据结构-------BeanDefin ...

  3. spring源码解析之IOC容器(三)——依赖注入

    上一篇主要是跟踪了IOC容器对bean标签进行解析之后存入Map中的过程,这些bean只是以BeanDefinition为载体单纯的存储起来了,并没有转换成一个个的对象,今天继续进行跟踪,看一看IOC ...

  4. spring源码解析之IOC容器(四)——属性注入

    上一篇跟踪了bean的创建过程,接下来,我们继续跟踪bean的属性填充的过程.先回到doCreateBean方法,代码如下: protected Object doCreateBean(final S ...

  5. 转 Spring源码剖析——核心IOC容器原理

    Spring源码剖析——核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring源码ioc编程bean 更多 个人分类: Java https://blog ...

  6. 【spring源码分析】IOC容器初始化(总结)

    前言:在经过前面十二篇文章的分析,对bean的加载流程大致梳理清楚了.因为内容过多,因此需要进行一个小总结. 经过前面十二篇文章的漫长分析,终于将xml配置文件中的bean,转换成我们实际所需要的真正 ...

  7. 【spring源码分析】IOC容器初始化(二)

    前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...

  8. 【spring源码分析】IOC容器初始化(三)

    前言:在[spring源码分析]IOC容器初始化(二)中已经得到了XML配置文件的Document实例,下面分析bean的注册过程. XmlBeanDefinitionReader#registerB ...

  9. 【spring源码分析】IOC容器初始化(四)

    前言:在[spring源码分析]IOC容器初始化(三)中已经分析了BeanDefinition注册之前的一些准备工作,下面将进入BeanDefinition注册的核心流程. //DefaultBean ...

  10. 【spring源码分析】IOC容器初始化(十)

    前言:前文[spring源码分析]IOC容器初始化(九)中分析了AbstractAutowireCapableBeanFactory#createBeanInstance方法中通过工厂方法创建bean ...

随机推荐

  1. js脚本语言(数组)

    定义:给数据Array(1,3.14,"aa")给长度(Array(5))使用方括号定义[1,3.14,"aa"] 属性:lenght(数据的长度) 方法:pu ...

  2. C++ 虚基类表指针字节对齐

    下面博客转载自别人的,我也是被这个问题坑了快两天了,关于各种虚基类,虚继承,虚函数以及数据成员等引发的一系列内存对齐的问题再次详细描述 先看下面这片代码.在这里我使用了一个空类K,不要被这个东西所迷惑 ...

  3. leetcode day8

    [83] Remove Duplicates from Sorted List Given a sorted linked list, delete all duplicates such that ...

  4. 虔诚的墓主人(bzoj 1227)

    Description 小W 是一片新造公墓的管理人.公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地.当地的居民都是非常虔诚的基督徒,他们愿意提前为自己 ...

  5. 最近iOS开发遇到的问题

    1)计算器,编辑框键盘: 2)类间参量引用传递: 3)饼状图: 4)折线图: 5)uicollection使用: 6)富文本开发: 7)separatorInset,layoutMargins uit ...

  6. html bottom html submit按钮表单控件与CSS美化

    一.html submit与bottom按钮基本语法结构 1.html submit按钮在input标签里设置type="submit"即可设置此表单控件为按钮. submit按钮 ...

  7. easyui datagrid行中点击a标签链接,行被选中,但是获取不到对应的参数

    easyui中使用比较多的就是datagrid了,表格中添加连接,点击跳转,为比较常用的方式;往往在点及标签后调用getSeleted方法会失效; 一.初始代码: {field: 'id',title ...

  8. RAC执行root.sh报libcap.so.1: cannot open shared object file

    Failed to create keys in the OLR, rc = 127, Message: /opt/app/11.2.0/grid/bin/clscfg.bin: error whil ...

  9. Oracle Job 语法和时间间隔的设定(转)

    http://blog.itpub.net/27157/viewspace-425567/ 初始化相关参数job_queue_processesalter system set job_queue_p ...

  10. storm遇到问题汇总

    http://www.reader8.cn/jiaocheng/20131023/2139887.html 错误1:在windows下运行ExclamationTopology或者WordCountT ...