SpringBoot之容器启动源码分析与Bean加载

SpringBoot之启动容器源码分析

1、SpringApplication#run()

由SpringBoot应用引导类的 SpringApplication#run() 进入我们可以看到以下代码

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        // 监视器启动
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        // 从 META-INF/spring.factories 中获取 SpringApplicationRunListener 实现类,并调用starting()
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 准备环境变量配置
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            // 通过 spring.beaninfo.ignore 配置是否忽略bean信息 暂不明觉厉
            this.configureIgnoreBeanInfo(environment);
            // 打印SpringBoot控制台启动图案
            Banner printedBanner = this.printBanner(environment);
            // 创建应用上下文
            context = this.createApplicationContext();
            // 从 META-INF/spring.factories 中获取异常报告处理器,用作处理启动异常
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            /**
              * 准备应用上下文
              * 1 设置上下文环境配置
              * 2 注册 beanNameGenerator 等
              * 3 执行 ApplicationContextInitializer#initialize()初始化
              */
            ApplicationContextInitializer#initialize() 初始化
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            
            // 刷新上下文(下面重点分析)
            this.refreshContext(context);
            
            // 容器初始化之后 开始执行 ApplicationRunner 和 CommandLineRunner 自定义初始化执行器
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

2、SpringBoot 启动源码之 refreshContext() 方法

通过上面的代码可以看出,关键代码在于
this.refreshContext(context)
该方法最终会执行
AbstractApplicationContext#refresh()
这才是Spring容器启动的核心内容,重头戏一起往下看:

  • spring容器初始化总览 AbstractApplicationContext#refresh()
public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
        	// 准备初始化容器工作,设置启动标志、记录启动时间等
            this.prepareRefresh();
            // 创建 beanFactory, 并加载bean定义等
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            // beanFactory注入一些标准组件,例如ApplicationContextAwareProcessor,ClassLoader等
            this.prepareBeanFactory(beanFactory);

            try {
            	// 给实现类留的一个钩子,例如注入BeanPostProcessors,这里是个空方法 
                this.postProcessBeanFactory(beanFactory);

                // 执行 BeanFactoryPostProcessor 实现类的 postProcessBeanFactory()方法
                this.invokeBeanFactoryPostProcessors(beanFactory);

                // 注册 BeanPostProcessor 实现类
                this.registerBeanPostProcessors(beanFactory);
                
	            // 国际化资源处理 
                this.initMessageSource();

				// bean工厂注册一个key为applicationEventMulticaster的广播器 用于事件广播
                this.initApplicationEventMulticaster();

				// 给实现类留的一钩子,可以执行其他refresh的工作,比如启动tomcat server
                this.onRefresh();

				// 注册事件监听器
                this.registerListeners();
                
				// 完成bean的初始化
                this.finishBeanFactoryInitialization(beanFactory);
                // 完成容器启动,发布容器启动事件
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

上述即spring容器启动流程总览,不建议大家阅读源码每一行代码都需要看懂,细看的话只会让你陷入到无穷无尽的代码海洋中。我们需要学会择重避轻,下面我将重点分析bean初始化流程。

3、Spring bean的加载

由上述源码我们可以看出bean的加载核心代码在于
this.finishBeanFactoryInitialization(beanFactory);
下面一起来分析以下该方法的实现,以下直接上关键代码:

bean的三级缓存,以及bean的初始化

/**
 * finishBeanFactoryInitialization() 最终会调用该方法
  */
 public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Pre-instantiating singletons in " + this);
        }

        List<String> beanNames = new ArrayList(this.beanDefinitionNames);
        Iterator var2 = beanNames.iterator();

        while(true) {
            String beanName;
            Object bean;
            do {
                while(true) {
                    RootBeanDefinition bd;
                    do {
                        do {
                            do {
                                if (!var2.hasNext()) {
                                    var2 = beanNames.iterator();

                                    while(var2.hasNext()) {
                                        beanName = (String)var2.next();
                                        // 这里是从 bean的三级缓存中取
                                        Object singletonInstance = this.getSingleton(beanName);
                                        if (singletonInstance instanceof SmartInitializingSingleton) {
                                            SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
                                            if (System.getSecurityManager() != null) {
                                                AccessController.doPrivileged(() -> {
                                                    smartSingleton.afterSingletonsInstantiated();
                                                    return null;
                                                }, this.getAccessControlContext());
                                            } else {
                                                smartSingleton.afterSingletonsInstantiated();
                                            }
                                        }
                                    }

                                    return;
                                }

                                beanName = (String)var2.next();
                                bd = this.getMergedLocalBeanDefinition(beanName);
                            } while(bd.isAbstract());
                        } while(!bd.isSingleton());
                    } while(bd.isLazyInit());

                    if (this.isFactoryBean(beanName)) {
                        bean = this.getBean("&" + beanName);
                        break;
                    }

                    this.getBean(beanName);
                }
            } while(!(bean instanceof FactoryBean));

            FactoryBean<?> factory = (FactoryBean)bean;
            boolean isEagerInit;
            if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                SmartFactoryBean var10000 = (SmartFactoryBean)factory;
                ((SmartFactoryBean)factory).getClass();
                isEagerInit = (Boolean)AccessController.doPrivileged(var10000::isEagerInit, this.getAccessControlContext());
            } else {
                isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
            }

            if (isEagerInit) {
                this.getBean(beanName);
            }
        }
    }

上面代码可以看出首先 从bean的三级缓存中获取bean,如缓存中没有,则调用getBean()

Bean的三级缓存

  • singletonObjects:用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用

  • earlySingletonObjects:提前曝光的单例对象的cache,存放原始的 bean 对象(尚未填充属性),用于解决循环依赖

  • singletonFactories:单例对象工厂的cache,存放 bean 工厂对象,用于解决循环依赖

	/**
	  * 从三级缓存中获取bean
	  */
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            synchronized(this.singletonObjects) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }

        return singletonObject;
    }

下面看getBean() 方法调用如下

1、getBean()
2、doGetBean()
3、createBean()
4、doCreateBean()
5、populateBean()
6、initializeBean()
以上看出获取bean还是很曲折的,我们直接关注最后 initializeBean()

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
 		// 执行 Aware 接口
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(() -> {
                this.invokeAwareMethods(beanName, bean);
                return null;
            }, this.getAccessControlContext());
        } else {
            this.invokeAwareMethods(beanName, bean);
        }
		/**
		  * 执行 BeanPostProcessor#postProcessBeforeInitialization         bean初始化前置方法
		  * 其中 InitDestroyAnnotationBeanPostProcessor 来执行 @PostConstruct 标注的方法
		  */
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        try {
        	// bean初始化方法 init-method 和 InitializingBean#afterPropertiesSet()
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }
		
		/**
          * 执行 BeanPostProcessor#postProcessAfterInitialization bean初始化后置方法
          * 其中 InitDestroyAnnotationBeanPostProcessor 来执行 @PreDestroy 标注的方法
          */ 
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

到此我们已经分析完SpringBoot启动过程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章