Spring技术内幕(一):IOC容器

原理:依赖反转模式

合作对象的引用或依赖关系的管理交由容器或平台来完成,而不是具体的对象。


IOC容器接口体系

Spring技术内幕(一):IOC容器_第1张图片
IOC容器接口设计图.png
  • 实现BeanFactory接口的简单容器系列:实现了容器的最基本的功能
  • ApplicationContext应用上下文:容器的高级特性

BeanFactory容器设计原理(以XmlBeanFactory实现为例)

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);
    }
}
  • XmlBeanFactory继承DefaultListableBeanFactory容器(默认功能完整的IOC容器)
  • 通过XmlBeanDefinitionReader添加新功能

编程式使用IOC容器

注意观察IOC容器实现中的那些关键的类(Resource,DefaultListableBeanFactory和 BeanDenifitionReader)之间的相互关系。如何把IOC容器功能解耦,又如何结合在一起为IOC容器服务。以下代码都有注释:

/**
     * Created by 阿越.
     * 以编程的方式使用DefaultListableBeanFactory
     */
    public void testSpringIOC(){
        // 创建IOC配置文件抽象资源(含有BeanDefinition)
        ClassPathResource resource = new ClassPathResource("beans.xml");
        // 创建一个BeanFactory
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        // 载入BeanDenifition的读取器
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        // 读入配置信息
        reader.loadBeanDefinitions(resource);
    }

ApplicationContext容器设计原理

(以FileSystemXmlApplicationContext实现为例)

// 实例化这个应用上下文支持,启动IOC容器的refresh()
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

// 从文件系统中加载XML的Bean定义资源
@Override
    protected Resource getResourceByPath(String path) {
        if (path != null && path.startsWith("/")) {
            path = path.substring(1);
        }
        return new FileSystemResource(path);
    }
  • 与BeanFactory容器的设计原理相似,先以继承或构造方法的形式实现父类功能,在此基础上,添加自己的新功能。

IOC容器的初始化过程

  1. Resource定位:BeanDefinition的资源定位
  2. BeanDefinition的载入:把用户定义好的Bean表示成IOC容器内部数据结构BeanDefinition
  3. 向IOC容器注册BeanDefinition:把BeanDefinition注入到IOC内部的一个HashMap中
Bean定义的载入和依赖注入是两个独立的过程
  • Bean定义(BeanDefinition)的载入是在IOC容器初始化时完成
  • 依赖注入默认是在开发者第一次通过getBean向容器索取Bean的时完成
  • 设置lazyinit属性,使该Bean的依赖注入在IOC容器初始化时就预先完成
refresh():IOC容器初始化入口,载入BeanDefinition的入口

以FileSystemXmlApplicationContext为例

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            // IOC容器初始化入口   
            refresh();
        }
    }

之后过程图解如下(感兴趣的可以照着图看源码):


Spring技术内幕(一):IOC容器_第2张图片
BeanDefinition载入的交互过程.png
BeanDefinition在IOC容器中的注册

在DefaultListableBeanFactory实现BeanDefinitionRegistry接口,这个接口的实现完成BeanDefinition向容器的注册。具体实现可看源码。


IOC容器的依赖注入

getBean接口的实现触发依赖注入,是起点,内部用doGetBean()实现,之后会调用createBean。图解如下:


Spring技术内幕(一):IOC容器_第3张图片
依赖注入过程.png

参考资料:Spring技术内幕(第2版) 计文柯

你可能感兴趣的:(Spring技术内幕(一):IOC容器)