Spring源码解析(一)入门
前言:一入spring深似海,呃,后面不知道怎么写了,那就开干吧。
这篇是spring系列的第一篇文章,希望自己能坚持下去,愿阅读源码的各位都一同坚持下去。与君共勉!
0. 准备工作
首先应该准备相关的环境,我的环境是:
- IntelliJ IDEA 2020.2 (Ultimate Edition)
- JDK 1.8.*
- gradle-5.6.4
- spring版本:spring-framework-5.1.17.RELEASE
可以使用我的环境,然后参考后面的步骤时,只需要修改对应的版本,当然你也可以使用这篇的文章的环境对应的版本。如果有不对的地方,欢迎留言,我会尽量提供帮助的。
具体的步骤可以参考这篇文章 gradle+idea配置阅读Spring源码开发环境(解决jar包下载缓慢问题),强烈推荐,良心博主
,不做重复工作(不,其实是懒!)。但是好像有一个错误
,就是设置gradle环境的地方,具体操作,参看下图。
1. 源码阅读
源码分析的部分主要是用JavaConfig技术启动spring环境,这也是spring官网推荐的方式。本系列文章是假设读者已经掌握了spring基本入门的应用。如未掌握,可以点击链接Java-based Container Configuration,前往官网学习入门,或者百度相关知识入门
1.1 编写基本代码
AppConfig.Java
首先写一个配置类
@Configuration
@ComponentScan("com.example")
public class AppConfig {
}
Test.Java
编写一个测试类
public class Test {
public static void main(String[] args) throws IOException {
// 把spring所有的前提环境准备好(比如:bean容器、bean工厂等)
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
context.register(AppConfig.class);
context.refresh();
AppConfig bean = context.getBean(AppConfig.class);
System.out.println(bean);
}
}
如果成功打印出来,说明spring环境已经搭建成功,现在可以开心阅读源码了。
1.2 AnnotationConfigApplicationContext类
// 继承了GenericApplicationContext类
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry
首先在上面的main
方法中,调用了AnnotationConfigApplicationContext类
的无参构造方法,在其实例化之前,会调用父类 GenericApplicationContext类
的无参构造,其构造方法如下:
public GenericApplicationContext() {
// 实例化了一个spring默认提供的BeanFactory ==> DefaultListableBeanFactory类
// 保存到了成员变量 beanFactory中
this.beanFactory = new DefaultListableBeanFactory();
}
然后再调用本类的构造方法,如下:
public AnnotationConfigApplicationContext() {
// 创建一个读取注解的Bean定义读取器。Bean定义:BeanDefinition
// 这个中完成了
this.reader = new AnnotatedBeanDefinitionReader(this);
/*
* 可以用来扫描包或类,然后转换成bd
* 但是实际上我们扫描包工作不是scanner对象
*/
// 扫描器,这是仅仅是为了程序员能够在外部地调用AnnotationConfigApplicationContext对象的scan方法
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
下面主要介绍实例化 AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner两个类所做的事情
1.2.1 AnnotatedBeanDefinitionReader类
在上面实例化AnnotatedBeanDefinitionReader类
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
调用到,下面这个构造方法:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
// .....省略
// 梦开始的地方,嘿嘿
// 非常重要的方法
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
registerAnnotationConfigProcessors()方法
首先调用这个方法,一个空壳方法:
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
真正的内容方法:
这里首先介绍一下BeanDefinition:
BeanDefinition是什么,顾名思义,它是用来描述Bean的,里面存放着关于Bean的一系列信息,比如Bean的作用域,Bean所对应的Class,是否懒加载,是否Primary等等,这个BeanDefinition也相当重要,我们以后会常常和它打交道。如需详细的了解,可以点击spring官网的链接查看。(后面可能用bd来代表BeanDefinition)
这个方法注册了6个关键的bd(也是6个后置处理器)到beanDefinitionMap中,在后面会被使用,这个方法中的RootBeanDefinition是实现了 BeanDefinition的,其代表spring内部的BeanDefinition。
这里注册了一个在初始化 beanFactory环境重要的一个类:ConfigurationClassPostProcessor
,这个类后在后面着重讲解。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 这里返回的是 在GenericApplicationContext类中的构造方法创建的一个 beanFactory
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
// AnnotationAwareOrderComparator主要能解析@Order注解和@Priority。设置实例
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
// ContextAnnotationAutowireCandidateResolver提供处理延迟加载的功能
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
// BeanDefinition的注册。这里注册了6个关键的bd
// 这个是最核心的类 ConfigurationClassPostProcessor,这个类将会在后面重点介绍
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
/*
* ConfigurationClassPostProcessor 的类型是BeanDefinitionRegistryPostProcessor
* 而BeanDefinitionRegistryPostProcessor 最终实现BeanFactoryPostProcessor
* 可以把RootBeanDefinition理解成spring内部的bean定义,通过BeanDefinition实现,可以将一个类变成bean定义
*
* 为什么在这里注册这个ConfigurationClassPostProcessor?
* 因为在spring的beanFactory初始化需要做一些事情,在执行invokeBeanFactoryPostProcessors()时
* 委托调用其内部实现
* 以此来实现解耦合。
*
*/
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
// 注册成一个bean定义 beanDefinitionMap
// registerPostProcessor()方法,最终会把这个类放到beanFactory的 beanDefinitionMap中
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//.....后面的省略
}
registerPostProcessor()方法
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册成一个bean定义。这里的registry 是 我们开始实例的 DefaultListableBeanFactory
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}
registerBeanDefinition()方法
主要是将beanDefinition、beanName分别放入到Map、List中,这两个容器也是beanFactory工厂中非常重要的两个属性,将在后面逐步展示其所起的作用。
// ....省略
else {
// Still in startup registration phase
// Map
this.beanDefinitionMap.put(beanName, beanDefinition);
// List
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
// ... 省略
/** Map of bean definition objects, keyed by bean name. */
// bean的定义
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** List of bean definition names, in registration order. */
// beanName
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
1.2.2 ClassPathBeanDefinitionScanner类
这里并不介绍其内部结构,主要介绍其用途,因为一般很少被使用。
正如上图注释所说那样,这里的scanner主要是作为调用者在外部调用,例如:
public class Test {
public static void main(String[] args) throws IOException {
// 把spring所有的前提环境准备好(比如:bean容器、bean工厂等)
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
context.register(AppConfig.class);
// 自己想要额外的扫描一些包,并不想要spring来扫描,可以调用该方法
context.scan("com.example");
context.refresh();
}
主要的使用地方
// AnnotationConfigApplicationContext类内部
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
到这里就介绍完了实例化AnnotationConfigApplicationContext类所做的事情了,Test类中剩下的方法将放在后面逐步更新,希望自己能当个秒男一样更新吧(雾