原来Spring源码学习可以这么学(三)AnnotationConfigApplicationContext光构造函数干了这么多的事情你知道吗

问题清单

本篇主要为以下几点解惑:

  1. ApplicationContext 是在什么时候构建的BeanFactory?
  2. 构造函数中的reader和scanner到底是干什么的?

ApplicationContext 是在什么时候构建的BeanFactory

当我们调用AnnotationConfigApplicationContext的构造函数(没有传入beanFactory)的时候,明明我们没有new BeanFactory ,而且我们也找不到在这个类里面有什么时机构建了beanFactory,这个时候应该有一个疑惑,它到底是什么时候new 出来的?请看它的父类GenericApplicationContext的无参构造函数
在这里插入图片描述
基础知识比较好的应该知道,当一个类有父类的时候,它调用父类无参构造函数的super();这行代码可以省略,这个就解释了beanFactory从哪来的

构造函数中的reader和scanner到底是干什么的

在这里插入图片描述
首先在无参构造函数中通过上一个问题,我们知道了有一个beanFactory被new出来了,紧接着它又new了2个对象 reader和scanner,首先我们来看reader

reader = new AnnotatedBeanDefinitionReader(this)

从代码中我们可以看出创建这个reader的同时将当前构建的ApplicationContext对象作为一个注册器传入,注册器是什么后面会说到。我们再跟进去看下里面干了啥
在这里插入图片描述
通过层层调用,我们会发现核心方法是这个AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
从名字上我们可以看出 这个方法的作用是注册注解配置后置处理器,讲到这里又不得不提到spring的魅力,它的方法名类名都很规范,看到名字就能知道这个东西大概是干什么的。
我们闲话不多扯,再跟进去看下里面到底干了啥,
在这里插入图片描述
这个地方注入了几个很重要的后置处理器,这里我们只详细看西面2个

  1. ConfigurationClassPostProcessor 实现了配置类解析的后置处理器
  2. AutowiredAnnotationBeanPostProcessor 实现了@Autowired @Value @Lookup的后置处理器
ConfigurationClassPostProcessor

这个类可以说是spring最核心的类之一,它主要作用是解析配置信息,注册bd
在这里插入图片描述

由类图我们可以看出它是一个BeanDefinitionRegistryPostProcessor,那么它所干的事情肯定在postProcessBeanDefinitionRegistry和postProcessBeanFactory 2个方法中
首先来看postProcessBeanDefinitionRegistry方法,这里主要是调用了processConfigBeanDefinitions方法
在这里插入图片描述
当我们跟进这个方法,重头戏来了,这里解决了3个问题:

  1. spring 怎么样读取配置类信息
  2. spring 怎么将配置信息转换成为bd注册到容器中
  3. @Import是如何解决的

当我们启动spring容器的时候 beanDefinitionMap中只有6个bd,

在这里插入图片描述
当我们执行完这个方法的时候会发现多了3个我们自定义的bd在这里插入图片描述
那么问题就来了,spring是在什么时候去解析了配置类,并且给他注册到beanDefinitionMap中

我们继续跟它,在processConfigBeanDefinitions中首先需要注意的一个地方是ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)
这个地方很关键,关键到你无法想象的重要,
跟进去我们会发现一个很熟悉的东西
在这里插入图片描述
在这里我们可以看到Configuration这个注解,跟到isConfigurationCandidate方法内我们还能看到@Component @ComponentScan @Import @ImportResource @Bean这几个熟悉的注解,
从这里我们可以得出一个结论:配置类不写@Configuration也没关系,有其它几个也行
但是这里会带来一个疑惑,为什么两段里面设置CONFIGURATION_CLASS_ATTRIBUTE的值不一样,一个是full一个是lite,这个问题后面给出答案。

我们跳出这个方法继续跟踪processConfigBeanDefinitions,我们进入第二个关键的地方parser.parse(candidates);
从字面意思上我们不难看出这行代码的作用,通过一个解析器去解析上面获得的配置类信息
在这里插入图片描述
跟进去,我们是以AnnotationConfigApplicationContext来看的,所以我们只用关心第一个parse即可
在这里插入图片描述
再次跟进去,通过一层层的空壳方法找到真正调用的方法
在这里插入图片描述

上面巴拉巴拉一大堆,终于到了我们的重头戏,这个方法至关重要,重要到无法想象,
首先这个方法解决了第一个问题,spring 怎么样读取配置类信息
这里是对@PropertySources和@Component注解的支持
这里通过asm技术读取class文件并且封装为bd,跟进去会发后可以验证狗叫构造函数中的scanner的却确没有被内部使用在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
我们真正关心的地方在这个processImports上面,这个方法里面我们可以看到@Impoort到底如何实现的
在这里插入图片描述
我们快速的看完了ConfigurationClassPostProcessor的第一个方法,再来喵一下下第二个方法postProcessBeanFactory
在这里插入图片描述
前面调用的方法也是processConfigBeanDefinitions,关键是下一个方法enhanceConfigurationClasses,在这个方法内我们可以解决上面的疑惑 full与lite有什么区别
在这里插入图片描述
首先spring对所有的bd进行遍历,如果当前bd加了@Configuration那么将它收集起来,使用cglib去代理他,这里我们跟进封装cglib代理的方法内,里面主要干了注释内的2件事情,具体的代码就是封装了cglib的调用
在这里插入图片描述
我们这里讨论的是spring,所以对cglib不做太深的跟入,我们只跟入到BeanMethodInterceptor这个类中,看下它到底干了啥
在这里插入图片描述
在这里插入图片描述
从resolveBeanReference的标注的这句我们可以找到想要的答案同时也验证了为什么@Bean方法(非static)重复调用不会创建多个对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值