从源码分析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


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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

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