• SpringBoot2启动流程分析


    首先上一张图,图片来自 SpringBoot启动流程解析

    SpringBoot启动结构图.png

    本文基于spring-boot-2.0.4.RELEASE.jar包分析。

    程序启动入口

    public static void main(String[] args) {
    	SpringApplication.run(Springboot2Application.class, args);
    }
    

    run是一个静态方法,最后会调用创建SpringApplication实例并run

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

    我们先看new SpringApplication(xx)构建的实例。

    public SpringApplication(Class... primarySources) {
    	this((ResourceLoader)null, primarySources);
    }
    
    public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
    	this.sources = new LinkedHashSet();
    	this.bannerMode = Mode.CONSOLE;
    	this.logStartupInfo = true;
    	this.addCommandLineProperties = true;
    	this.headless = true;
    	this.registerShutdownHook = true;
    	this.additionalProfiles = new HashSet();
    	this.resourceLoader = resourceLoader;
    	Assert.notNull(primarySources, "PrimarySources must not be null");
    	//配置source
    	this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
    	//判断是否web应用
    	this.webApplicationType = this.deduceWebApplicationType();
    	//创建初始化构造器
    	this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    	//创建应用监听器
    	this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    	//推断出main方法类
    	this.mainApplicationClass = this.deduceMainApplicationClass();
    }
    

    SpringApplication的构造函数主要设置了一些基本参数并配置source、判断了是否web应用、创建初始化构造器、创建应用监听器、找出main方法所在的类。
    getSpringFactoriesInstances为获取spring工厂中的实例,具体代码块为

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    	return this.getSpringFactoriesInstances(type, new Class[0]);
    }
    
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        //获取类加载器
    	ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    	//通过类加载器、获取指定的spring.factories文件,并获取文件中工厂类的全路径名
    	Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        //通过类路径反射得到工厂class对象、构造方法
    	List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    	AnnotationAwareOrderComparator.sort(instances);
    	return instances;
    }
    

    new SpringApplication(xx)构建完实例后,会进行run方法。

    public ConfigurableApplicationContext run(String... args) {
    		StopWatch stopWatch = new StopWatch();
            //应用启动计时器开始计时
    		stopWatch.start();
    		ConfigurableApplicationContext context = null;
    		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
            //Headless模式配置
    		configureHeadlessProperty();
            //获取启动监听器
    		SpringApplicationRunListeners listeners = getRunListeners(args);
            //应用启动监听器开始计时
    		listeners.starting();
    		try {
    			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
    					args);
                 //配置环境模块(祥见下面prepareEnvironment方法)
    			ConfigurableEnvironment environment = prepareEnvironment(listeners,
    					applicationArguments);
                 //配置需要忽略的bean
    			configureIgnoreBeanInfo(environment);
                //Banner配置
    			Banner printedBanner = printBanner(environment);
                //创建应用上下文对象
    			context = createApplicationContext();
    			exceptionReporters = getSpringFactoriesInstances(
    					SpringBootExceptionReporter.class,
    					new Class[] { ConfigurableApplicationContext.class }, context);
                //上下文基本属性配置(祥见下面prepareContext方法)
    			prepareContext(context, environment, listeners, applicationArguments,
    					printedBanner);
                //更新应用上下文(祥见下面refresh方法)
    			refreshContext(context);
    			afterRefresh(context, applicationArguments);
    			stopWatch.stop();
    			if (this.logStartupInfo) {
    				new StartupInfoLogger(this.mainApplicationClass)
    						.logStarted(getApplicationLog(), stopWatch);
    			}
    			listeners.started(context);
    			callRunners(context, applicationArguments);
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, exceptionReporters, listeners);
    			throw new IllegalStateException(ex);
    		}
    
    		try {
    			listeners.running(context);
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, exceptionReporters, null);
    			throw new IllegalStateException(ex);
    		}
    		return context;
    	}
    
    private ConfigurableEnvironment prepareEnvironment(
    			SpringApplicationRunListeners listeners,
    			ApplicationArguments applicationArguments) {
    		// 创建配置环境
    		ConfigurableEnvironment environment = getOrCreateEnvironment();
            //加载属性文件
    		configureEnvironment(environment, applicationArguments.getSourceArgs());
            //监听器监听配置
    		listeners.environmentPrepared(environment);
    		bindToSpringApplication(environment);
    		if (this.webApplicationType == WebApplicationType.NONE) {
    			environment = new EnvironmentConverter(getClassLoader())
    					.convertToStandardEnvironmentIfNecessary(environment);
    		}
    		ConfigurationPropertySources.attach(environment);
    		return environment;
    	}
    
    private void prepareContext(ConfigurableApplicationContext context,
    			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
    			ApplicationArguments applicationArguments, Banner printedBanner) {
            //加载配置环境
    		context.setEnvironment(environment);
            //ResourceLoader资源加载器
    		postProcessApplicationContext(context);
            //初始化环境
    		applyInitializers(context);
            //配置监听
    		listeners.contextPrepared(context);
    		if (this.logStartupInfo) {
    			logStartupInfo(context.getParent() == null);
    			logStartupProfileInfo(context);
    		}
    
    		// Add boot specific singleton beans
    		context.getBeanFactory().registerSingleton("springApplicationArguments",
    				applicationArguments);
    		if (printedBanner != null) {
    			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    		}
    
    		// 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);
    	}
    
     public void refresh() throws BeansException, IllegalStateException {
            Object var1 = this.startupShutdownMonitor;
            synchronized(this.startupShutdownMonitor) {
                //准备更新上下文时的预备工作:1.初始化PropertySource; 2.验证Enrivonment中必要的属性
                this.prepareRefresh();
                //获取上下文中的BeanFactory
                ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
                //对BeanFactory做些预备工作
                this.prepareBeanFactory(beanFactory);
    
                try {
                    //对BeanFactory进行预处理
                    this.postProcessBeanFactory(beanFactory);
                    //执行容器中的BeanFactoryPostProcessor
                    this.invokeBeanFactoryPostProcessors(beanFactory);
                    //注册BeanPostProcessor
                    this.registerBeanPostProcessors(beanFactory);
                    //初始化MessageSource(国际化相关)
                    this.initMessageSource();
                    //初始化容器事件广播器(用来发布事件)
                    this.initApplicationEventMulticaster();
                    //初始化一些特殊的Bean,主要做了: 1.初始化ThemeSource(跟国际化相关的接口) 2.创建WebServer
                    this.onRefresh();
                    //将所有监听器注册到前两步创建的事件广播器中
                    this.registerListeners();
                    //结束BeanFactory的初始化工作(这一步主要用来将所有的单例BeanDefinition实例化)
                    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();
                }
    
            }
        }
    
  • 相关阅读:
    PyCharm 激活方法
    Android Studio 如何启动自身模拟器来调试(一般人我不告诉他)
    Android 打造一款逼格高的圆形图片
    Android Observer观察模式基础入门
    Android OkHttp3(完美封装)Get异步获取数据、Post异步获取数据、Form表单提交、文件下载
    Kotlin学习资料
    Android 导入外部字体的完美解决方案
    Android 开发者福利Google Developers中国网站发布
    Android 自定义弹出框 EditText获取光标后键盘遮挡,及初始化弹出键盘问题解决
    Android ListView动态设置高度
  • 原文地址:https://www.cnblogs.com/cnJun/p/12069814.html
Copyright © 2020-2023  润新知