前言
这篇文章主要讲spring的getBean过程. 前面我们已经扫描好class文件并封装成BeanDefinition了, 现在拿这些beanDefinition来做点什么了!
建议搭配源码食用, 源码版本 Spring Framework 5.3.10
Spring的启动
//使用配置类来配置spring
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
上面的代码是传统spring项目, 创建一个Spring容器的代码, spring容器以及bean的初始化都在这一行代码完成, 所以是很重要的一行代码.
点进去这个构造方法
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
this();
register(componentClasses);
refresh();
}
可以看到这里首先调用了无参的构造方法, 调用无参构造方法时会先调用父类的无参构造方法
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
// 额外会创建StandardEnvironment
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
上面分别是AnnotationConfigApplicationContext以及它父类GenericApplicationContext的构造方法
可以看出创建了一个scanner(ClassPathBeanDefinitionScanner), 以及一个reader(AnnotatedBeanDefinitionReader)
父类创建了一个DefaultListableBeanFactory对象赋值给beanFactory(bean工厂)属性
细心的小伙伴就会发现ClassPathBeanDefinitionScanner这个类就是上一篇文章中doScan的那个类, 就是负责bean扫描的类. 你可能会想, 是不是扫描bean是不是就是用这里创建出来的scanner进行的. 很遗憾的告诉你, 并不是. 后面Spring启动流程的文章里会详细介绍的了, 这里先留个印象.
讲完了this(), 接下来简单说说register(componentClasses), 这里就是简单的把AppConfig.class这个类解析成BeanDefinition注册进Spring容器里.
这里说的BeanDefinition注册进Spring容器是什么意思, 这里就要说一个Map org.springframework.beans.factory.support.DefaultListableBeanFactory#beanDefinitionMap, 这个Map就是用来存放那些注册的BeanDefinition. 换言之, 注册bean(registerBean)的过程就是把BeanDefinition放入这个Map中, 所以这个Map很重要. 它的Key是Bean的名字.
再来看看这个Map所在的类DefaultListableBeanFactory, 还记得它吗? 刚刚在这个类的父类的无参构造方法里创建的就是这个类的对象, 所以他也是Spring中很重要的一个类.
这个类中还有一个List org.springframework.beans.factory.support.DefaultListableBeanFactory#beanDefinitionNames 专门用来存放这些注册的bean的名字的, 同样是在注册bean的时候把bean的名字存入这个list中.(下面讲getBean就会用到这个list)
说完了前面两个, 剩下最后一个refresh(),