spring源码解析(一)

 
 

Spring

读书笔记

  • Spring
  • Spring整体概述
    • 1,Spring设计目标与理念
    • 2,Spring整体架构
  • Spring核心实现
    • 1,IOC概述
    • 2,IOC的实现
      • 2.1 SpringIOC容器的设计
      • 2.2 IOC容器的初始化过程

 

Spring整体概述

 

1,Spring设计目标与理念

Spring 它是一个框架,但是其实可以称之为一个轻量级开发平台,目的是简化企业开发。利用IOC和AOP这两大核心搭建起来的平台。如果把Spring这个平台类 比成操作系统的话,Spring Framework(Core) 就是kernel,即为IOC和AOP模块。就像是操作系统通过kernel去管理进程调度,IOC则是管理对象。在这个核心的支持下,我们简化了 JavaEE的开发。
比如建立在这个核心上的一些服务 WEBMVC,JDBC,ORM和远程调用。有了这个核心,在加上Spring的开源,同时依赖开源社区的力量 才使得Spring不断的发展壮大,这样发展了很多子项目和新技术来提供更多的服务。

 

2,Spring整体架构

spring源码解析(一)
从图中我们可以看出Spring整体的架构,分层的思想和Spring的主要组件。
每个组件的应用就不具体描述了。想了解某一部分自行百度。

 

Spring核心实现

 

1,IOC概述

控制反转:程序所依赖对象的获取权利被反转了。

说的在普通一点就是:在程序运行中,需要许多对象之间的协作才能完成某个功能,当程序需要另一个对象去完成一个功能的时候,这个这个程序就会依 赖这个对象。在通常情况下,程序所依赖的对象可以通过程序本身创建,但是这样会导致代码的耦合度高,所以我们通过从外部给程序注入依赖对象,而不需要程序 本身去做这件事情。这样就实现了控制反转。
举个例子,当你创建一个 "人" 你需要 眼睛,鼻子,腿,胳膊,手。等等。程序需要自己去管理这些 依赖的对象。但是当使用IOC的方式的时候,程序则无需关注依赖对象。在创建"人" 的时候依赖的对象会已经注入到程序中。 并且当依赖的层级非常深或者复杂的时候,更能体现出IOC的优势。

 

2,IOC的实现

IOC 的实现主要是IOC的容器,IOC容器为开发者管理对象的依赖提供了很多便利和基础的服务。在Spring中提供了很多种IOC容器,例如两个主要的容器 系列,一种是实现了BeanFactory的简单IOC容器,这类容器实现了容器所需要的最基本功能,另一类就是ApplicationContext的 高级容器,在简单容器的基础上增加了许多功能和特性。

 

2.1 SpringIOC容器的设计

首先看如下图所示的IOC容器接口设计图,这张图描述了IOC容器接口的主要设计

spring源码解析(一)

一共有两条路径。

  • 第一是 BeanFactory 到 HierarchicalBeanFactory 到ConfigurableBeanFactory 通过这些接口设计的叠加d定义了BeanFactory就是简单IOC容器的基本功能

  • 第二条路径是 ApplicationContext相关路径,主要是从BeanFactory到ListableBeanFactory到Application在到 我们常用的WebApplication或者ConfigurableApplicationContext接口。我们之前也提到过 ApplicationContext是属于高级的容器因为它还继承了 MessageSource ResourceLoader ApplicationEventPublisher 通过这些添加了许多高级特性

上面所描述的都是接口的关系,而具体的IOC的实现都是在这个接口体系下实现的 比如DefaultListableBeanFactory 它就实现了ConfigurableBeanFactory,从而成为一个简单的IOC容器,像其他的容器比如 XmlBeanFactory 都是在DefaultListableBeanFactory的基础上进行扩展的 同样的ApplicationContext的实现也是类似的。

总的来说这个系统是以BeanFactory和ApplicationContext为核心的。BeanFactory是IOC容器的最基本的接口
ApplicationContext继承了BeanFactory接口体系中的 ListableBeanFactory,HierarchicalBeanFactory,AutowireCapableBeanFactory接口 从而具有了BeanFactory的基本功能 同时又继承了MessageSource ResourceLoader ApplicationEventPublisher接口这样就具备了高级功能,从而变身为高级容器。

一,BeanFactory容器的的设计原理
beanFactory 提供了一些检索获取bean的方法,可以很方便的从IOC容器中获取到所需要的Bean,从而忽略具体的IOC实现。从这个角度看,这些方法就是容器的入口。
接口方法如下:

 
  1. public interface BeanFactory {
  2. String FACTORY_BEAN_PREFIX = "&";
  3. Object getBean(String name) throws BeansException;
  4. <T> T getBean(String name, Class<T> requiredType) throws BeansException;
  5. <T> T getBean(Class<T> requiredType) throws BeansException;
  6. Object getBean(String name, Object... args) throws BeansException;
  7. boolean containsBean(String name);
  8. boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
  9. boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
  10. boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
  11. Class<?> getType(String name) throws NoSuchBeanDefinitionException;
  12. String[] getAliases(String name);
  13. }

beanFactory接口提供了IOC容器的规范,在这个基础上Spring提供了一些IOC容器的实现类。接下来我们以XmlbeanFactory为例子,简单说明IOC容器的设计原理。
XmlbeanFactory 的继承结构如下
spring源码解析(一)

我 们可以看到这是一层一层扩展下来的。XmlbeanFactory 继承了DefaultListableFactory,这是一个非常重要的类,使我们经常用到的一个IOC实现。比如在设计Application的时候 就会用到它。在Spring中DefaultListableFactory是作为一个默认功能完整的IOC容器。XmlbeanFactory再继承了 DefaultListableFactory的基础上又扩展了自己的功能。从名字上就可以看出来是xml相关功能,实际上就是可以读取xml文件的信息 来定义BeanDefinition。
XmlbeanFactory会初始化一个XmlBeanDifinitionReader,有了这个对象那么就可以处理以XML形式的的BeanDefinition。现在有了处理信息的对象,接下来我们就需要知道BeanDefinition信息的来源。
像如下这样构造resource 然后传递给 XmlBeanFactory

 
  1. ClassPathResource resource = new ClassPathResource("beans.xml");
  2. XmlBeanFactory factory = new XmlBeanFactory(resource);

这样IOC容器就可以方便的定位到BeanDefinition的信息然后进行IOC容器的初始化和依赖注入。
XmlBeanFactory是在DefaultListableFactory的基础上扩展了XML相关的附加功能接下来看看是如何实现的。

 
  1. public class XmlBeanFactory extends DefaultListableBeanFactory {
  2. private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
  3. public XmlBeanFactory(Resource resource) throws BeansException {
  4. this(resource, null);
  5. }
  6. public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException{
  7. super(parentBeanFactory);
  8. this.reader.loadBeanDefinitions(resource);
  9. }
  10. }

可 以看出来,在构造方法中获取到了Resource对象,然后用XmlBeanDefinitionReader 这个对象进行 loadBeanDefinitions(resource)。loadBeanDefinitions同时也是IOC容器初始化的重要部分。
在上面这个例子中我我们看到XmlBeanFactory是继承自DefaultListableBeanFactory的。 DefaultListableBeanFactory是一个非常重要一个IOC容器的实现,比如ApplicationContext也是在这个类基础 上进行扩展的。通过继承DefaultListableBeanFactory来获得IOC容器的基本功能。
接下来我们通过编程式的方式去使用DefaultListableBeanFactory,这样我们可以更好的理解IOC容器的使用过程,还有一些关键类之间的关系。

 
  1. //创建IOC配置文件的资源,这个抽象资源包含BeanDefinition的定义信息
  2. ClassPathResource resource = new ClassPathResource("beans.xml");
  3. //创建一个BeanFactory 这里使用DefaultListableBeanFactory
  4. DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
  5. //创建一个BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML形式的BeanDefinition通过一个回调配置给BeanFactory
  6. XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
  7. //从定义好的资源位置读取配置信息,具体解析过程由XmlBeanDefinitionReader开完成。完成整个载入和注册Bean定义的时候,需要的IOC容器就建立起来了。整个时候就可以使用IOC容器了。
  8. reader.loadBeanDefinitions(this);

二 ApplicationContext容器的设计原理
ApplicationContex具备了容器的基本功能的基础上,还进行了一定的扩展。添加了一些BeanFactory 不具备的功能,如下图接口。
spring源码解析(一)

  • 支持不同的信息源 MessageSource 接口
  • 访问资源 ResourceLoader 接口
  • 支持应用事件 ApplicationEventPubliclisher 接口
  • 提供其他的附加服务

接下来 我们用FileSystemXmlApplicationContext的实现做为例子来讲述ApplicationContext容器的设计原理
ApplicationContext的基本功能已经被FileSystemXmlApplicationContext的基类AbstractXmlApplicationContext实现了,所以接下来只需要关注这个类的自身设计的量个功能。

  1. 实例化此容器IOC容器的启动IOC容器的refresh过程。

    1. public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
    2. super(parent);
    3. setConfigLocations(configLocations);
    4. if (refresh) {
    5. refresh();
    6. }
    7. }

    refresh() 过程会有IOC容器启动过程中的一系列的复杂操作,以后会分析。现在只是对基类的一个调用。

  2. 自身设计的功能,从这个类的名字就可以看出来,是要从系统中加载xml定义的bean信息。

    1. protected Resource getResourceByPath(String path) {
    2. if (path != null && path.startsWith("/")) {
    3. path = path.substring(1);
    4. }
    5. return new FileSystemResource(path);
    6. }

    不同的上下文有不同的获取beanDefinition定义信息的方式。调用这个方法就可以获取到FileSystemResource资源的定位。

 

2.2 IOC容器的初始化过程

之前所提及的refresh()过程就标志着IOC容器的初始化开始启动。
IOC容器的初始化主要分为三个步骤,resource资源的定位,载入,注册。

  1. BeanDefinition的Resource资源的的定位
  2. BeanDefinition的载入和解析
  3. BeanDefinition在IOC容器中的

相关推荐