【1】Spring容器系列的设计与实现
1. BeanFactory和ApplicationContext
在spring Ioc容器的设计中,有两个主要的容器系列,一个是BeanFactory接口的简单容器系列,这个系列只实现了容器的最基本功能,另一个是ApplicationContext应用上下文,它作为容器的高级形式而存在,应用上下文在简单容器的基础上增加了许多面向框架的特性,同时对应用环境做了许多适配
在spring提供的基础Ioc容器的接口定义和实现基础上,spring通过定义BeanDefinition来管理基于spring的应用中的各种对象以及它们之间的相互依赖关系,BeanDefinition抽象了我们对于Bean的定义,BeanDefinition就是对依赖反转模式中管理的对象依赖关系的数据抽象,也是容器实现依赖反转功能的核心数据结构,依赖反转功能都是围绕这个BeanDefinition的处理完成的,概括来说,管理对象和对象之间依赖关系
2. Spring Ioc 容器的设计
BeanFactory
//定义IOC容器的基本方法,即IOC容器基本的功能
public interface BeanFactory {
//转义字符,用来取FactoryBean
String FACTORY_BEAN_PREFIX = "&";
//获取bean的方法,根据名字
Object getBean(String var1) throws BeansException;
//通过名字和类型获取bean
<T> T getBean(String var1, Class<T> var2) throws BeansException;
//通过类型获取
<T> T getBean(Class<T> var1) throws BeansException;
//通过名字和参数吧???这个var2暂时不清楚是啥,可能是参数的意思
Object getBean(String var1, Object... var2) throws BeansException;
//判断容器内是否包含这个名字的bean
boolean containsBean(String var1);
//是否单例
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
//是否原型
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
//bean的类型检查,var1名字的bean是否是var2类型
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
//var1名字的bean的类型是什么
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
//得到容器中bean名字var1的所有的别名,这些别名是用户在BeanDefinition中定义的
String[] getAliases(String var1);
}
ApplicationContext
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
String getId();
String getApplicationName();
String getDisplayName();
long getStartupDate();
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
在spring Ioc体系中有两条线,一条例如从BeanFactory开始,到XmlBeanFactory为止的,只实现Ioc容器基本功能,另一条例如实现着ApplicationContext的WebApplicationContext,不仅包含着BeanFactory的基本功能,还增加来许多对容器的高级特性。
3. BeanFactory容器设计原理
以XmlBeanFactory为例
XmlBeanFactory
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader;
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, (BeanFactory)null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader = new XmlBeanDefinitionReader(this);
this.reader.loadBeanDefinitions(resource);
}
}
这个类继承的是DefaultListableBeanFactory这个类,在spring当中实际上就是把DefaultListableBeanFactory作为一个默认功能完整的Ioc容器来使用,而XmlBeanFactory在继承DefaultListableBeanFactory功能的同时,增加来新功能,可以读取XML文件方式定义的BeanDefinition的Ioc容器
实现XML读取的功能是怎么实现的呢,对于这些实现并不是通过XmlBeanFactory实现,而是在类中初始化来一个XmlBeanDefinitionReader对象完成的
编程式使用Ioc容器
ClassPathResource res = new ClassPathResource("beans.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
- 创建Ioc配置文件的抽象资源,这个抽象资源包含来BeanDefinition的定义信息
- 创建一个BeanFactory,这里使用DefaultListableBeanFactory
- 创建来一个载入BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML文件形式的BeanDefinition,通过一个回调给BeanFactory
- 从定义好的资源位置读取信息,具体的解析过程由XmlBeanDefinitionReader来完成,完成整个载入和注册Bean定义之后,需要的Ioc容器就建立起来来,这个时候就能使用Ioc容器了
4. ApplicationContext
ApplicationContext是一个高级形态的Ioc容器,在BeanFactory的基础上添加了附加功能
可以从上图接口继承图发现
- 支持不同的信息源,扩展了MessageSource接口,这些信息源的扩展功能可以支持国际化的实现,为开发多语言版本的应用提供服务
- 访问资源,这一特性体现在ResourceLoader和Resource的支持上,这样我吗可以从不同地方得到Bean的定义资源,从不同的I/O途径得到Bean的定义信息
- 支持应用事件,继承了接口ApplicationEventPublisher,从而在上下文引入了事件机制,这些事件和Bean的生命周期的结合为Bean的管理提供了便利
- 在ApplicationContext提供的附加服务,这些服务使得基本Ioc容器的功能更加丰富
以FileSystemXmlApplicationContext为例
FileSystemXmlApplicationContext
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
public FileSystemXmlApplicationContext() {
}
public FileSystemXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[]{configLocation}, true, (ApplicationContext)null);
}
public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, (ApplicationContext)null);
}
public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
this(configLocations, true, parent);
}
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
this(configLocations, refresh, (ApplicationContext)null);
}
//实例化上下文支持,启动Ioc
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if (refresh) {
this.refresh();
}
}
//如何从系统中加载XML定义的Bean资源文件
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}
可以看出,Application应用上下文的主要功能已经在FileSystemXmlApplicationContext的基类AbstractXmlApplicationContext中实现了,在FileSystemXmlApplicationContext中,作为一个具体的应用上下文,只需要实现和它自身设计相关的两个功能
一个功能是,如果应用直接使用FileSystemXmlApplicationContext,对于实例化这个应用上下文支持,同时启动Ioc容器的refresh的过程,refresh过程会牵涉Ioc容器启动的一系列复杂操作
另一个功能是与FileSystemXmlApplicationContext设计具体相关,这部分与怎样从文件系统中加载XML的Bean定义资源有关