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。
- 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 配置文件:
- class="SayHelloFactoryBeanImpl">
测试类:
- 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 是 IOC 容器系列最底层的实现,它继承自 DefaultListableBeanFactory 这个类。而后者是 Spring 中非常重要的一个类,它是 Spring 容器中一个基本产品,可以把它当做一个默认的功能完整的 IOC 容器来使用。
XmlBeanFactory 除了从 DefaultListableBeanFactory 继承到 IOC 容器基本功能之外,还新增了一些其他功能,从名称就可以猜测出来,它是一个可以读取以 XML 文件方式定义 BeanDefinition 的容器。
XmlBeanFactory 源码如下:
- 1 public class XmlBeanFactory extends DefaultListableBeanFactory
- 2 {
- 3 private final XmlBeanDefinitionReader reader;
- 4
- 5 public XmlBeanFactory(Resource resource)
- 6 throws BeansException
- 7 {
- 8 this(resource, null);
- 9 }
- 10
- 11 public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)
- 12 throws BeansException
- 13 {
- 14 super(parentBeanFactory);
- 15
- 16 this.reader = new XmlBeanDefinitionReader(this);
- 17
- 18 this.reader.loadBeanDefinitions(resource);
- 19 }
- 20 }
实际上,实现 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 容器功能的。
接口设计图:
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 容器,只需要实现和其本身相关的功能即可。
源码片段:
- 1 public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) 2 throws BeansException 3 {
- 4 super(parent);
- 5 setConfigLocations(configLocations);
- 6
- if (refresh) 7 refresh();
- 8
- }
- 9 10 protected Resource getResourceByPath(String path) 11 {
- 12
- if ((path != null) && (path.startsWith("/"))) {
- 13 path = path.substring(1);
- 14
- }
- 15
- return new FileSystemResource(path);
- 16
- }
- 17
- }
这里面有两个主要的方法:refresh()、getResourceByPath(String path)
1、refresh 涉及到 IOC 容器启动的一系列操作,由于这个启动过程对于不同类型的容器来说都是相似的,所以这个启动过程被封装在基类中,具体的容器只需要调用即可。refresh 方法后面会有详细介绍。
2、getResourceByPath 这个方法是跟 FileSystemXmlApplicationContext 区别于其他具体容器的功能。通过这个方法可以让容器在文件系统中读取以 XML 形式存在的 BeanDefinition。
来源: http://www.cnblogs.com/dongguacai/p/6429503.html