最近在学习 spring 源码, 把自己的学习笔记记录一下, 分享出来, 如果有理解错的, 也希望各位能提出来, 大家一起学习
首先 spring 源码的入口方法:
- public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
- // 在 this() 中调用父类的方法 创建了 DefaultListableBeanFactory(这就是平常说的 springbean 工厂)
- this();
- // 把 annotatedClasses(AppConfig.java) 放到 spring 容器中, 最底层调用的是 DefautListableBeanFactory.registerBeanDefinition() 方法, 将配置类 put 到 beanDefinitionMap 中
- register(annotatedClasses);
- refresh();
- }
- // 这个方法是 this() 调用的
- public AnnotationConfigApplicationContext() {
- /**
- * 创建一个读取注解的 bean 定义读取器
- * bean 定义其实就是 beanDefinition
- * 在这个方法里面 声明了六个比较重要的 bean, 并将这个几个 bean 存到了 beanDefinitionMap 里面
- * CommonAnnotationBeanPostProcessor
- * RequiredAnnotationBeanPostProcessor
- * AutowiredAnnotationBeanPostProcessor
- * ConfigurationClassPostProcessor
- */
- this.reader = new AnnotatedBeanDefinitionReader(this);
- /**
- * 实际上完成包扫描并不是这里的 scanner 完成的. 而是 spring 在扫描包的时候, 又重新 new 了一个 ClassPathBeanDefinitionScanner 完成的
- * 这里的 scanner 是为了程序员能够在外部调用 annotationConfigApplicationbContext 对象
- */
- this.scanner = new ClassPathBeanDefinitionScanner(this);
- }
在 spring 初始化过程中, 最重要的方法就是 refresh() 方法, 在 refresh 中完成了 bean 的扫描, 初始化, 以及 AOP 动态代理对象的生成等等, 我们来一点一点分析
- public void refresh() throws BeansException, IllegalStateException {
- synchronized (this.startupShutdownMonitor) {
- // Prepare this context for refreshing.
- // 准备工作包括设置启动时间, 是否激活标志位, 初始化属性源配置
- prepareRefresh();
- // Tell the subclass to refresh the internal bean factory.
- // 返回一个 factory
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
- // Prepare the bean factory for use in this context.
- // 准备工厂
- prepareBeanFactory(beanFactory);
- try {
- // Allows post-processing of the bean factory in context subclasses.
- postProcessBeanFactory(beanFactory);
- // Invoke factory processors registered as beans in the context.
- /**
- * TODO
- * 完成对 bean 的扫描, 将 beanDefinition 存到 map 中
- *
- 26 *
- * 在这个方法中, 注入 bean, 分为了三种
- * 一, 普通 bean:@Component 注解的 bean30 *
- * 1. 获取到所有的 beanFactoryPostProcessor
- * 2. 执行 bean 后置处理器的 postProcessBeanFactory(configurationClassPostProcessor), 该方法会把 beanFactory 作为入参传到方法里面
- * 3. 从 beanFactory 中获取到所有的 beanName 打断点看一下 org.springframework.context.annotation .ConfigurationClassPostProcessor#processConfigBeanDefinitions
- *
- * 4. 然后将所有的 bean 包装成 beanDefinitionHolder, 在后面又根据 beanName 和 bean 的 metadata 包装成了 ConfigurationClass
- * 5. 把所有包含 @ComponentScan 的类取出来, 遍历每一个 componentScan, 调用 ClassPathBeanDefinitionScanner.doScan(basePackages) 方法
- * 6. 在 doScan 方法中, 会遍历 basePackages, 因为一个 ComponentScan 中可以配置多个要扫描的包
- * 7. 获取每个包下面的 *.class 文件, registerBeanDefinition(definitionHolder, this.registry); 这个方法底层就是调用 org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition 方法 把当前 bean put 到 beanDefinitionMap 中
- *
- * 二, 是通过 ImportSelector 注解注入的 bean
- *
- * 三, ImportBeanDefinitionRegistrar 注入的 bean
- */
- invokeBeanFactoryPostProcessors(beanFactory);
- // Register bean processors that intercept bean creation.
- // 注册 beanPostProcessor; 方法里面调用的是 beanFactory.addBeanPostProcessor(postProcessor);
- registerBeanPostProcessors(beanFactory);
- // Initialize message source for this context.
- initMessageSource();
- // Initialize event multicaster for this context.
- /**
- * 注册一个多事件派发器
- * 先从 beanFactory 获取, 如果没有, 就创建一个, 并将创建的派发器放到 beanFactory 中
- */
- initApplicationEventMulticaster();
- // Initialize other special beans in specific context subclasses.
- onRefresh();
- // Check for listener beans and register them.
- /**
- * 注册所有的事件监听器
- * 将容器中的时间监听器添加到 applicationEventMulticaster 中
- */
- registerListeners();
- // Instantiate all remaining (non-lazy-init) singletons.
- /**
- * TODO
- * 完成对 bean 的实例化
- */
- finishBeanFactoryInitialization(beanFactory);
- // Last step: publish corresponding event.
- /**
- * 当容器刷新完成之后, 发送容器刷新完成事件
- * publishEvent(new ContextRefreshedEvent(this));
- */
- finishRefresh();
- }
- catch (BeansException ex) {
- }
- finally {
- // Reset common introspection caches in Spring's core, since we
- // might not ever need metadata for singleton beans anymore...
- resetCommonCaches();
- }
- }
- }
在 refresh 方法中, 个人觉得比较重要的是
- invokeBeanFactoryPostProcessors(beanFactory);
- finishBeanFactoryInitialization(beanFactory);
其他几个方法, 还没来得及进行深入的研究, 本次主要来分析这两个方法
首先说, 一个 bean 要在 spring 中完成初始化, 简单来说, 分为两步 (当前, 这是个人目前的理解)
1. 首先要把 bean 扫描到容器中, 然后再将 bean 实例化; invokeBeanFactoryPostProcessors 这个方法个人理解: 主要是完成了 bean 的扫描, 将要注入的 bean 扫描到 beanDefinitionMap 中; 这个 map 是用来存放
spring 中要实例化的 bean,key 值是 beanName,value 值是一个 beanDefinition 对象, beanDefinition 存放的是对 bean 的一些描述信息;
2. 当 bean 被扫描到 beanDefinitionMap 中之后, 就需要调用 bean 的构造方法等来实例化, 然后在调用 bean 的初始化方法来进行初始化; 以及 bean 的属性注入等; 这个工作是在 finishBeanFactoryInitialization 方法中完成;
一,
我们首先来说在 invokeBeanFactoryPostProcessors 方法中是如何完成 bean 的扫描的;
先说结论吧: spring 在将 bean 注入到容器中, 有几种方式:
1.@Component 注解 +@ComponeneScan 注解
2.@Import 注解注入, import 注入的话分两种, 一种是注入 ImportSelector, 一种是注入 ImportBeanDefinitionRegistrar
3.@Bean 在配置类中, 直接通过该注解将 bean 注入到容器中
1. 那我们首先来说 @Component 注解这种注入方式的源码:
由于这里的调用链比较长, 所以直接截图放出来, 不一个一个手打了;
在前面, spring 将配置类注入到了 beanDefinitionMap 中, 在这个方法里面, 会获取到配置类;
然后获取到配置类的 ComponentScan 注解的值, 由于 ComponentScan 可以指定多个包, 所以会循环每个包, 在 doScan 方法中获取到当前包下所有的 *.class 文件; 将扫描的文件, put 到 beanDefinitionMap 中
这是通过扫描注入 bean 的方式原理
2. 那通过 ImportSelector 和 importBeanDefinitionRegistrar 方式注入的 bean, 是这样注入的
org.springframework.context.annotation.ConfigurationClassParser#processImports
在这个方法中完成了对这两种方式注入的 bean 的扫描; 方法中, 会区分是 ImportSelector.class 还是 ImportBeanDefinitionRegistrar.class;
稍微说一下这两个接口的区别:
1.ImportSelector 接口中 selectImports 方法返回的是一个 String[] 数组对象, 返回数组中, 包含的是要注入的 bean 的全类名
2.ImportBeanDefinitionRegistrar 接口中的方法可以直接注册 bean, 因为接口中的方法可以得到 BeanDefinitionRegisty 对象
我们接着说注入: 对于 ImportSelector 注入的 bean 会存入到 configurationClasses 中; 对于 ibdr(importbeanDefinitionRegistrar) 注入的 bean 会存到 importBeanDefinitionRegistrars 中
在处理完这些之后, 在 org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions 方法中, 对 import 注入的 bean 和 @Bean 注入的 bean 进行注入
- private void loadBeanDefinitionsForConfigurationClass(
- ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
- if (trackedConditionEvaluator.shouldSkip(configClass)) {
- String beanName = configClass.getBeanName();
- if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
- this.registry.removeBeanDefinition(beanName);
- }
- this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
- return;
- }
- // 这里是对 importSelector 注入的 bean 进行初始化
- if (configClass.isImported()) {
- registerBeanDefinitionForImportedConfigurationClass(configClass);
- }
- //@Bean 注解需要注入的 bean 对象
- for (BeanMethod beanMethod : configClass.getBeanMethods()) {
- loadBeanDefinitionsForBeanMethod(beanMethod);
- }
- loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
- // 这里是对 ImportBeanDefinitionRegistrar 注入的 bean 进行初始化
- loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
- }
这个方法执行完之后, 所有的 bean 就被注入到了 beanDefinitionMap 中
在 invokebeanFactoryPostProcessors 方法中, 还有很多细节, 比如对配置类上加 @Configuration 注解与不加 @Configuration 注解的处理, 对 importSelector 注入 bean 的递归调用等等., 如果展开了, 不知道该怎么写, 细节点太多, 太碎, 所以本次只把主干流程简单说了一下, 对于源码解读的注释, 可以参考本人在 GitHub 上传的注释来看. https://github.com/mapy95/spring-sourceCode
这上面是 spring 的源码学习的一些注释, 对于 spring 源码的学习笔记还在持续更新哈.
来源: https://www.cnblogs.com/mpyn/p/11781639.html