终于,有一天我也来看Spring的源码了,看了一阵之后感觉心情那叫一个舒畅,对Spring底层的实现也有了进一步的了解, 最直观的感受就是Spring的命名风格很赞,很长,真的长到使人见名知意, 闲言少叙,开始整理笔记了

程序的入口

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);

跟进这个AnnotationConfigApplicationContext()程序的启动入口, 注解配置的应用上下文.主要做了下面的三件事

  • 调用本类无参构造方法
  • 调用register(annotatedClasses) 将我们传递进来的配置类注册进BeanFactoryBeanDefinitionMap
  • 刷新容器
	public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}

创建BeanFactory

首先调用本类的无参构造方法,,通过上图,可以看到,AnnotationConfigAllicationContext的父类是GenericApplicationContext但是,在执行本类的无参构造方法时会先执行父类的无参构造方法.它父类的无参构造方法我贴在下面,就做了一件事,初始化了Spring的BeanFactory,没错就是Spring的Bean工厂,由于两者的继承关系,我们就任务,AnnotationConfigApplicationContext的Bean工厂被初始化了

	public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}

创建AnnotatedBeanDefinitionReader加载

接着回到这个构造方法的源码我贴在下面, 这个构造方法主要做了两件事

  • 为应用的上下文创建reader读取器, 读取被添加了注解的类信息
  • 实例化了一个Scanner, 这个Scanner可以用去做包扫描的工作,但是Spring根据我们的配置信息去进行包扫描的工作时,并没有使用这个扫描器,而是自己new 了一个,当前的扫描器可以理解成是方便程序员使用而创建的
	public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

下面跟进AnnotatedBeanDefinitionReader扫描器的创建过程,经过几个没有重要逻辑的方法,我们会进入registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source),下面是源码: 这算是Spring初始化的一个小高潮了!!!,为啥这样说呢? 因下面的逻辑中,为Spring初始化过程中,构建BeanFactory提供了几个开天辟地性质的RootBeanDefinition``

  • 首先是在为BeanFactory添加了两个大组件

    • AnnotationAwareOrderComparator用于解析@Order@Priorty注解
    • ContextAnnotationAutowireCandidateResolver 提供了懒加载的支持
  • 然后就是往BeanFactory中的BeanDefinitionMap中添加了6个RootBeanDefinition
    • ConfigurationClassPostProcessor
    • AutowiredAnnotationBeanPostProcessor
    • ...
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) { // 得到bean工厂
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
// 给Bean工厂添加原材料
// AnnotationAwareOrderComparator 主要能解析@Order注解和@Priority
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
// ContextAnnotationAutowireCandidateResolver 提供处理懒加载(Lazy)相关的功能
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
// 作用是方便传递参数BeanDefinitionHolder
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
// BeanDefinition的注册,这里很重要,需要理解注册每个bean的类型
// 就是判断工厂中有没有包含 CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME 名称的bean, Spring在启动时,工厂肯定是空的返回false , 加上! 表示ture
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {//configuration_annotation_processor_bean_name
// 注意: 下面的ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,间接实现了 BeanFactoryPostProcessor bean工厂的后置处理器
// RootBeanDefinition可以理解成 描述Spring内部类的Definition // 除了通过AnnotationedBeanDefinitionReader把 加上了注解的类加载成bean,下面的第二种方式, 通过new RootBeanDefinition, 进而将 XXX.class起来注册进bean工厂
// 这是使用第二种方式, 通过new Spring自己实现的BeanDefinition接口的类,将java转换成 Bean 然后put进BeanFactory的BeanDefinitionMap中
// 下面的111-666 就是最先放置进去的6个Spring的RootBean对象
// ---111---------------------------
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
// 跟进去 registerPostProcessor
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
} if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
//AutowiredAnnotationBeanPostProcessor 实现了 MergedBeanDefinitionPostProcessor
//MergedBeanDefinitionPostProcessor 最终实现了 BeanPostProcessor
// ---222---------------------------
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
} if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
// ---333---------------------------
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
} // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { // ---444---------------------------
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
} // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
} if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
// ---555--------------------------- RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
} if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
// ---666---------------------------
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
} return beanDefs;
}

上面的代码中有来如下两个亮点:

亮点1:RootBeanDefinition

首先涉及到的知识点就是,Spring有哪几种方式将对象转成BeanDefinition? 其实是有两种,第一种就是让Spring通过Scanner去扫描包解析程序员提供的添加了注解的类,这是个自动完成的过程,第二种就是Spring通过new RootBeanDefinition等诸多的BeanDefinition接口的实现类, 然后将Spring原生的对象当成参数传递进去进而转换成BeanDefinition, 当然,Spring在这里选择的就是第二种方法

亮点2:ConfigurationClassPostProcessor

这个类很牛,为什么这么说呢? 先看一下他的继承类图

没错,他是6个RootBeanDefinition中唯一的一个实现BeanFactoryPostProcessor的,其他的五个RootBeanDifinition实现的都是BeanPostProcessor, 其实也不用懵逼,只要我们整明白这里说的BeanPostProcessorBeanFactoryPostProcessor的作用就好了,然后在这里我用下面的两个模块解释

BeanPostProcessor

接口的抽象方法源码如下:

public interface BeanPostProcessor {

@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}

两个方法名,见名知意: 第一个会在 对象的 constructor 之后,init()方法之前调用

第二个会在init()方法之后调用

但是,大家可以发现,它的调用时机都是在构造方法执行之后进行拦截,这时候BeanDefinition已经被实例化了

BeanFactoryPostProcessor

@FunctionalInterface
public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }

它就比较厉害了, 这也是Spring牛的地方,它不仅仅会替我们维护这些Bean,而且还通过当前的BeanFactoryPostProcessor,为程序员开放一个缺口,让程序员可以参与到Bean的创建过程中来,为什么这样说呢, 其实大家可以看到,它唯一的抽象方法中的入参位置上是谁? 没错,就是BeanFactory, Bean工厂都给我们了,那不是想干啥干啥?

其次,它的作用时机是执行Bean的构造方法之前

最直接的应用场景: 当一个单例的Bean依赖 多例的Bean时,我们多次通过 应用的上下文获取出来的单例bean的hashcode都是唯一的这没错,但是紧接着打印它依赖的多例对象的hashcode同样是相同的,这种单例失效的问题,就可以根据这个知识点从容解决

前面说的ConfigurationClassPostProcessor就是BeanFactoryPostProcessor的实现类,并且它也不辱使命, 完美的使用作用时机不同的特点,在程序员提供的配置类的构造方法调用之前,就先入为主,围棋生成了 cglib代理对象


接着看代码,回到上面的代码,我们看如何将RootBeanDefinition注册进BeanFactory, 我从上面截取一行代码放在这里

	//   跟进去 registerPostProcessor
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));

跟进这个registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)

private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) { definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// registerBeanDefinition()
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}

我们关注这个registry.registerBeanDefinition(beanName, definition); , 可以看到,其实这个registerBeanDefinition()BeanDefinitionRegistry的抽象方法,我们要找的是它的实现类,那问题来了, 是谁实现他呢? 可以回到博客顶部,看看第一个图,没错Spring的BeanFactory,也就是DefualtListableBeanFactory实现了这个接口,虽然有点意外,一个工厂竟然还是一个注册器,但是这也是事实情况, 看看这个工厂是如何做的吧 .原函数很长,我截取了部分源码如下: 它的解释我写在源码的下面

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
...
else {
// 添加进入容器中, 最终的结果就是,这个map中存在哪些类,Spring的IOC中就有哪些类
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
// 单独使用一个list存放名字
this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
} if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}

可以看到,他将一开始的6个RootBeanDefinition全都都put进了一个map中, 下面这个map

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

key就是beanName, value就是BeanDefinition

这也是迄今为止我们遇到的第一个map, 这个map是BeanFactory的一个组件,但是它可不是传说中的IOC容器,大家也看到了它里面存放的是BeanDefinition,而不是Bean

将配置类注册进BeanFactory

回到一开始AnnotationConfigApplicationContextregister(annotatedClasses);方法,然后一路往下跟,会经过几个没有什么重要逻辑的方法, 然后来到这里

public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
// 继续跟进去
registerBean(annotatedClass);
}
}

通过上面的代码,我们可以回想,annotatedClasses这个可变长度的参数,其实就是我们在AnnotationConfigApplicationContext中传递进来的主配置类MainConfig, 也就是说,这个主配置类是可以存在多个的

接着往下跟

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 可以将当前类理解成一个方便参数传递的封装类
// 意为: 被加上注解的通用的BD
// 将传递进来的 主配置类封装进 这个AnnotatedGenericBeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
} abd.setInstanceSupplier(instanceSupplier); // 解析出它的元数据
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// 设置它的作用域
abd.setScope(scopeMetadata.getScopeName());
// 名称生成器, 目的是为BeanDefinition取个名字,因为这个BD最终被存放到一个map中,
// 默认情况下@Configuration(value = "XXX") 这个value有值,就是使用这个当成名字
// 都这就使用 类名首字母小写当成名字
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); // 处理bean上的通用注解, @Lazy @Dependon @Primary role等
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) {
abd.setPrimary(true);
}
//懒加载,前面加过
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else { abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
} for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
// 理解成方便参数传递的封装类
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd,beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 我们关注的重点, 注册BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

上面的函数的主要作用如下: 将我们通过AnnotationConfigApplicationContext构造函数传递进来的主配置类封装进了AnnotatedGenericBeanDefinition中,然后解析它身上的其他注解完成属性的赋值

接着跟进registerBeanDefinition()方法

	public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException { // 再来这个方法之前封装了一个 difinitionHolder , 然后在这里又把它拆分开传递给了下面的函数
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 在当前的BeanDefinitionReaderUtils中使用
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

继续跟进

	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

于是有回到了上面注册6大RootBeanDefinition的逻辑中,将我们的主配置类注册进BeanFactoryBeanDefinitionMap

未完待续...

Spring 源码阅读 一的更多相关文章

  1. Bean实例化(Spring源码阅读)-我们到底能走多远系列(33)

    我们到底能走多远系列(33) 扯淡: 各位:    命运就算颠沛流离   命运就算曲折离奇   命运就算恐吓着你做人没趣味   别流泪 心酸 更不应舍弃   ... 主题: Spring源码阅读还在继 ...

  2. 初始化IoC容器(Spring源码阅读)

    初始化IoC容器(Spring源码阅读) 我们到底能走多远系列(31) 扯淡: 有个问题一直想问:各位你们的工资剩下来会怎么处理?已婚的,我知道工资永远都是不够的.未婚的你们,你们是怎么分配工资的? ...

  3. Spring源码阅读-ApplicationContext体系结构分析

    目录 继承层次图概览 ConfigurableApplicationContext分析 AbstractApplicationContext GenericApplicationContext Gen ...

  4. Sping学习笔记(一)----Spring源码阅读环境的搭建

    idea搭建spring源码阅读环境 安装gradle Github下载Spring源码 新建学习spring源码的项目 idea搭建spring源码阅读环境 安装gradle 在官网中下载gradl ...

  5. Spring源码阅读笔记02:IOC基本概念

    上篇文章中我们介绍了准备Spring源码阅读环境的两种姿势,接下来,我们就要开始探寻这个著名框架背后的原理.Spring提供的最基本最底层的功能是bean容器,这其实是对IoC思想的应用,在学习Spr ...

  6. Spring源码阅读 之 配置的读取,解析

    在上文中我们已经知道了Spring如何从我们给定的位置加载到配置文件,并将文件包装成一个Resource对象.这篇文章我们将要探讨的就是,如何从这个Resouce对象中加载到我们的容器?加载到容器后又 ...

  7. 搭建 Spring 源码阅读环境

    前言 有一个Spring源码阅读环境是学习Spring的基础.笔者借鉴了网上很多搭建环境的方法,也尝试了很多,接下来总结两种个人认为比较简便实用的方法.读者可根据自己的需要自行选择. 方法一:搭建基础 ...

  8. Spring源码阅读系列总结

    最近一段时间,粗略的查看了一下Spring源码,对Spring的两大核心和Spring的组件有了更深入的了解.同时在学习Spring源码时,得了解一些设计模式,不然阅读源码还是有一定难度的,所以一些重 ...

  9. Spring源码阅读笔记

    前言 作为一个Java开发者,工作了几年后,越发觉力有点不从心了,技术的世界实在是太过于辽阔了,接触的东西越多,越感到前所未有的恐慌. 每天捣鼓这个捣鼓那个,结果回过头来,才发现这个也不通,那个也不精 ...

  10. idea构建spring源码阅读环境

    注:由于文章不是一次性完成,下文中的test1目录和test目录应为同一个目录. (一)安装git和Gradle Spring项目托管在github之上,基于Gradle来构建项目.所以要想搭建Spr ...

随机推荐

  1. 计蒜客-第五场初赛-第二题 UCloud 的安全秘钥(简单)

    每个 UCloud 用户会构造一个由数字序列组成的秘钥,用于对服务器进行各种操作.作为一家安全可信的云计算平台,秘钥的安全性至关重要.因此,UCloud 每年会对用户的秘钥进行安全性评估,具体的评估方 ...

  2. Request请求的应用

    1.通过request获得请求行 获得客户端的请求方式:String getMethod() 获得请求的资源: String getRequestURI()   StringBuffer getReq ...

  3. Numpy版本问题,import tensorflow as tf 报警:“ FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'”

    tensorflow成功安装后 import tensorflow as tf 报警:“ FutureWarning: Passing (type, 1) or '1type' as a synony ...

  4. sql 增删改列名

    添加列:alter table table_name add new_column data_type [interality_codition] ALTER TABLE dbo.tb newColu ...

  5. DevExpress的TextEdit、RadioGroup、ColorPickEdit设置默认值

    场景 Winform中实现ZedGraph的多条Y轴(附源码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1001322 ...

  6. Winform中实现ZedGraph的多条Y轴(附源码下载)

    场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...

  7. 利用github搭建私人maven仓库

    一.背景 最近在做HBase的项目,不免会引用到一些工具类,如StringUtils,NumberUtils,DateUtils这些,公司底层有封装好可以直接使用. 但是项目完成,用maven打包部署 ...

  8. 致初学者(四):HDU 2044~2050 递推专项习题解

    所谓递推,是指从已知的初始条件出发,依据某种递推关系,逐次推出所要求的各中间结果及最后结果.其中初始条件或是问题本身已经给定,或是通过对问题的分析与化简后确定.关于递推的知识可以参阅本博客中随笔“递推 ...

  9. 语音信号的梅尔频率倒谱系数(MFCC)的原理讲解及python实现

    梅尔倒谱系数(MFCC) 梅尔倒谱系数(Mel-scale FrequencyCepstral Coefficients,简称MFCC).依据人的听觉实验结果来分析语音的频谱, MFCC分析依据的听觉 ...

  10. 快速获取dom到body左侧和顶部的距离,简单粗暴无bug-getBoundingClientRect

    获取dom到body左侧和顶部的距离-getBoundingClientRect 平时在写js的时候,偶尔会需要用js来获取当前div到 body 左侧.顶部的距离.网上查一查,有很多都是通过offs ...