springBoot学习笔记源码分析之springApplication初始化过程

Posted 拐柒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springBoot学习笔记源码分析之springApplication初始化过程相关的知识,希望对你有一定的参考价值。

SpringApplication

springboot 启动的main放中的SpringApplication.run(DemoApplication.class, args)中的run方法其实是调用了SpringApplication中的run方法。

  public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

该方法分为两部分,第一部分为初始化SpringApplication,第二部分为run

初始化SpringApplication

		//将resourceLoader 置为null
		this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        //把启动类applicaiton放入成员变量名为primarySources的set中
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        //推断应用类型,后面会根据该变量初始化对应的环境,一般为servlet
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //初始化classpah下META-INF/spring.factory中已配置的ApplicaitonContextInitializer,通过反射进行初始化器的初始化。ApplicaitonContextInitializer是spring提供的一个接口,其作用spring容器在刷新之前,会回调initialize方法。
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //初始化classpah下META-INF/spring.factory中已配置的ApplicationListener,通过反射进行监听器的初始化。ApplicationListener可以对spring进行全生命周期的监听
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        //根据调用栈,推断出main方法的类名
        this.mainApplicationClass = this.deduceMainApplicationClass();

1、推断应用类型,一般为servlet。
2、初始化ApplicaitonContextInitializer初始化器。
3、初始化监听器
4、获取main方法类名。

run方法

public ConfigurableApplicationContext run(String... args) {
		//记录程序运行时间
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        //ConfigurableApplicationContext   spring的上下文
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        //1、获取并启动监听器
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //2、构造应用上下文环境
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            //3、初始化应用上下文
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            //4、刷新应用上下文前的准备阶段
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            //5、刷新应用上下文
            this.refreshContext(context);
            //6、刷新应用上下文后的拓展接口
            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, listeners);
            throw new IllegalStateException(var10);
        }

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

获取并启动监听器

  private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        //springApplicaitonRunListeners负责在springboot启动的不同阶段,广播出不同的消息,传递信息给ApplicationListener监听器实现类
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
    }

构造应用上下文环境

应用上下文环境:上下文,上下文代表了程序当下所运行的环境,联系你整个app的生命周期与资源调用,是程序可以访问到的所有资源的总和,资源可以是一个变量,也可以是一个对象的引用。

prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
		//创建并配置相应环境
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        //根据用户配置,配置environment系统环境,通过判断应用类型,即SERVLET,来创建环境
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach((Environment)environment);
        //启动相应的监听器,其中一个重要的监听器ConfigFileApplicationListener就是加载项目配置文件的监听器
        listeners.environmentPrepared(environment);
        this.bindToSpringApplication((ConfigurableEnvironment)environment);
        if (!this.isCustomEnvironment) {
            environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach((Environment)environment);
        return (ConfigurableEnvironment)environment;
    }

初始化应用上下文

beanFactory正是在AnnotationConfigServletWebServerApplicationContext实现的接口
GenericApplicationContext中定义的。在上面createApplicationContext()方法中的,
BeanUtils.instantiateClass(contextClass) 这个方法中,不但初始化了
AnnotationConfigServletWebServerApplicationContext类,也就是我们的上下文context,同样
也触发了GenericApplicationContext类的构造函数,从而IoC容器也创建了。

刷新应用上下文前的准备阶段

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		//设置容器环境
		context.setEnvironment(environment);
		//执行容器后置处理
		postProcessApplicationContext(context);
		//执行容器中的 ApplicationContextInitializer 包括spring.factories和通过三种 方式自定义的
		applyInitializers(context);
		//向各个监听器发送容器已经准备好的事件
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		//将main函数中的args参数封装成单例Bean,注册进容器
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		//加载启动类,将启动类注入容器
		load(context, sources.toArray(new Object[0]));
		//发布容器已加载事件
		listeners.contextLoaded(context);
	}

刷新应用上下文(IOC容器的初始化过程)

主要是执行AbstractApplicationContext类的refresh()方法。

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
        //刷新上下文环境
            this.prepareRefresh();
            //这里是在子类中启动refreshBeanFactory()的地方
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //准备bean工厂,以便在此上下文中使用
            this.prepareBeanFactory(beanFactory);

            try {
            //设置beanFactory的后置处理
                this.postProcessBeanFactory(beanFactory);
                //调用BeanFactory的后处理器,这些处理器是在Bean定义中向容器注册的
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //注册Bean的后处理器,在Bean创建过程中调用
                this.registerBeanPostProcessors(beanFactory);
                //对上下文中的消息源进行初始化
                this.initMessageSource();
                //初始化上下文中的事件机制
                this.initApplicationEventMulticaster();
                //初始化其他特殊的Bean
                this.onRefresh();
                //检查监听Bean并且将这些监听Bean向容器注册
                this.registerListeners();
                 //实例化所有的(non-lazy-init)单件
                this.finishBeanFactoryInitialization(beanFactory);
                //发布容器事件,结束Refresh过程
                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();
            }

        }
    }

以上是关于springBoot学习笔记源码分析之springApplication初始化过程的主要内容,如果未能解决你的问题,请参考以下文章

Springboot源码分析之代理三板斧

我的第一个spring boot程序(spring boot 学习笔记之二)

Springboot源码分析之TypeFilter魔力

SpringBoot 学习笔记 -- [spring Boot配置文件之YAML格式, springBoot自动配置浅入,springboot集成JDBC]

-RabbitMQ之Spring客户端源码

Spring Boot 学习笔记1---初体验之3分钟启动你的Web应用