Spring源码分析之IoC(一)

栏目: Java · 发布时间: 7年前

什么是IoC

控制反转(Inversion of Control,缩写为IoC),是一种设计模式,用来解耦组件之间的耦合度。

IoC容器系列的设计与实现

在Spring IoC容器的设计中,有两种主要的容器系列:BeanFactory与ApplicationContext。

BeanFactory,IoC容器的接口定义,该系列容器提供的是最基本的IoC容器的功能。ApplicationContext,容器的高级形态,它通过继承 MessageSource,ResourceLoader,ApplicationEventPublisher接口,在简单容器的基础上,增加了许多对高级容器的支持。

在Spring提供的最基本的IoC容器的接口定义和实现的基础上,Spring通过定义BeanDefinition来管理基于Spring的应用中的各种对象以及他们直接的相互依赖关系。BeanDefinition 抽象了我们对 Bean的定义,是让容器起作用的主要数据类型。对 IOC 容器来说,BeanDefinition 就是对依赖反转模式中管理的对象依赖关系的数据抽象。也是容器实现依赖反转功能的核心数据结构。

BeanFactory接口定义的方法:

Spring源码分析之IoC(一)

BeanFactory容器的设计原理

BeanFactory接口提供了使用IoC容器的规范,我们以XmlBeanFactory的实现为例来说明简单IoC容器的设计原理。XmlBeanFactory类继承关系图:

Spring源码分析之IoC(一) XmlBeanFactory继承自DefaultListableBeanFactory类,DefaultListableBeanFactory包含了基本IoC容器所具有的重要功能,XmlBeanFactory在继承了DefaultListableBeanFactory容器的功能的同时,增加了新的功能,它是一个可以读取以XML文件定义的BeanDefinition的IoC容器,来看下具体实现:

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中,初始化了一个XmlBeanDefinitionReader对象,该对象用于对XML文件定义信息的处理。XmlBeanFactory构造函数需要传入一个Resource参数,该参数封装了BeanDefinition的来源信息。在构造方法中,XmlBeanDefinitionReader会调用loadBeanDefinitions方法来完成BeanDefinition的加载。

ApplicationContext容器的设计原理

Spring源码分析之IoC(一)

我们以常用的FileSystemXmlApplicationContext为例,debug源码来看下ApplicationContext容器的设计原理。

测试代码如下:

@Test
public void testApplicationContext() {
    ApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/bean.xml");
    context.getBean("helloWorld",HelloWorld.class).sayHello();
}
复制代码

进入 FileSystemXmlApplicationContext 的构造方法:

public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
    this(new String[] {configLocation}, true, null);
}
复制代码

该方法调用重载方法,传入三个参数:数组类型的configLocation,默认属性为true,父容器为null:

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();
    }
}
复制代码

该方法首先会调用父类的构造方法,参数为null,在跟进去之前,我们先看下FileSystemXmlApplicationContext类的继承结构:

Spring源码分析之IoC(一) super(parent)方法会一直往上调用其父类构造方法,直到AbstractApplicationContext:

public AbstractApplicationContext(ApplicationContext parent) {
    this();
    setParent(parent);
}
复制代码

this方法调用默认构造函数,为属性resourcePatternResolver赋值:

public AbstractApplicationContext() {
    this.resourcePatternResolver = getResourcePatternResolver();
}
复制代码
protected ResourcePatternResolver getResourcePatternResolver() {
    return new PathMatchingResourcePatternResolver(this);
}
复制代码

回到setConfigLocations(configLocations)方法,看下该方法的具体实现:

public void setConfigLocations(String... locations) {
    if (locations != null) {
        Assert.noNullElements(locations, "Config locations must not be null");
        this.configLocations = new String[locations.length];
        for (int i = 0; i < locations.length; i++) {
            this.configLocations[i] = resolvePath(locations[i]).trim();
        }
    }
    else {
        this.configLocations = null;
    }
}
复制代码

先画出方法时序图,跟着图一步步跟下去:

Spring源码分析之IoC(一)

该方法会调用resolvePath方法,解析路径,跟进去看下:

protected String resolvePath(String path) {
    return getEnvironment().resolveRequiredPlaceholders(path);
}
复制代码
public ConfigurableEnvironment getEnvironment() {
    if (this.environment == null) {
        this.environment = createEnvironment();
    }
    return this.environment;
}
复制代码
protected ConfigurableEnvironment createEnvironment() {
    return new StandardEnvironment();
}
复制代码

getEnvironment方法返回的是StandardEnvironment对象,该对象是标准环境,会自动注册System.getProperties() 和 System.getenv()到环境。

接下来,回到resolvePath方法,该方法会调用AbstractEnvironment类的resolveRequiredPlaceholders方法:

public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
    return this.propertyResolver.resolveRequiredPlaceholders(text);
}
复制代码
private final ConfigurablePropertyResolver propertyResolver =
        new PropertySourcesPropertyResolver(this.propertySources);
复制代码

此时propertyResolver属性已经有值了,紧接着会调用propertyResolver属性的resolveRequiredPlaceholders方法,我们先看下ConfigurablePropertyResolver继承结构:

Spring源码分析之IoC(一) 进入resolveRequiredPlaceholders方法看下,该方法在AbstractPropertyResolver中:

public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
    if (this.strictHelper == null) {
        this.strictHelper = createPlaceholderHelper(false);
    }
    return doResolvePlaceholders(text, this.strictHelper);
}
复制代码

该方法做了两件事:1.调用createPlaceholderHelper方法为属性strictHelper赋值;2.调用doResolvePlaceholders方法,该方法是具体解析方法。

其中属性strictHelper,类型为PropertyPlaceholderHelper,持有要解析的前缀后缀,我们看下该类属性

Spring源码分析之IoC(一) 继续跟进,会调用doResolvePlaceholders方法:

private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
    return helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() {
        @Override
        public String resolvePlaceholder(String placeholderName) {
            return getPropertyAsRawString(placeholderName);
        }
    });
}
复制代码

具体不在深入,讲了半天,我们来总结下setConfigLocations方法干了什么事情:解析FileSystemXmlApplicationContext构造函数中参数存在的占位符,并替换为真实值。如:

@Test
public void testApplicationContext() {
    Properties properties = System.getProperties();
    properties.setProperty("aaaa", "bbbb");
    properties.setProperty("bbbb", "src/main/resources/bean.xml");
    ApplicationContext context = new FileSystemXmlApplicationContext("${${aaaa}}");
    context.getBean("helloWorld",HelloWorld.class).sayHello();
}
复制代码

setConfigLocations方法会将 ${${aaaa}} ,递归解析为bbbb,然后查找对应的系统属性存在aaaa为key的value bbbb,然后再根据bbbb查找系统属性,替换为applicationContext.xml。

如果读完觉得有收获的话,欢迎点赞、关注、加公众号【Java在线】,查阅更多精彩历史!!!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Mechanics of Web Handling

The Mechanics of Web Handling

David R. Roisum

This unique book covers many aspects of web handling for manufacturing, converting, and printing. The book is applicable to any web including paper, film, foil, nonwovens, and textiles. The Mech......一起来看看 《The Mechanics of Web Handling》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

MD5 加密
MD5 加密

MD5 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具