Spring 部分源码理解

Spring 流程概述

入口 类 ClassPathXmlApplicationContext refresh()方法

容器刷新前的准备工作

<1> 设置容器启动时间

<2> 设置活跃状态为true

<3>设置关闭状态为false

<4> 获取Environment对象,并加载当前系统的属性值到Environment对象中

<5> 准备监听器和事件的集合对象,默认为空的集合

// Prepare this context for refreshing.prepareRefresh();

创建容器对象,DefaultListableBeanFactory,加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition

    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this contextprepareBeanFactory(beanFactory);

// Allows post-processing of the bean factory in context subclassespostProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the contextinvokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creationregisterBeanPostProcessors(beanFactory);

// Initialize message source for this contextinitMessageSource();

// Initialize event multicaster for this contextinitApplicationEventMulticaster();

// Initialize other special beans in specific context subclassesonRefresh();

  // Check for listener beans and register them  registerListeners();

// Instantiate all remaining (non-lazy-init) singletons

finishBeanFactoryInitialization(beanFactory);

```

// Last step: publish corresponding eventfinishRefresh();

源码分析--spring启动流程细节

/*** 做容器刷新前的准备工作* 1、设置容器的启动时间* 2、设置活跃状态为true* 3、设置关闭状态为false* 4、获取Environment对象,并加载当前系统的属性值到Environment对象中* 5、准备监听器和事件的集合对象,默认为空的集合*/prepareRefresh();

prepareRefresh()方法关键片段:

// 留给子类覆盖,初始化属性资源  initPropertySources();// 创建并获取环境对象,验证需要的属性文件是否都已经放入环境中  getEnvironment().validateRequiredProperties();// 判断刷新前的应用程序监听器集合是否为空,如果为空,则将监听器添加到此集合中  if (this.earlyApplicationListeners == null) {      this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);  }else {// 如果不等于空,则清空集合元素对象    this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners);  }// 创建刷新前的监听事件集合  this.earlyApplicationEvents = new LinkedHashSet<>();

// 创建容器对象:DefaultListableBeanFactory// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinitionConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

obtainFreshBeanFactory() 方法关键片段

// 初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中 refreshBeanFactory(); // 返回当前实体的beanFactory属性 return getBeanFactory();

源码分析--spring配置文件加载过程

接上一节obtainFreshBeanFactory方法

refreshBeanFactory方法:

loadBeanDefinitions方法

spring自定义标签解析过程

自定义标签步骤:

创建对应标签的解析类parser(对当前标签的其他属性值进行解析工作)

创建一个对应的解析器处理类(在init方法中添加自定义的parser类)

创建一个普通的spring.handlers配置文件,让应用程序能够完成加载工作

定义对应的schema和xsd文件

示例:

目录结构:

新建实体类User(略)

新建标签parser解析类 UserBeanDefinitionParser

新建对应的解析器处理类 UserNamespaceHandler

相关配置文件

在META-INF下新建对应的spring.handlers spring.schemas user.xsd文件

spirng.handlers 指定对应的handler处理类

spring.schemas 指定xsd文件路径

user.xsd xsd配置文件

关键方法:

getMergeLocalBeanDefinition在实例化之前,要把所有基础的BeanDefinition对象转换成RootBeanDefinition对象进行缓存,后续在需要马上实例化的时候直接获取定义的信息,而定义信息中如果包含了父类,那么必须要先创建父类才有子类。

BeanFacoryFacoryBean区别:  都是对象工厂,用来创建对象,如果使用BeanFactory接口,必须严格遵循Spring bean的生命周期, 从实例化到初始化,invokeAwareMethod, invokeInitMethod, before, after,此流程非常复杂且麻烦。 更加便捷简单的方式创建的话,用到了FactoryBean接口,不需要遵循此创建顺序。FactoryBean创建的对象由Spring管理,存在一级缓存,但是不是单例的话,需要每次调用的时候重新创建,缓存中不会保存当前对象。

Bean的生命周期

入口定义的xml或注解配置等

创建容器对象 obtainFreshBeanFactory

2.1 创建容器DefaultListableBeanFactory

2.2 设置某些属性值

2.3 加载配置文件 loadBeanDefinitions—>document  **—> ** element

—>parseDefaultElement(bean标签)/parseCustomElement(context/aop开头的标签,自定义标签等)

—>GenericBeanDefinition (后续调用才会触发) 合并—>RootBeanDefinition

prepareBeanFactory**—>** 给容器工厂设置某些属性值

invokeBeanFactoryPostProcessor**—>** 调用执行BFPP,可以修改或者引入其他的beanDefinition,需要注意BFPP      针对的操作对象是BeanFactory**—>** ConfigurationClassPostProcessor用来完成相关注解的解析工作(@Import,@Configuration,@Component,@Bean等等)

registerBeanPostProcessor 实例化BPP**—>** 完成BeanPostProcessor的注册工作,方便后续在实例化完成之后调用before和after的操作

finishBeanFactoryInitialization—>完成对象的创建工作 (先从缓存中找,没有则创建)—>将需要创建的bean对象放到数组中,挨个进行创建

getBean**—>**doGetBean **—>**createBean **—>**doCreateBean

**—>**createBeanInstance(1. supplier 2. factoryMethod 3. 反射创建 4. BPP代理方式)

    **—>**applyMergedBeanDefinitionPostProcessors

    (注册生命周期接口 @PostConstruct,@PreDestory,@Resource,@Autowired,@Value)

—>populateBean(1.填充属性 2.创建需要依赖的bean对象)

—>initiializeBean(进行初始化工作

invokeAwareMethod(BeanNameAware, BeanClassLoaderAware,BeanFactoryAware)

执行BPP的before方法 ApplicationAwarePostProcessor继续实现某些Aware接口的set方法/CommonAnnotationBeanPostProcessor

invokeInitMethod 判断是否实现InitializingBean 执行afterPropertiesSet 最后一次修改属性值

/执行用户自定义的init-method

执行BPP的after方法 aop)

—>获取对象来进行相关操作**—>** 销毁流程 DestructionAwareBeanPostProcessors(postProcessBeforeDestruction) / DisposableBean

/ 自定义的destoryMethod

循环依赖

Spring AOP的BeanDefinition的准备工作

使用xml注解

查看配置文件的解析工作,在处理之后的BeanDefinition中包含什么信息

BeanDefinition的解析工作(loadBeandefinitions(default和custom))

对aop相关的BeanDefinition进行实例化操作,在进行第一个对象创建之前,就必须要把aop相关的对象提前准备好,因为无法预估哪些对象需要动态代理

在哪个步骤中可以提前实例化并且生成对应的对象

BFPP是用来对BeanFactory进行修改操作的,不会影响到后续的实例化过程

BPP(BeanPostProcessor(before和after))  resolveBeforeInstantiation()

AspectJPointcutAdvisor#0->AspectJAroundAdvice->MethodLocatingFactory 0 / 表达式 1 / SimpleBeanFactoryAwareAspectInstanceFactory 2

AspectJPointcutAdvisor#1->AspectJMethodBeforeAdvice->MethodLocatingFactory 0 / 表达式 1 / SimpleBeanFactoryAwareAspectInstanceFactory 2

AspectJPointcutAdvisor#2->AspectJAfterAdvice->MethodLocatingFactory 0 / 表达式 1 / SimpleBeanFactoryAwareAspectInstanceFactory 2

AspectJPointcutAdvisor#3->AspectJAfterReturingAdvice->MethodLocatingFactory 0 / 表达式 1 / SimpleBeanFactoryAwareAspectInstanceFactory 2

AspectJPointcutAdvisor#4->AspectJAfterThrowingAdvice->MethodLocatingFactory 0 / 表达式 1 / SimpleBeanFactoryAwareAspectInstanceFactory 2

总结

准备BeanDefinition->1.AspectjExpressionPointcut  2.Advisior#0 - #4  3. AspectjAutoProxyCreator

Spring AOP的核心对象的创建

创建AspectJPointcutAdvisor#0-4, 先使用带参的构造方法进行对象的创建,但是想使用带参的构造方法必须要参数对象准备好,因此要准备创建包含的对象AspectJAroundAdvice

创建AspectJAroundAdvice,也需要使用带参的构造方法进行创建,也需要提前准备好具体的参数对象,包含三个参数: MethodLocatingFactoryBean, AspectJExpressionPointcut, SimpleBeanFactoryAwareAspectInstanceFactory

分别创建上述的三个对象,上述三个对象的创建过程都是调用无参的构造方法,直接反射生成。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容