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核心实现
1,IOC概述
控制反转:程序所依赖对象的获取权利被反转了。
说的在普通一点就是:在程序运行中,需要许多对象之间的协作才能完成某个功能,当程序需要另一个对象去完成一个功能的时候,这个这个程序就会依 赖这个对象。在通常情况下,程序所依赖的对象可以通过程序本身创建,但是这样会导致代码的耦合度高,所以我们通过从外部给程序注入依赖对象,而不需要程序 本身去做这件事情。这样就实现了控制反转。
举个例子,当你创建一个 "人" 你需要 眼睛,鼻子,腿,胳膊,手。等等。程序需要自己去管理这些 依赖的对象。但是当使用IOC的方式的时候,程序则无需关注依赖对象。在创建"人" 的时候依赖的对象会已经注入到程序中。 并且当依赖的层级非常深或者复杂的时候,更能体现出IOC的优势。
2,IOC的实现
IOC 的实现主要是IOC的容器,IOC容器为开发者管理对象的依赖提供了很多便利和基础的服务。在Spring中提供了很多种IOC容器,例如两个主要的容器 系列,一种是实现了BeanFactory的简单IOC容器,这类容器实现了容器所需要的最基本功能,另一类就是ApplicationContext的 高级容器,在简单容器的基础上增加了许多功能和特性。
2.1 SpringIOC容器的设计
首先看如下图所示的IOC容器接口设计图,这张图描述了IOC容器接口的主要设计
一共有两条路径。
第一是 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实现。从这个角度看,这些方法就是容器的入口。
接口方法如下:
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
beanFactory接口提供了IOC容器的规范,在这个基础上Spring提供了一些IOC容器的实现类。接下来我们以XmlbeanFactory为例子,简单说明IOC容器的设计原理。
XmlbeanFactory 的继承结构如下
我 们可以看到这是一层一层扩展下来的。XmlbeanFactory 继承了DefaultListableFactory,这是一个非常重要的类,使我们经常用到的一个IOC实现。比如在设计Application的时候 就会用到它。在Spring中DefaultListableFactory是作为一个默认功能完整的IOC容器。XmlbeanFactory再继承了 DefaultListableFactory的基础上又扩展了自己的功能。从名字上就可以看出来是xml相关功能,实际上就是可以读取xml文件的信息 来定义BeanDefinition。
XmlbeanFactory会初始化一个XmlBeanDifinitionReader,有了这个对象那么就可以处理以XML形式的的BeanDefinition。现在有了处理信息的对象,接下来我们就需要知道BeanDefinition信息的来源。
像如下这样构造resource 然后传递给 XmlBeanFactory
ClassPathResource resource = new ClassPathResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(resource);
这样IOC容器就可以方便的定位到BeanDefinition的信息然后进行IOC容器的初始化和依赖注入。
XmlBeanFactory是在DefaultListableFactory的基础上扩展了XML相关的附加功能接下来看看是如何实现的。
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException{
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
可 以看出来,在构造方法中获取到了Resource对象,然后用XmlBeanDefinitionReader 这个对象进行 loadBeanDefinitions(resource)。loadBeanDefinitions同时也是IOC容器初始化的重要部分。
在上面这个例子中我我们看到XmlBeanFactory是继承自DefaultListableBeanFactory的。 DefaultListableBeanFactory是一个非常重要一个IOC容器的实现,比如ApplicationContext也是在这个类基础 上进行扩展的。通过继承DefaultListableBeanFactory来获得IOC容器的基本功能。
接下来我们通过编程式的方式去使用DefaultListableBeanFactory,这样我们可以更好的理解IOC容器的使用过程,还有一些关键类之间的关系。
//创建IOC配置文件的资源,这个抽象资源包含BeanDefinition的定义信息
ClassPathResource resource = new ClassPathResource("beans.xml");
//创建一个BeanFactory 这里使用DefaultListableBeanFactory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//创建一个BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML形式的BeanDefinition通过一个回调配置给BeanFactory
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//从定义好的资源位置读取配置信息,具体解析过程由XmlBeanDefinitionReader开完成。完成整个载入和注册Bean定义的时候,需要的IOC容器就建立起来了。整个时候就可以使用IOC容器了。
reader.loadBeanDefinitions(this);
二 ApplicationContext容器的设计原理
ApplicationContex具备了容器的基本功能的基础上,还进行了一定的扩展。添加了一些BeanFactory 不具备的功能,如下图接口。
- 支持不同的信息源 MessageSource 接口
- 访问资源 ResourceLoader 接口
- 支持应用事件 ApplicationEventPubliclisher 接口
- 提供其他的附加服务
接下来 我们用FileSystemXmlApplicationContext的实现做为例子来讲述ApplicationContext容器的设计原理
ApplicationContext的基本功能已经被FileSystemXmlApplicationContext的基类AbstractXmlApplicationContext实现了,所以接下来只需要关注这个类的自身设计的量个功能。
实例化此容器IOC容器的启动IOC容器的refresh过程。
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
refresh() 过程会有IOC容器启动过程中的一系列的复杂操作,以后会分析。现在只是对基类的一个调用。
自身设计的功能,从这个类的名字就可以看出来,是要从系统中加载xml定义的bean信息。
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
不同的上下文有不同的获取beanDefinition定义信息的方式。调用这个方法就可以获取到FileSystemResource资源的定位。
2.2 IOC容器的初始化过程
之前所提及的refresh()过程就标志着IOC容器的初始化开始启动。
IOC容器的初始化主要分为三个步骤,resource资源的定位,载入,注册。
- BeanDefinition的Resource资源的的定位
- BeanDefinition的载入和解析
- BeanDefinition在IOC容器中的