Spring, 相信每个 Java 开发都用过, 而且是每天都在用, 那强大又神秘的 IoC,AOP, 让我们的开发变得越来越简单, 只需要一个注解搞定一切, 但是它内部到底是什么样子的呢? 跟着我, 一起探究 Spring 源码把.
写在前面的话: Spring 项目距今已有 15 年左右的历史了, 是众多 Java 大神们的杰作, 由于我个人水平有限, 时间有限, 不保证我说的全部都是正确的, 但是我可以保证每一句话都是反复推敲, 经过验证, 绝没有复制粘贴. 当然在这里, 也不可能把每个方法都进行深层次的分析, 只能把重点集中在重要的方法上, 有些 (其实是绝大部分) 只能采取黑盒理论, 即: 不去探究方法内部到底做了什么, 只大概的知道执行这个方法后发生了什么.
本文中采用的 Spring 版本是 5.0.0
由于现在 JavaConfig 风格 + 注解的方式来使用 Spring, 是 Spring 官方主推的, 也是现在的主流方式, 所以我们从这里出发:
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);
让我们先来看看 AnnotationConfigApplicationContext 的关系图:
image.PNG
可以看到这个关系够复杂的, 我们现在完全不需要特意全部记住, 只要有一个大概的印象就可以了, 后面随着源码分析的深入, 自然而然会记住其中的一些关系.
创建 AnnotationConfigApplicationContext 对象, 首先会跑到这里:
- // 根据参数类型可以知道, 其实可以传入多个 annotatedClasses, 但是这种情况出现的比较少
- public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
- // 调用无参构造函数, 会先调用父类 GenericApplicationContext 的构造函数
- // 父类的构造函数里面就是初始化 DefaultListableBeanFactory, 并且赋值给 beanFactory
- // 本类的构造函数里面, 初始化了一个读取器: AnnotatedBeanDefinitionReader read, 一个扫描器 ClassPathBeanDefinitionScanner scanner
- //scanner 的用处不是很大, 它仅仅是在我们外部手动调用 .scan 等方法才有用, 常规方式是不会用到 scanner 对象的
- this();
- // 把传入的类进行注册, 这里有两个情况,
- // 传入传统的配置类
- // 传入 bean(虽然一般没有人会这么做
- // 看到后面会知道 spring 把传统的带上 @Configuration 的配置类称之为 FULL 配置类, 不带 @Configuration 的称之为 Lite 配置类
- // 但是我们这里先把带上 @Configuration 的配置类称之为传统配置类, 不带的称之为普通 bean
- register(annotatedClasses);
- // 刷新
- refresh();
- }
这个方法第一眼看上去, 很简单, 无非就是三行代码, 但是这三行代码包含了大千世界.
我们先来为构造方法做一个简单的说明:
这是一个有参的构造方法, 可以接收多个配置类, 不过一般情况下, 只会传入一个配置类.
这个配置类有两种情况, 一种是传统意义上的带上 @Configuration 注解的配置类, 还有一种是没有带上 @Configuration, 但是带有 @Component,@Import,@ImportResouce,@Service,@ComponentScan 等注解的配置类, 在 Spring 内部把前者称为 Full 配置类, 把后者称之为 Lite 配置类. 在本源码分析中, 有些地方也把 Lite 配置类称为普通 Bean.
我们先来看一下第一行代码: 通过 this()调用此类无参的构造方法, 代码会跑到下面:
- public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
- // 注解 bean 定义读取器, 主要作用是用来读取被注解的了 bean
- private final AnnotatedBeanDefinitionReader reader;
- // 扫描器, 它仅仅是在我们外部手动调用 .scan 等方法才有用, 常规方式是不会用到 scanner 对象的
- private final ClassPathBeanDefinitionScanner scanner;
- /**
- * Create a new AnnotationConfigApplicationContext that needs to be populated
- * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
- */
- public AnnotationConfigApplicationContext() {
- // 会隐式调用父类的构造方法, 初始化 DefaultListableBeanFactory
- // 初始化一个 Bean 读取器
- this.reader = new AnnotatedBeanDefinitionReader(this);
- // 初始化一个扫描器, 它仅仅是在我们外部手动调用 .scan 等方法才有用, 常规方式是不会用到 scanner 对象的
- this.scanner = new ClassPathBeanDefinitionScanner(this);
- }
- }
首先映入眼帘的是 reader 和 scanner, 无参构造方法中就是对 reader 和 scanner 进行了实例化, reader 的类型是 AnnotatedBeanDefinitionReader, 从字面意思就可以看出它是一个 "打了注解的 Bean 定义读取器",scanner 的类型是 ClassPathBeanDefinitionScanner, 其实这个字段并不重要, 它仅仅是在我们外面手动调用. scan 方法, 或者调用参数为 String 的构造方法, 传入需要扫描的包名, 才会用到, 像我们这样传入配置类是不会用到这个 scanner 对象的.
AnnotationConfigApplicationContext 类是有继承关系的, 会隐式调用父类的构造方法:
- public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
- private final DefaultListableBeanFactory beanFactory;
- public GenericApplicationContext() {
- this.beanFactory = new DefaultListableBeanFactory();
- }
- }
这个代码很简单, 就是初始化了 DefaultListableBeanFactory.
我们再来看看 DefaultListableBeanFactory 的关系图:
image.PNG
DefaultListableBeanFactory 是相当重要的, 从字面意思就可以看出它是一个 Bean 的工厂, 什么是 Bean 的工厂? 当然就是用来生产和获得 Bean 的.
让我们把目光回到 AnnotationConfigApplicationContext 的无参构造方法, 让我们看看 Spring 在初始化 AnnotatedBeanDefinitionReader 的时候做了什么:
- public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
- this(registry, getOrCreateEnvironment(registry));
- }
这里的 BeanDefinitionRegistry 当然就是 AnnotationConfigApplicationContext 的实例了, 这里又直接调用了此类其他的构造方法:
- 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);
- AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
- }
让我们把目光移动到这个方法的最后一行, 进入 registerAnnotationConfigProcessors 方法:
- public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
- registerAnnotationConfigProcessors(registry, null);
- }
这又是一个门面方法, 再点进去, 这个方法的返回值 Set<BeanDefinitionHolder>, 但是上游方法并没有去接收这个返回值, 所以这个方法的返回值也不是很重要了, 当然方法内部给这个返回值赋值也不重要了. 由于这个方法内容比较多, 这里就把最核心的贴出来, 这个方法的核心就是注册 Spring 内置的多个 Bean:
- if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
- RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
- def.setSource(source);
- beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
- }
判断容器中是否已经存在了 ConfigurationClassPostProcessor Bean
如果不存在(当然这里肯定是不存在的), 就通过 RootBeanDefinition 的构造方法获得 ConfigurationClassPostProcessor 的 BeanDefinition,RootBeanDefinition 是 BeanDefinition 的子类:
image.PNG
执行 registerPostProcessor 方法, registerPostProcessor 方法内部就是注册 Bean.
当然这里注册其他 Bean 也是一样的流程.
BeanDefinition 是什么, 顾名思义, 它是用来描述 Bean 的, 里面存放着关于 Bean 的一系列信息, 比如 Bean 的作用域, Bean 所对应的 Class, 是否懒加载, 是否 Primary 等等, 这个 BeanDefinition 也相当重要, 我们以后会常常和它打交道.
registerPostProcessor 方法:
- private static BeanDefinitionHolder registerPostProcessor(
- BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
- definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
- registry.registerBeanDefinition(beanName, definition);
- return new BeanDefinitionHolder(definition, beanName);
- }
这方法为 BeanDefinition 设置了一个 Role,ROLE_INFRASTRUCTURE 代表这是 spring 内部的, 并非用户定义的, 然后又调用了 registerBeanDefinition 方法, 再点进去, Oh No, 你会发现它是一个接口, 没办法直接点进去了, 首先要知道 registry 实现类是什么, 那么它的实现是什么呢? 答案是 DefaultListableBeanFactory:
- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
- throws BeanDefinitionStoreException {
- this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
- }
这又是一个门面方法, 再点进去, 核心在于下面两行代码:
- //beanDefinitionMap 是 Map<String, BeanDefinition>,
- // 这里就是把 beanName 作为 key,ScopedProxyMode 作为 value, 推到 map 里面
- this.beanDefinitionMap.put(beanName, beanDefinition);
- //beanDefinitionNames 就是一个 List<String>, 这里就是把 beanName 放到 List 中去
- this.beanDefinitionNames.add(beanName);
从这里可以看出 DefaultListableBeanFactory 就是我们所说的容器了, 里面放着 beanDefinitionMap,beanDefinitionNames,beanDefinitionMap 是一个 hashMap,beanName 作为 Key,beanDefinition 作为 Value,beanDefinitionNames 是一个集合, 里面存放了 beanName. 打个断点, 第一次运行到这里, 监视这两个变量:
image.PNG
image.PNG
DefaultListableBeanFactory 中的 beanDefinitionMap,beanDefinitionNames 也是相当重要的, 以后会经常看到它, 最好看到它, 第一时间就可以反应出它里面放了什么数据
这里仅仅是注册, 可以简单的理解为把一些原料放入工厂, 工厂还没有真正的去生产.
上面已经介绍过, 这里会一连串注册好几个 Bean, 在这其中最重要的一个 Bean(没有之一)就是 BeanDefinitionRegistryPostProcessor Bean.
ConfigurationClassPostProcessor 实现 BeanDefinitionRegistryPostProcessor 接口, BeanDefinitionRegistryPostProcessor 接口又扩展了 BeanFactoryPostProcessor 接口, BeanFactoryPostProcessor 是 Spring 的扩展点之一, ConfigurationClassPostProcessor 是 Spring 极为重要的一个类, 必须牢牢的记住上面所说的这个类和它的继承关系.
image.PNG
除了注册了 ConfigurationClassPostProcessor, 还注册了其他 Bean, 其他 Bean 也都实现了其他接口, 比如 BeanPostProcessor 接口.
BeanPostProcessor 接口也是 Spring 的扩展点之一.
至此, 实例化 AnnotatedBeanDefinitionReader reader 分析完毕.
由于常规使用方式是不会用到 AnnotationConfigApplicationContext 里面的 scanner 的, 所以这里就不看 scanner 是如何被实例化的了.
把目光回到最开始, 再分析第二行代码:
register(annotatedClasses);
这里传进去的是一个数组, 最终会循环调用如下方法:
- <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
- @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
- //AnnotatedGenericBeanDefinition 可以理解为一种数据结构, 是用来描述 Bean 的, 这里的作用就是把传入的标记了注解的类
- // 转为 AnnotatedGenericBeanDefinition 数据结构, 里面有一个 getMetadata 方法, 可以拿到类上的注解
- AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
- // 判断是否需要跳过注解, spring 中有一个 @Condition 注解, 当不满足条件, 这个 bean 就不会被解析
- if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
- return;
- }
- abd.setInstanceSupplier(instanceSupplier);
- // 解析 bean 的作用域, 如果没有设置的话, 默认为单例
- ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
- abd.setScope(scopeMetadata.getScopeName());
- // 获得 beanName
- String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
- // 解析通用注解, 填充到 AnnotatedGenericBeanDefinition, 解析的注解为 Lazy,Primary,DependsOn,Role,Description
- AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
- // 限定符处理, 不是特指 @Qualifier 注解, 也有可能是 Primary, 或者是 Lazy, 或者是其他(理论上是任何注解, 这里没有判断注解的有效性), 如果我们在外面, 以类似这种
- //AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class); 常规方式去初始化 spring,
- //qualifiers 永远都是空的, 包括上面的 name 和 instanceSupplier 都是同样的道理
- // 但是 spring 提供了其他方式去注册 bean, 就可能会传入了
- if (qualifiers != null) {
- // 可以传入 qualifier 数组, 所以需要循环处理
- for (Class<? extends Annotation> qualifier : qualifiers) {
- //Primary 注解优先
- if (Primary.class == qualifier) {
- abd.setPrimary(true);
- }
- //Lazy 注解
- else if (Lazy.class == qualifier) {
- abd.setLazyInit(true);
- }
- // 其他, AnnotatedGenericBeanDefinition 有个 Map<String,AutowireCandidateQualifier > 属性, 直接 push 进去
- else {
- abd.addQualifier(new AutowireCandidateQualifier(qualifier));
- }
- }
- }
- for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
- customizer.customize(abd);
- }
- // 这个方法用处不大, 就是把 AnnotatedGenericBeanDefinition 数据结构和 beanName 封装到一个对象中
- BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
- definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
- // 注册, 最终会调用 DefaultListableBeanFactory 中的 registerBeanDefinition 方法去注册,
- //DefaultListableBeanFactory 维护着一系列信息, 比如 beanDefinitionNames,beanDefinitionMap
- //beanDefinitionNames 是一个 List<String>, 用来保存 beanName
- //beanDefinitionMap 是一个 Map, 用来保存 beanName 和 beanDefinition
- BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
- }
在这里又要说明下, 以常规方式去注册配置类, 此方法中除了第一个参数, 其他参数都是默认值.
通过 AnnotatedGenericBeanDefinition 的构造方法, 获得配置类的 BeanDefinition, 这里是不是似曾相似, 在注册 ConfigurationClassPostProcessor 类的时候, 也是通过构造方法去获得 BeanDefinition 的, 只不过当时是通过 RootBeanDefinition 去获得, 现在是通过 AnnotatedGenericBeanDefinition 去获得.
image.PNG
判断需不需要跳过注册, Spring 中有一个 @Condition 注解, 如果不满足条件, 就会跳过这个类的注册.
然后是解析作用域, 如果没有设置的话, 默认为单例.
获得 BeanName.
解析通用注解, 填充到 AnnotatedGenericBeanDefinition, 解析的注解为 Lazy,Primary,DependsOn,Role,Description.
限定符处理, 不是特指 @Qualifier 注解, 也有可能是 Primary, 或者是 Lazy, 或者是其他(理论上是任何注解, 这里没有判断注解的有效性).
把 AnnotatedGenericBeanDefinition 数据结构和 beanName 封装到一个对象中(这个不是很重要, 可以简单的理解为方便传参).
注册, 最终会调用 DefaultListableBeanFactory 中的 registerBeanDefinition 方法去注册:
- public static void registerBeanDefinition(
- BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
- throws BeanDefinitionStoreException {
- // 获取 beanName
- // Register bean definition under primary name.
- String beanName = definitionHolder.getBeanName();
- // 注册 bean
- registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
- //Spring 支持别名
- // Register aliases for bean name, if any.
- String[] aliases = definitionHolder.getAliases();
- if (aliases != null) {
- for (String alias : aliases) {
- registry.registerAlias(beanName, alias);
- }
- }
- }
这个 registerBeanDefinition 是不是又有一种似曾相似的感觉, 没错, 在上面注册 Spring 内置的 Bean 的时候, 已经解析过这个方法了, 这里就不重复了, 此时, 让我们再观察下 beanDefinitionMap beanDefinitionNames 两个变量, 除了 Spring 内置的 Bean, 还有我们传进来的 Bean, 这里的 Bean 当然就是我们的配置类了:
image.PNG
image.PNG
到这里注册配置类也分析完毕了.
大家可以看到其实到这里, Spring 还没有进行扫描, 只是实例化了一个工厂, 注册了一些内置的 Bean 和我们传进去的配置类, 真正的大头是在第三行代码:
refresh();
不过, 这就是下一章的内容了.
来源: http://www.jianshu.com/p/922125d40eb4