Spring源码学习---IOC容器

前言

在以前的5个文章中咱们已经对 IOC, DI, AOP 和配置相关进行了一些了解,相信在此基础上能够帮助你们更好地去阅读 Spring 的源码git

源码学习-IOC容器


① 注意事项

1.这里的源码版本号为 version 5.1.3.RELEASEgithub

2.源码获取地址 github.com/spring-proj…spring

3.jdk要在1.8以上,spring5中大量使用了lambda表达式,而lambda表达式在1.8后开始支持编程

4.使用指南:spring.io/guides数据结构

5.各个版本的介绍:github.com/spring-proj…maven

6.Spring5.x的版本新特性:github.com/spring-proj…ide


② IOC的步骤整理(若是已经忘记,请回到 手写Spring---IOC容器(1)

1.用户配置bean定义 ---> 2.IOC容器加载bean定义 
    ---> 3.IOC容器建立bean实例 ---> 4.使用IOC容器
复制代码

③ 使用Spring的入口和如何作好阅读源码的准备

使用Spring的入口为:ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext(...Service.xml);

前期准备:
    建立一个maven工程,仅引入Spring-Context包(注意版本号)便可
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
复制代码

④ 围绕 ApplicationContext 咱们须要了解的问题(会先大体阐述,还并未涉及具体实现)

1. ApplicationContext 就是IOC容器

内部隐藏的BeanFactory是不多被关注的,提供给用户直观看到的就是ApplicationContext,我使用的是IDEA,能够点击类后打开navigate选项---Type Hierarchy---选择SuperTypes Hierarchy,观看它的继承体系,如下是它做为一个接口,又继承了什么接口post

既然它继承了上面6个接口,那它一定会有这6个接口相关的行为学习

2. ApplicationContext 所继承的接口

EnvironmentCapable:取环境相关的参数,.properties文件
ListableBeanFactory:提供BeanFactorys行为
HierarchicalBeanFactory:父子容器
    ---提供bean分层管理的方式
        且父容器没法访问子容器,子容器能够访问父容器,就好比只有儿子问老爸拿钱,没有父亲问儿子要钱的
MethodSource:国际化
ApplicationEventPublisher:应用的事件发布,好比应用的开启,结束,销毁等等
ResourcePatternResolver:加载Resource
复制代码

这些在后面咱们再展开来说···ui

3.继承了 ApplicationContext 的接口

那如何先大体地查看这幅图

先看 ConfigurableApplicationContext 这一大块,
ConfigurableApplicationContext 如下全是抽象的,一直到 FileSystemXmlApplicationContext 
和 ClassPathXmlApplicationContext 两个xml配置方式的具体实现,

而下面的 GenericApplicationContext 则是通用实现,其中包括了通用xml,静态,动态语言Groovy和注解,
通用xml实现 GenericXmlApplicationContext 支持 FileSystemXmlApplicationContext 和 ClassPathXmlApplicationContext,
则不管放到文件系统或者classpath均可以

两大块 AbstractRefreshableApplicationContext 和 GenericApplicationContext 
都继承了 AbstractApplicationContext
复制代码
1、ConfigurableApplicationContext --- 可配置的 ApplicationContext

做为一个接口确定加入了某些行为,咱们参考图左 structure 处,而后比照源码片断


① void addApplicationListener(ApplicationListener<?> listener);
此处加入了应用监听器,确定是使用了观察者模式,里面发生的事件均可以往外提供发布
经过这个 listener 就能够获取到
复制代码

② void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);

此处看名字是否会有熟悉的感受,若是没有,能够回顾下 手写Spring---AOP面向切面编程(4)

在手写AOP的时候,postProcessor已经被说起,讲到了beanFactory如何可以灵活扩展,
可是咱们当时讲的是BeanPostProcessor,是对bean的建立过程实现阶段动态加强

那为何如今这个是 BeanFactoryPostProcessor 呢,那就是它把工厂的建立过程也引入了各个阶段
并且提供了各个阶段支持动态加强的功能

ApplicationContext会帮咱们完成bean定义的加载,解析等一系列过程,在此过程当中咱们可能须要灵活加入一些处理
复制代码

③ void refresh() throws BeansException, IllegalStateException;
这里的refresh方法是刷新,刷新bean定义,IOC容器里面的bean实例
复制代码

2、AbstractApplicationContext --- 抽象的 ApplicationContext 的实现

此类中已经提供了不少的接口方法的实现,并且里面的定义都广泛具备了数据结构的支持

须要注意的是 registerBeanPostProcessors() 方法是保护类型的,只能供子类调用

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
复制代码

以前说起到的 HierarchicalBeanFactory --- 父子容器在这里也有体现

好比它的一个构造器,此时这里父容器就已经给进来了

@Nullable
private ApplicationContext parent;

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

此时再看看在setParent()方法中,大体就是取得父容器的环境参数,而后进行一个比较 instanceof 与合并 merge 的事情

@Override
public void setParent(@Nullable ApplicationContext parent) {
	this.parent = parent;
	if (parent != null) {
		Environment parentEnvironment = parent.getEnvironment();
		if (parentEnvironment instanceof ConfigurableEnvironment) {
			getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
		}
	}
}
复制代码

而在此实现后的继续深刻扩展就是 AbstractRefreshableApplicationContext 和 AbstractRefreshableConfigApplicationContext , 刚刚在 ConfigurableApplicationContext 的第 ③ 点不是说起了一个 refresh() 方法吗,第一个就是可支持刷新的,第二个就是可支持刷新且又被配置的,再以后就是 xml 的了,咱们如今先不细说

3、GenericApplicationContext --- 通用的 ApplicationContext
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry
复制代码

此时往下看


1、构造方法

不难发现构造方法中,只有默认的 beanFactory 和父容器 parent 等做为参数,并无说起咱们能够给入 beanDefinition 的来源,好比 xml文件等等

private final DefaultListableBeanFactory beanFactory;

// 构造方法:

// 若是你没有传入beanFactory,那就是默认的
public GenericApplicationContext() {
	this.beanFactory = new DefaultListableBeanFactory();
}

// 也能够本身提供
public GenericApplicationContext(DefaultListableBeanFactory beanFactory) {
	Assert.notNull(beanFactory, "BeanFactory must not be null");
	this.beanFactory = beanFactory;
}
复制代码

和上面同样的套路,提供了setParent()方法

@Override
public void setParent(@Nullable ApplicationContext parent) {
	super.setParent(parent);
	this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory());
}
复制代码

2、模板方法 refreshBeanFactory() --- 实现了父类的保护类型的方法
//---------------------------------------------------------------------
// Implementations of AbstractApplicationContext's template methods
//---------------------------------------------------------------------

/**
 * Do nothing: We hold a single internal BeanFactory and rely on callers
 * to register beans through our public methods (or the BeanFactory's).
 * @see #registerBeanDefinition
 */
@Override
protected final void refreshBeanFactory() throws IllegalStateException {
	if (!this.refreshed.compareAndSet(false, true)) {
		throw new IllegalStateException(
				"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
	}
	this.beanFactory.setSerializationId(getId());
}

@Override
protected void cancelRefresh(BeansException ex) {
	this.beanFactory.setSerializationId(null);
	super.cancelRefresh(ex);
}
复制代码

3、接口 BeanDefinitionRegistry 要求提供的方法,包括实现注册bean定义等等


4、其余

这样下来,咱们能大体了解最外层的 ApplciationContext 是如何一步步加入哪些参数的


Finally

此篇只是大体地看了一下 ApplicationContext 的子类所拥有的一些东西,可能你们看起来会以为一头雾水,下一篇会结合实例去进行使用而后一步步进行分析,可能篇幅就会增长。

有人反映了篇幅过长的问题,因此如今秉承少吃多餐的原则去慢更,望多多总结,互相进步··

相关文章
相关标签/搜索