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);

  1. 创建Ioc配置文件的抽象资源,这个抽象资源包含来BeanDefinition的定义信息
  2. 创建一个BeanFactory,这里使用DefaultListableBeanFactory
  3. 创建来一个载入BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML文件形式的BeanDefinition,通过一个回调给BeanFactory
  4. 从定义好的资源位置读取信息,具体的解析过程由XmlBeanDefinitionReader来完成,完成整个载入和注册Bean定义之后,需要的Ioc容器就建立起来来,这个时候就能使用Ioc容器了

 

4. ApplicationContext

ApplicationContext是一个高级形态的Ioc容器,在BeanFactory的基础上添加了附加功能

可以从上图接口继承图发现

  1. 支持不同的信息源,扩展了MessageSource接口,这些信息源的扩展功能可以支持国际化的实现,为开发多语言版本的应用提供服务
  2. 访问资源,这一特性体现在ResourceLoader和Resource的支持上,这样我吗可以从不同地方得到Bean的定义资源,从不同的I/O途径得到Bean的定义信息
  3. 支持应用事件,继承了接口ApplicationEventPublisher,从而在上下文引入了事件机制,这些事件和Bean的生命周期的结合为Bean的管理提供了便利
  4. 在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定义资源有关