Spring核心流程梳理

1. 简介

之前其实有写过Spring Bean的生命周期:Spring 容器Bean与生命周期

当时太过于关注细节的实现,而进入了Spring庞大的体系之中,对于还不太了解Spring的朋友不太友好,也不方便记忆。

所以,这一次以应用为目的来重新梳理一下Spring核心流程。

因为对于实用主义来说,暂时并不想关心那么多Spring的细节,现在只希望能做2件事情:

  1. 当遇到问题了能快速知道大致那个步骤出现了问题,知道debug入口,以便于快速定位问题
  2. 知道一些Spring的重要扩展点,以便于更好的根据自己的需求完成自定义

2. 开始

想想我们使用Spring最常用的操作是什么?

无非就是我们添加一些xml、properties、注解配置。

然后,Spring解析这些配置帮我们创建相应的对象,并且用一个容器(上下文,BeanFactory,ApplicationContext)统一来管理。

如果,我们想要知道Spring怎样根据我们的配置,创建出我们需要的对象,那就得对Spring怎样创建上下文的流程有所了解。

所以,下面我们来简单看一下Spring创建上下文的核心流程。

注意:不要太过于关注每一个分支的细节,需要的时候再细看,否则就会没完没了的陷入一个又一个的分支细节之中。

不关心细节,只关心流程。

所以我们这里先不管是使用xml配置的ClassPathXmlApplicationContext,还是使用注解的AnnotationConfigApplicationContext,亦或是其他的Context。

我们这里只关注一个抽象类:AbstractApplicationContext,并且只关注它的refresh方法。

3. AbstractApplicationContext的refresh

这是一个典型的模板方法模式,在refresh方法中定义了各种Context的创建流程,具体怎么实现,就看个人。

1@Override 2 public void refresh() throws BeansException, IllegalStateException { 3 synchronized (this.startupShutdownMonitor) { 4 StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); 5 prepareRefresh(); 6 // 告诉子类该刷新BeanFactory了 7 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 8 prepareBeanFactory(beanFactory); 9 10 try { 11 // 告诉子类BeanFactory准备完成了 12 postProcessBeanFactory(beanFactory); 13 14 // 统计信息 15 StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); 16 // 调用BeanFactoryPostProcessor来进一步定义BeanFactory 17 invokeBeanFactoryPostProcessors(beanFactory); 18 19 // 创建注册BeanPostProcessor 20 registerBeanPostProcessors(beanFactory); 21 beanPostProcess.end(); 22 23 // 国际化设置 24 initMessageSource(); 25 26 // 初始化事件多播 27 initApplicationEventMulticaster(); 28 29 // 告诉子类可以实例化其他一些特殊Bean了 30 onRefresh(); 31 32 // 检查注册事件监听器 33 registerListeners(); 34 35 // 实例化所有剩下的非懒加载单例bean 36 finishBeanFactoryInitialization(beanFactory); 37 38 // 发布相应的事件 39 finishRefresh(); 40 } 41 42 catch (BeansException ex) { 43 if (logger.isWarnEnabled()) { 44 logger.warn("Exception encountered during context initialization - " + 45 "cancelling refresh attempt: " + ex); 46 } 47 48 // 消耗已经创建的bean 49 destroyBeans(); 50 51 // 重置 'active' 标识 52 cancelRefresh(ex); 53 throw ex; 54 } 55 finally { 56 // 重置哪些可能已经不需要的公共缓存 57 resetCommonCaches(); 58 contextRefresh.end(); 59 } 60 } 61 }

4. refresh方法说明

顺序

调用方法

说明

1

prepareRefresh

处理properties的占位符,验证上下文环境中所有的properties是否可以解析,设置早期事件监听器

2

obtainFreshBeanFacotry

获取的BeanFactory,主要是为了得到BeanDefinition这么一个玩意儿,解析创建BeanDefinition不一定发生在这一步

3

prepareBeanFactory

BeanFactory定制化工作

4

postProcessBeanFactory

BeanFactory准备好了,如果还想在对BeanFactory进行定制可以在这里完成

5

invokeBeanFactoryPostProcessors

BeanFctoryPostProcessor在这个地方被执行,可以处理一些特殊的bean,如EventListenerMethodProcessor的EventListenerFactory

6

registerBeanPostProcessors

实例化和注册BeanPostProcessor,并处理它们的执行顺序

7

initMessageSource

国际化设置

8

initApplicationEventMulticaster

初始化事件多播器

9

onRefresh

用于初始化一些特定Bean,如SpringBoot重写该方法启动Tomcat容器

10

registerListeners

检查容器中所有的事件监听器,并注册

11

finishBeanFactoryInitialization

实例化剩下所有非懒加载的单例

12

finishRefresh

发布容器刷新完成事件

13

resetCommonCaches

清除公共缓存数据

AbstractApplicationContext为prepareBeanFactory提供了默认实现,主要完成下面的工作:

  1. 设置类加载器

  2. 设置SpEL解析器和属性注册解析器

  3. 利用BeanPostProcessor的特性给各种Aware接口的实现类注入ApplicationContext中对应的属性

  4. 设置各种Aware接口的实现类为忽略自动装配

  5. 手动注册BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext

  6. 探测LoadTimeWeaver,并完成动态织入

  7. 注册其他工具bean:ConfigurableEnvironment、系统属性、系统环境变量、ApplicationStartup(容器启动监控)

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 设置类加载器 beanFactory.setBeanClassLoader(getClassLoader()); if (!shouldIgnoreSpel) {//设置SpEL解析器 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); } // 属性注册解析器 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    1// 配置BeanFactory的回调类 2beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); 3// 配置忽略自动装配的接口 4beanFactory.ignoreDependencyInterface(EnvironmentAware.class); 5beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); 6beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); 7beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); 8beanFactory.ignoreDependencyInterface(MessageSourceAware.class); 9beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); 10beanFactory.ignoreDependencyInterface(ApplicationStartup.class); 11 12// BeanFactory中手动注册下面这些类 13beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); 14beanFactory.registerResolvableDependency(ResourceLoader.class, this); 15beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); 16beanFactory.registerResolvableDependency(ApplicationContext.class, this); 17 18// 注册一个早期的BeanPostProcessor用来探测beans是不是一个ApplicationListeners 19beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); 20 21// 探测LoadTimeWeaver,如果是准备织入 22if (!IN_NATIVE_IMAGE && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { 23 beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); 24 // 设置临时类加载器 25 beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); 26} 27 28// 注册默认的environment beans ConfigurableEnvironment 29if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { 30 beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); 31} 32// 注册系统属性bean 33if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { 34 beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); 35} 36 37//注册系统环境变量bean 38if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { 39 beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); 40} 41// 注册启动指标监测bean 42if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) { 43 beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup()); 44}

    }

TIPS:

  1. PropertySource,主要处理properties文件中的键值对和系统变量
  2. PropertySource会注册到上下文环境中,我们可以通过Environment这个类直接获取
  3. systemProperties与systemEnvironment有啥区别?就是System.getProperties()与System.getenv(),更具体就是systemProperties是user.dir这些,systemEnvironment是PATH、OS这些

5. 核心流程梳理

前面我们已经大致从代码层面简单的介绍了Spring上下文启动的流程,下面用一个图做一个简单的梳理。

Spring核心流程梳理

6. Bean生命周期

前面在介绍Spring上下文启动的流程,我们为了尽量聚焦于核心的流程,并没有细化进入介绍和Bean生命周期的流程。

其实,对于定制化来说,我们更多的是针对Bean的定制化,你可以通过【】这篇文章了解Bean的生命周期。

当然,你也可以通过下面两个类来详细了解:

AnnotationConfigApplicationContext:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

AnnotationConfigApplicationContext

ClassPathXmlApplicationContext:

ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

ClassPathXmlApplicationContext

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

spring源码

SpringIOC容器源码解析系列,建议大家按顺序阅读,欢迎讨论(_spring源码均为4.1.6.RELEASE版本_)1.Spring源码IOC容器(一)构建简单IOC容器(https://my.oschina.net/u/2377110/blog/902073)2.Spring源码IOC容器(二)Bean的定位解析注

spring注解

随着越来越多地使用Springboot敏捷开发,更多地使用注解配置Spring,而不是Spring的applicationContext.xml文件。Configuration注解:Spring解析为配置类,相当于spring配置文件Bean注解:容器注册Bean组件,默认id为方法名@Configurat

springcloud eureka.instance

1.在springcloud中服务的 InstanceID默认值是:${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance\_id:${server.port}},也就是:主机名:应用名:应用端口。如图1