该来的总会来,spring源码我抵触好几年的东西,总该还了。。。。
1.1 IOC容器的实现
1.1.1 关于DI和IOC
可以说IOC与DI是相互依赖的概念,IOC是指依赖倒置原理,指的是可以在对象生成或初始化的时候直接将数据注入到对象中,也可以通过将对象引用注入到对象数据域中。
1.1.2 BeanFactory与ApplicationContext
这是Spring IOC容器中最重要的两个容器,一般设计线路有两种:
- 一个是实现Beanfactory接口的简单容器系列
- 另一个是ApplicationContext应用上下文,它作为高级容器的存在增强了许多面向框架的特性
2.1 IOC容器的设计
这里涉及的是主要接口关系,而具体的IOC容器都是在这个接口体系下实现的,比如DefaultListableBeanFactory,这个基本的容器的实现就是实现了ConfigurableBeanFactory接口从而成为一个简单的IOC容器。
基于这个最基本容器又可以做很多扩展,比如:XmlBeanFactory就是在DefaultListableBeanFactory的基础上做扩展实现的,ApplicationContext的实现也是如此。
关于这个高级容器ApplicationContext可以看到它继承了BeanFactory体系下的ListableBeanFactory和AutowireCapableBeanFactory等接口。具备了BeanFactory的基本功能。在此基础上通过继承MessageSource,ResourceLoadr等接口赋予了更高级的IOC容器特性。
2.1.1 BeanFactory的应用场景
在Spring中BeanFactory只是一个接口类,基于这个接口实现的简单容器譬如:DefaultListableBeanFactory,XmlBeanFactory等等。用户在使用容器的时候可以使用转移符号“&”来得到FactoryBean本身。
关于BeanFactory与FactoryBean前者是一个Bean在Spring中所有的Bean都是由BeanFactory来管理的。而后者是一个工厂,虽然也是一个Bean但是这个Bean不是一个简单的Bean,而是一个能够生产或者修饰对象生成的工厂Bean。
BeanFactory中定义了作为一个IOC容器最基本的功能:
- Object getBean()
- boolean containsBean()
- boolean isSingleton()
- boolean isPrototype()
- booolean isTypeMatch()
- Class getType()
- String[] getAliases()
2.1.2 BeanFactory的设计原理
XmlBeanFactory继承与DefaultListableBeanFactory,后者非常重要,它是一个我们经常要用到的一个IOC容器的实现,在设计ApplicationContext的时候也会用到这个基类。在Spring中实际上是把DefaultListableBeanFactory作为一个默认的功能完整的Ioc容器来使用的。下面是XmlBeanFactory的源码:
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* Create a new XmlBeanFactory with the given resource,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
/**
* Create a new XmlBeanFactory with the given input stream,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @param parentBeanFactory parent bean factory
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
创建一个IOC容器的基本步骤:
- 创建Ioc配置文件的抽象资源,这个抽象资源包括了BeanDefinition的定义信息
- 创建一个BeanFactory工厂一般用的是DefaultListableBeanFactory
- 创建一个载入BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML文件形式的BeanDefinition
- 从定义好的资源位置开始载入配置信息。完成整个资源定位,载入,注册这三个步骤后,需要的IOC容器就被建立起来了。
2.1.3 ApplicationContext的应用场景
不同于基于BeanFactory的设计线路,应用上下文多了如下特性:
- 支持不同的信息源,因为实现了MessageSource接口,这些信息源的扩展功能可以支持国际化的实现
- 访问资源。由于ResourceLoader和Resource接口的支持,我们可以从不同的地方获取BeanDefinition
- 支持应用事件
2.1.4 ApplicationContext的设计原理
/**
* Create a new FileSystemXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of file paths
* @param refresh whether to automatically refresh the context,
* loading all bean definitions and creating all singletons.
* Alternatively, call refresh manually after further configuring the context.
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
public FileSystemXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
// 设置配置文件集,字符串数组
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
FileSystemXmlApplicationContext继承与基类AbstractXmlApplicationContext。直接创建这样一个IOC容器实列的话会调用IOC容器的启动方法refresh()。
2.2 IOC容器的初始化过程
分为3个主要过程:
- Resource的定位,指的是BeanDefinition的定位,它由ResourceLoader通过统一的Resource接口来实现。比如文件系统中的BeanDefinition可以用FileSystemResouce来扫描,类路径中的bean信息可以用ClassPathResouce来扫描
- BeanDefinition信息的载入。具体来说就是将POJO对象中的方法字段抽象到IOC容器中
- IOC容器注册这些BeanDefinition的过程,这个过程是通过调用BeanDefinitionRegister接口来完成的,在IOC容器内部将这些Bean信息会注入到一个CurrentHashMap中。
Bean的载入和依赖注入是两个不同概念,bean载入不包含实列数据,而依赖注入发生在第一次通过getbean()方法从IOC容器中获取bean的时候。有一个例外就是bean开启了lazy-init那么在IOC容器初始化的时候该bean的依赖注入过程就已经完成了。