在以前的5个文章中咱们已经对 IOC, DI, AOP 和配置相关进行了一些了解,相信在此基础上能够帮助你们更好地去阅读 Spring 的源码git
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
1.用户配置bean定义 ---> 2.IOC容器加载bean定义
---> 3.IOC容器建立bean实例 ---> 4.使用IOC容器
复制代码
使用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>
复制代码
内部隐藏的BeanFactory是不多被关注的,提供给用户直观看到的就是ApplicationContext,我使用的是IDEA,能够点击类后打开navigate选项---Type Hierarchy---选择SuperTypes Hierarchy,观看它的继承体系,如下是它做为一个接口,又继承了什么接口post
既然它继承了上面6个接口,那它一定会有这6个接口相关的行为学习
EnvironmentCapable:取环境相关的参数,.properties文件
ListableBeanFactory:提供BeanFactorys行为
HierarchicalBeanFactory:父子容器
---提供bean分层管理的方式
且父容器没法访问子容器,子容器能够访问父容器,就好比只有儿子问老爸拿钱,没有父亲问儿子要钱的
MethodSource:国际化
ApplicationEventPublisher:应用的事件发布,好比应用的开启,结束,销毁等等
ResourcePatternResolver:加载Resource
复制代码
这些在后面咱们再展开来说···ui
那如何先大体地查看这幅图
先看 ConfigurableApplicationContext 这一大块,
ConfigurableApplicationContext 如下全是抽象的,一直到 FileSystemXmlApplicationContext
和 ClassPathXmlApplicationContext 两个xml配置方式的具体实现,
而下面的 GenericApplicationContext 则是通用实现,其中包括了通用xml,静态,动态语言Groovy和注解,
通用xml实现 GenericXmlApplicationContext 支持 FileSystemXmlApplicationContext 和 ClassPathXmlApplicationContext,
则不管放到文件系统或者classpath均可以
两大块 AbstractRefreshableApplicationContext 和 GenericApplicationContext
都继承了 AbstractApplicationContext
复制代码
做为一个接口确定加入了某些行为,咱们参考图左 structure 处,而后比照源码片断
此处加入了应用监听器,确定是使用了观察者模式,里面发生的事件均可以往外提供发布
经过这个 listener 就能够获取到
复制代码
此处看名字是否会有熟悉的感受,若是没有,能够回顾下 手写Spring---AOP面向切面编程(4)
在手写AOP的时候,postProcessor已经被说起,讲到了beanFactory如何可以灵活扩展,
可是咱们当时讲的是BeanPostProcessor,是对bean的建立过程实现阶段动态加强
那为何如今这个是 BeanFactoryPostProcessor 呢,那就是它把工厂的建立过程也引入了各个阶段
并且提供了各个阶段支持动态加强的功能
ApplicationContext会帮咱们完成bean定义的加载,解析等一系列过程,在此过程当中咱们可能须要灵活加入一些处理
复制代码
这里的refresh方法是刷新,刷新bean定义,IOC容器里面的bean实例
复制代码
此类中已经提供了不少的接口方法的实现,并且里面的定义都广泛具备了数据结构的支持
须要注意的是 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 的了,咱们如今先不细说
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry
复制代码
此时往下看
不难发现构造方法中,只有默认的 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());
}
复制代码
//---------------------------------------------------------------------
// 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);
}
复制代码
这样下来,咱们能大体了解最外层的 ApplciationContext 是如何一步步加入哪些参数的
此篇只是大体地看了一下 ApplicationContext 的子类所拥有的一些东西,可能你们看起来会以为一头雾水,下一篇会结合实例去进行使用而后一步步进行分析,可能篇幅就会增长。
有人反映了篇幅过长的问题,因此如今秉承少吃多餐的原则去慢更,望多多总结,互相进步··