从源码分析Spring启动过程

一直没有梳理过这些知识,导致没能有条理地,系统了解spring整体框架的工作原理。现到了有点迷茫的时候,趁着有时间从头梳理了一下spring的相关知识。了解Spring启动过程前先了解一下Spring的整体框架框架。

深入了解Spring前,先弄清楚几个问题:

[if !supportLists]1. [endif]Spring是什么?

[if !supportLists]2. [endif]使用Spring能给我们带来什么?

[if !supportLists]3. [endif]Spring的工作原理是什么?


Spring是一个全栈框架,提供了从表示层到业务层再到持久层的一套完整的解决方案。可以很方便地让应用集成第三方框架组件,快速集成第三方提供的功能。Spring属于低侵入式设计,可以降低各组件之间的耦合性,实现软件各层之间的解耦,加快应用的开发。


Spring框架的7个模块


组成Spring框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

[if !supportLists]· [endif]核心容器:核心容器提供Spring框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。

[if !supportLists]· [endif]Spring Context:SpringContext是一个配置文件,向Spring框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。

[if !supportLists]· [endif]Spring AOP:通过配置管理特性,Spring AOP模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

[if !supportLists]· [endif]Spring DAO:JDBC DAO抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。

[if !supportLists]· [endif]Spring ORM:Spring框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。

[if !supportLists]· [endif]Spring Web模块:Web上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

[if !supportLists]· [endif]Spring MVC框架:MVC框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

Spring的两大核心IOC和AOP。

以下介绍spring启动过程是基于springboot方式。

其入口就是SpringApplication.run(DemoApplication.class,args);

创建Spring上下文:Context = createApplicationContext();

其中webApplicationType由SpringApplication初始化时指定

this.webApplicationType = WebApplicationType.deduceFromClasspath();


从deduceFromClasspath方法可以看到,如果存在org.springframework.web.reactive.DispatcherHandler且不存在org.springframework.web.servlet.DispatcherServlet且不存在org.glassfish.jersey.servlet.ServletContianer时,WebApplicationType为REACTIVE,否则返回Servlet。此处采用的是默认配置,返回的是Servlet.

所以createApplicationContext初始化的为web.servlet.context.AnnotationConfigServletWebServerApplicationContext。

创建webApplicationContext后,刷新context前需完成一些准备工作prepareContext()方法。

Load(context,sources.toArray(new Object[0])方法根据注解,XML或componentScan路径加载bean并注册到BeanDefinitionMap中

刷新ApplicationContext前数据准备好了,接下来执行refreshContext(context)方法。

refreshContext(context)里调用refresh(context)方法

protected void refresh(ApplicationContext applicationContext) {   

     Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);   

    ((AbstractApplicationContext) applicationContext).refresh();

}

((AbstractApplicationContext) applicationContext).refresh();这一句话实际走的就是AbstractApplicationContext.refresh();


代码来到这里,就与传统的配置spring启动流程一样了。

其中有个关键的方法:obtainFreshBeanFactory(),看似个获取一个BeanFactory,其实这方法里做了很多事情,如:加载Bean并注册到spring容器。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  

     refreshBeanFactory();   return getBeanFactory();

}


AbstractRefreshableApplicationContext.refreshBeanFactory()方法:

DefaultListableBeanFactory 是Spring整个bean加载的核心部分。

loadBeanDefinitions(beanFactory)方法,从方法名可以看出主要功能是解析配置文件中的bean定义并加载注册。


loadBeanDefinitions(beanFactory)解析XML的会走到AbstractXmlApplicationContext.loadBeanDefinitions(beanFactory)。最终会调用XmlBeanDefinitionReader.loadBeanDefinitions(EncodeResource encodeResource);


最后通过Document解析XML,并将XML定义的BEAN解析成BeanDefinition。最后通过BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());将BeanDefinition注册到BeanFactory中。

至些解析XML的obtainFreshBeanFactor()方法完成。

代码继续回到AbstractApplicationContext.refresh()方法中prepareBeanFactory(beanFactory);主要是对新实例化好的BeanFactory对象进行相关的参数设置。

invokeBeanFactoryPostProcessors(beanFactory)方法主要是判断BeanFactory中是否有指定类型的Bean,有则调用其相应的方法。

initApplicationEventMulticaster();方法主要是初始化一个applicationContext事件广播器。

onRefresh();模板方法,执行子类里的onRefresh方法。

registerListeners(); 主要是注册一些应用的监听器。

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

finishBeanFactoryInitialization(beanFactory);主要是实例化剩下所有的非懒加载的单例bean实体。

// Last step: publish corresponding event.

finishRefresh();

最后一步主要是清理一些缓存,触发context完成事件。


至此spring的启动基本完成。

总结:Spring的启动过程就是资源的加载和将注解BEAN或配置文件XML定义的BEAN转换成BeanDefinition并注册到BeanFactory,完成ApplicationContenct上下文创建的过程。

Spring的两大核心基础:BeanFactory,ApplicationContext


以上仅是本人的学习随笔笔记,由于能力有限可能存在错误的地方,欢迎指出。大家可以相互学习。

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

推荐阅读更多精彩内容

  • Spring容器高层视图 Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相...
    Theriseof阅读 2,811评论 1 24
  • 依赖注入是Spring框架最核心的能力,Spring框架提供的AOP,WebMVC等其它功能都是以依赖注入容器作为...
    无醉_1866阅读 398评论 0 1
  • 对于java中的思考的方向,1必须要看前端的页面,对于前端的页面基本的逻辑,如果能理解最好,不理解也要知道几点。 ...
    神尤鲁道夫阅读 812评论 0 0
  • 第三章 住校风波 外面的风在乌云的笼罩下毫无头绪地刮着,风沙中小角落里的垃...
    沫若水阅读 212评论 0 0
  • 紫菜对于在海边生活的人们来说,最熟悉不过了。它也是海边寻常老百姓家里最日常的一道菜。 紫菜是生长在浅海岩礁上,一种...
    七月风阅读 449评论 1 11