文章目录
概要
以前总是很忙,没有时间写博客,现在挤出时间写一些总结性及实用性的博客。
首先聊一下,之所以开始看源码,是因为随着自身对java的理解不断加深,感觉自己对技术架构方面很感兴趣。所以想深入了解一下开源框架的本质,看各种开源框架、jdk源码有一段时间了,也在源码上写了很多自己理解的注释,一直没有整体总结,偶尔想起来有一些思路,但是容易忘记,所以想做一些总结,每一个我觉得非常复杂的核心流程,我都会用一张或时许图、流程图来进行学习总结。
总的来说,spring的总体流程不是很复杂,但是细思极恐;每一个类、每一个方法的内部实现能牵扯出很多与之相关联的类;其中实现错综复杂,不过不管怎么难,带着设计模式的思想、以及多思考,多实践,多总结的角度,多看几遍,终归会有所收获(可以自己手绘一些uml时序图、流程图来加深理解)。
本文及后续文章主要基于spring 5.0源码分析spring 核心的 ioc和aop,首先缕清spring运行的整体脉络流程。由于注解驱动(无xml)的流行,本文不会涉及xml的上下文及容器刷新流程(注意:作者之前有使用过ssm,涉及过xml配置,个人觉得xml配置会让人思想上更容易理解spring容器、bean的定义等等,感觉现在直接使用spring boot的人可能渐渐忽略了spring才是基石)。
1.程序入口:加载配置类
本文主要采用AnnotationConfigApplicationContext 作为程序的起点。
public class MyApplication {
public static void main(String[] args) {
//spring上下文,启动一个spring应用程序。
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyApp.class);
Car bean =(Car) context.getBean("car");
System.out.println(bean.getColor()+bean.getPrice());
}
}
2.注解配置上下文AnnotationConfigApplicationContext
AnnotationConfigApplicationContext:注解配置上下文。
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
//this()由于继承关系,所以会先调用父类的构造方法,在调用子类的构造方法
/**
* @Author coyhzx
* @Description 类继承结构(暂不涉及接口)DefaultResourceLoader -> AbstractApplicationContext ->GenericApplicationContext -> AnnotationConfigApplicationContext
* {@link DefaultResourceLoader} 初始化当前线程的classLoader
* {@link AbstractApplicationContext} 初始化资源模式匹配解析器 PathMatchingResourcePatternResolver
* {@link GenericApplicationContext} 初始化 ioc底层容器 DefaultListableBeanFactory
* {@link AnnotationConfigApplicationContext} 初始化 reader 注解的bean的读取器,scanner 类路径的bean的扫描器
**/
this();
//componentClasses 注册单个组件bean
register(componentClasses);
//刷新容器
refresh();
}
AnnotationConfigApplicationContext的无参构造this();
public AnnotationConfigApplicationContext() {
//创建一个注解的bean的读取器,猜想一下,很关键,要想读取注解,是不是要注册一些内置的BeanPostProcess后置处理器来处理注解bean。
this.reader = new AnnotatedBeanDefinitionReader(this);
//创建一个类路径的bean的扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
3.刷新上下文
refresh()刷新容器
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 刷新上下文前的准备
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 获取beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// beanFactory的一些准备工作
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 留给子类Context去实现,目前为空
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 调用 beanFactoryPostProcessors beanFactory的后置处理器
//重点: 解析入口的配置类
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注册Bean的后置处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//初始化消息源
initMessageSource();
// Initialize event multicaster for this context.
//初始化事件广播监听器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//子类初始化一些特殊的bean
onRefresh();
// Check for listener beans and register them.
// 检查并注册监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//重点:完成所有非延迟加载bean的初始化
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//完成上下文刷新
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
简单来说:整体流程其实已经走完了,感觉有点走马观花,但是其中每一个方法每一个new对象,每一个父子继承的实现其实很复杂。得慢慢梳理。先看一下AnnotationConfigApplicationContext得类图,从图中可以看成,spirng把一个上下文的接口抽象出来了很多顶级接口,和抽象类和实现类,看多了很多源码,摸清楚了一些spring框架的一些小特点,通常spring接口会有顶级接口,定义规范,抽象类实现接口的公用方法,具体的特性交给不同实现类去实现,这里着重介绍一些核心得关键接口和类。
4.核心类AnnotationConfigApplicationContext的类图结构
BeanFactory: Bean工厂的顶级接口。里面定义了变量factorbean的前缀&,getBean()、getType()、是否单例、是否原型的方法等等。
ResourceLoader: 资源加载的顶级接口。很简单,里面仅仅定义了classpath的url,getClassLoader()、getResource(String location)方法。
DefaultResourceLoader:默认的资源加载类。加载classpath下的资源文件。
AbstractApplicationContext:抽象的上下文类。实现了可配置的上下文接口ConfigurableApplicationContext,是一个很重要的类,refresh()刷新容器的主要逻辑就在其中。
GenericApplicationContext:广泛普通的上下文类。我们真正底层的ioc容器,bean工厂DefaultListableBeanFactory就是在它的初始化中创建的。
AnnotationConfigApplicationContex:注解配置的上下文类。很关键,是可以直接定位加载注解配置类的上下文。
BeanDefinitionRegistry:bean的注册接口。定义了注册bean、移除bean等接口。
5.跟踪源码进入ioc
先简单的介绍AnnotationConfigApplicationContext#register(componentClasses)方法,以及跟踪源码,可以直接进入我们常说的ioc容器之中,看着上下文是如何帮我们在上下文中创建一个BeanDefinition,并放入容器中。
好了,尽管我省略了很多细节,但是整体的配置类BeanDefinition注册流程通过下图展示,spring在ioc容器中注册了bean的定义了,那么如何去完成实例化bean的实例呢,请期待我下一篇文章把!
下一篇:2、spring源码解析之单例bean的实例化