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的创建流程,具体怎么实现,就看个人。

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
			prepareRefresh();
            // 告诉子类该刷新BeanFactory了
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			prepareBeanFactory(beanFactory);

			try {
                // 告诉子类BeanFactory准备完成了
				postProcessBeanFactory(beanFactory);

                // 统计信息
				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// 调用BeanFactoryPostProcessor来进一步定义BeanFactory
				invokeBeanFactoryPostProcessors(beanFactory);

				// 创建注册BeanPostProcessor
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// 国际化设置
				initMessageSource();

				// 初始化事件多播
				initApplicationEventMulticaster();

				// 告诉子类可以实例化其他一些特殊Bean了
				onRefresh();

				// 检查注册事件监听器
				registerListeners();

				// 实例化所有剩下的非懒加载单例bean
				finishBeanFactoryInitialization(beanFactory);

				// 发布相应的事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 消耗已经创建的bean
				destroyBeans();

				// 重置 'active' 标识
				cancelRefresh(ex);
				throw ex;
			}
			finally {
				// 重置哪些可能已经不需要的公共缓存
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

4. refresh方法说明

顺序调用方法说明
1prepareRefresh处理properties的占位符,验证上下文环境中所有的properties是否可以解析,设置早期事件监听器
2obtainFreshBeanFacotry获取的BeanFactory,主要是为了得到BeanDefinition这么一个玩意儿,解析创建BeanDefinition不一定发生在这一步
3prepareBeanFactoryBeanFactory定制化工作
4postProcessBeanFactoryBeanFactory准备好了,如果还想在对BeanFactory进行定制可以在这里完成
5invokeBeanFactoryPostProcessorsBeanFctoryPostProcessor在这个地方被执行,可以处理一些特殊的bean,如EventListenerMethodProcessor的EventListenerFactory
6registerBeanPostProcessors实例化和注册BeanPostProcessor,并处理它们的执行顺序
7initMessageSource国际化设置
8initApplicationEventMulticaster初始化事件多播器
9onRefresh用于初始化一些特定Bean,如SpringBoot重写该方法启动Tomcat容器
10registerListeners检查容器中所有的事件监听器,并注册
11finishBeanFactoryInitialization实例化剩下所有非懒加载的单例
12finishRefresh发布容器刷新完成事件
13resetCommonCaches清除公共缓存数据

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()));

    // 配置BeanFactory的回调类
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    // 配置忽略自动装配的接口
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationStartup.class);

    // BeanFactory中手动注册下面这些类
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // 注册一个早期的BeanPostProcessor用来探测beans是不是一个ApplicationListeners
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // 探测LoadTimeWeaver,如果是准备织入
    if (!IN_NATIVE_IMAGE && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // 设置临时类加载器
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // 注册默认的environment beans ConfigurableEnvironment
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    // 注册系统属性bean
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }

    //注册系统环境变量bean
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
    // 注册启动指标监测bean
    if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
        beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
    }
}

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的定制化,你可以通过Spring Bean生命周期这篇文章了解Bean的生命周期。

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

AnnotationConfigApplicationContext:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

AnnotationConfigApplicationContext

ClassPathXmlApplicationContext:

ApplicationContext context = new ClassPathXmlApplicationContext(“application.xml”);

ClassPathXmlApplicationContext

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值