Spring源码学习(一):Spring容器创建和初始化工作准备
文章目录
前言
基于学习遗忘曲线收敛太快,决定将Spring源码的解读记录下来。今天是第一篇,容器的启动
那就开始吧~
一、Spring是什么?
用java的应该都清楚Spring框架是什么,目前市面上的主流java框架也都会做和Spring的结合。Spring两大利器:IOC+AOP。API的学习可以借助官网,因为有时候中文翻译或某些同学的博客翻译有问题:https://spring.io/projects/spring-framework#learn
二、探究
鉴于大家现在java项目几乎都是使用Springboot,那我们从Springboot项目的启动切入口查看Spring容器的启动。具体springboot版本就不指定了,Spring容器启动差别不大。
1. Spring容器启动
从Springboot的run方法开始进入
1.1 容器类型(contextClass)的判断
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
// 通过反射生成ApplicationContext类型的对象
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
通过判断webApplicationType来进行容器创建类型contextClass的设置。
因为默认的webApplicationType在前期被deduce成了SERVLET,所以创建的是AnnotationConfigServletWebServerApplicationContext
/**
* The class name of application context that will be used by default for web
* environments.
*/
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
1.2 容器的实例化
这个其实不算难了,一句话总结,就是利用反射就行实例化拿到容器的对象。
具体是BeanUtils.instantiateClass(contextClass)
- 拿到Class的构造方法clazz.getDeclaredConstructor()
- 获取构造方法的参数类型
- 调用ctor.newInstance(argsWithDefaultValues)进行容器对象创建及初始化
2. 容器的创建及实例化过程
2.1 构造方法读下去
构造方法代码如下:
/**
* Create a new {@link AnnotationConfigServletWebServerApplicationContext} that needs
* to be populated through {@link #register} calls and then manually
* {@linkplain #refresh refreshed}.
*/
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
对于java来说,调用自己的无参构造方法之前,会把父类的无参构造方法都调用:
AnnotationConfigServletWebServerApplicationContext ->
ServletWebServerApplicationContext ->
GenericWebApplicationContext ->
GenericApplicationContext->
/**
* Create a new GenericApplicationContext.
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
由此可以看到applicationContext里面的beanFactory属性默认会被初始化为DefaultListableBeanFactory对象。
2.1.1 scanner的作用
scaner的作用,顾名思义,扫描器,就是后期为了扫描所有生成的.class文件,然后根据class文件生成BeanDefinition放入到Spring的容器里,至于BeanDefinition的作用,后面再讲,先记住即可。
2.1.2 reader的作用
那reader的作用呢,其实就是为了补充scaner的力所不能及。怎么说呢,因为scaner扫描出来的class,需要具体的类对象来进行操作,咱们姑且用X来代替,那么X来把别人加入到容器,X从何而来呢?其实对于我们这些程序员来说,可能最直观的想法,就是直接new呗。但是Spring作为一个牛逼开源框架,他的开发者选择了一种尽量自洽的方式来处理,也就是通过reader把这些X类的BeanDefinition放入到了applicationContext里面,然后后续通过调用getBean的方式从容器中拿到X。
具体逻辑可以从AnnotatedBeanDefinitionReader的构造方法debug下去看到,最终会调用:
/**
* Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
* using the given {@link Environment}.
* @param registry the {@code BeanFactory} to load bean definitions into,
* in the form of a {@code BeanDefinitionRegistry}
* @param environment the {@code Environment} to use when evaluating bean definition
* profiles.
* @since 3.1
*/
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
//在这一步会进行刚刚说的X的BeanDefinition的放入
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
具体放入了哪些类的BeanDefinition呢?
这5个类对象的具体作用,我们以后再说。
此处还得记住AnnotatedBeanDefinitionReader还有个register方法,这个方法的作用是把某个类注册进Spring的容器中
而相对于reader初始化做的事儿,scanner对象的初始化就显得很简单,就是做了一些属性的赋值。
总结
以上就是今天要讲的内容,本文仅仅简单介绍了Springboot使用的ApplicationContext的contextClass的选取及对象实例化的一些基本工作。
也就是Springboot的run方法中的**context = createApplicationContext();**进行的逻辑。
本文地址:https://blog.csdn.net/liangsheng_g/article/details/109571193
上一篇: 看来小伙子还没把那姑娘骗到手