雷丰阳springboot之原理运行流程

目录

雷丰阳课件

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

引子-重要的监听器

springboot的运行流程是非常复杂的。

但是在运行流程当中,包含了几个非常重要的事件回调机制。

我们也希望掌握这些事件回调机制,真正干预到springboot的运行流程。

特别是这些事件回调机制,牵扯到的接口。

  1. ApplicationContextInitializer,需要配置在META-INF/spring-factories
  2. SpringApplicationRunListener,需要配置在META-INF/spring-factories
  3. ApplicationRunner,需要放在IOC容器中。
  4. CommandLineRunner,需要放在IOC容器中。

Debug跟踪springboot启动

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

step into

雷丰阳springboot之原理运行流程

step into

雷丰阳springboot之原理运行流程

这里说明了springboot启动是分为两步,第一步是创建SpringApplication对象,第二步是运行run方法。

第一步:创建SpringApplication对象

step into

雷丰阳springboot之原理运行流程

step over

雷丰阳springboot之原理运行流程

不断step over,就来到了下面:

雷丰阳springboot之原理运行流程

这是说明,是调用了initialize(sources)来创建对象的。

step into

雷丰阳springboot之原理运行流程

通过initialize(sources)创建对象的流程,就是下面的流程:

	private void initialize(Object[] sources) {
		//sources就是主配置类,这里面就是sources不为空的时候,保存主配置类。
        //保存在了sources属性当中。
        if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
        //判断当前应用是不是web应用,具体怎么判断,看下一个番外1
		this.webEnvironment = deduceWebEnvironment();
        
        //参考番外2
        //getSpringFactoriesInstances方法从类路径下找到"META-INF/spring.factories"下面配置的所有的ApplicationContextInitializer,然后保存起来。
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
        
        //从类路径下找到"META-INF/spring.factories"下面配置的所有的ApplicationListener
        //参考番外3
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        
        //参考番外4
        //决定哪个applicationClass是个主程序。
        //从多个配置类中找到有main方法的主配置类
		this.mainApplicationClass = deduceMainApplicationClass();
	}

到这里的时候,springapplication对象,就创建完成了。

番外1:判断web环境

判断web环境的时候,是这样的:

雷丰阳springboot之原理运行流程

	private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

看看上面的Servlet或者ConfigurableWebApplicationContext这些东西是否存在。

番外2:从类路径下找Initializer

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

这句话的意思就是:
getSpringFactoriesInstances方法从"META-INF/spring.factories"下面找ApplicationContextInitializer

这些东西就在这里:

雷丰阳springboot之原理运行流程

我们step over一下,然后点进去看看,找到了多少initializer:

雷丰阳springboot之原理运行流程

一看是找到了6个Initializer。

番外3:从类路径下找到ApplicationListener

雷丰阳springboot之原理运行流程

一共是找到了10个listeners。

番外4:找到主配置类

this.mainApplicationClass = deduceMainApplicationClass();

雷丰阳springboot之原理运行流程

从多个配置类中找到有main方法的主配置类。

第二步:运行run方法

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

运行流程

	public ConfigurableApplicationContext run(String... args) {
		// 创建一个监听,然后启动
        StopWatch stopWatch = new StopWatch();
		stopWatch.start();
        
        //创建一个IOC容器,是空的。
        //声明analyzers
		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;
		
       	//参考番外1
        //configureHeadlessProperty是跟做awt应用有关的玩意
        configureHeadlessProperty();
        
        //获取SpringApplicationRunListeners,从类路径META-INF/spring.factories
        //参考番外2
		SpringApplicationRunListeners listeners = getRunListeners(args);
        //回调所有的SpringApplicationRunListeners的starting方法。
        //参考番外2
		listeners.starting();
		try {
            
            //把args命令行参数,用ApplicationArguments封装了一下。
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
            //参考番外3
            //创建环境,然后回调所有的SpringApplicationRunListeners的environmentPrepared方法。
            //表示环境准备完成。
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
            
            //控制台打印Banner图标
            //参考番外4
			Banner printedBanner = printBanner(environment);
            
            //创建IOC容器,ApplicationContext
            //参考番外5
            //决定创建web的IOC还是普通的IOC容器
			context = createApplicationContext();
            
            //analyzers主要是出现异常之后,用来做异常报告的。
			analyzers = new FailureAnalyzers(context);
            
            //参考番外6
            //准备上下文环境,传入了IOC容器,环境,listeners等等
            //applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
            //回调所有的SpringApplicationRunListener的contextPrepared()方法。
            //prepareContext运行完成之后,回调所有的SpringApplicationRunListener的contextLoaded()
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
            
            //参考番外7
            //刷新容器:IOC容器初始化的过程。
            //加载IOC容器当中所有的组件。
            //扫描所有的配置类,扫描所有的@Bean来创建对象进行初始化
            //如果是web应用,还会创建嵌入式的tomcat
            //扫描,创建,加载所有组件的地方
            //自动配置类,组件,配置类,都是在这里,IOC容器加载的。
			refreshContext(context);
            
            //参考番外8
            //从IOC容器中获取所有的ApplicationRunner和CommandLineRunner
            //ApplicationRunner先回调。
            //CommandLineRunner再回调。
			afterRefresh(context, applicationArguments);
            
            //所有的SpringApplicationRunListener回调finished方法
			listeners.finished(context, null);
            
            //保存当前应用状态
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
            //整个springboot应用启动完成之后。
            //返回IOC容器
            //IOC容器当中有所有的组件。
			return context;
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}

番外1:configureHeadlessProperty是跟做awt应用有关的玩意

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

番外2:SpringApplicationRunListeners

雷丰阳springboot之原理运行流程

一路step over然后可以看到:获取到的listener是如下:

雷丰阳springboot之原理运行流程

listeners.starting();step into进来

雷丰阳springboot之原理运行流程

点进去,可以看到SpringApplicationRunListener当中,有下面的回调机制的方法:

雷丰阳springboot之原理运行流程

番外3:prepareEnvironment

雷丰阳springboot之原理运行流程

首先是创建环境

雷丰阳springboot之原理运行流程

创建环境完成后,会回调SpringApplicationRunListeners的environmentPrepared方法。

番外4:printBanner

雷丰阳springboot之原理运行流程

番外5:createApplicationContext()

step into之后,看到下面的内容:

雷丰阳springboot之原理运行流程

雷丰阳springboot之原理运行流程

番外6:prepareContext

雷丰阳springboot之原理运行流程

	private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		//将environment保存到IOC容器当中。
        context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}

		// Add boot specific singleton beans
        // 把命令行参数的对象,注册到IOC容器中。包括把banner也注册进来。
		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

		// Load the sources
        // 相当于拿到主类
		Set<Object> sources = getSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[sources.size()]));
        // 回调所有的contextLoaded方法。
		listeners.contextLoaded(context);
	}
applyInitializers(context);

applyInitializers是干嘛的呢?这些应该跟一些初始化器有关。

我们step into进去。

雷丰阳springboot之原理运行流程

获取所有的ApplicationContextInitializer,调用他们的initialize方法。

这些ApplicationContextInitializer,就是我们在第一步,创建SpringApplication对象的时候,拿到的所有的ApplicationContextInitializer。

listeners.contextPrepared(context);

雷丰阳springboot之原理运行流程

番外7:refreshContext()

不断step into,来到这里:

    public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                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();
            }

        }
    }

番外8:afterRefresh()

step into进来。

雷丰阳springboot之原理运行流程

	protected void afterRefresh(ConfigurableApplicationContext context,
			ApplicationArguments args) {
		callRunners(context, args);
	}

	private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<Object>();
        //相当于,从所有的IOC容器中,获取所有的ApplicationRunner和CommandLineRunner
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<Object>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}
上一篇:Ubuntu配置apt的国内源地址


下一篇:更新vim