博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
011-Spring Boot 运行流程分析SpringApplication.run
阅读量:6186 次
发布时间:2019-06-21

本文共 12468 字,大约阅读时间需要 41 分钟。

一、程序入口

1.1、静态方法

//直接调用run方法ConfigurableApplicationContext context = SpringApplication.run(App.class, args);

内部实现:

public static ConfigurableApplicationContext run(Object source, String... args) {        return run(new Object[] { source }, args);    }

查看run

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {        return new SpringApplication(sources).run(args);    }

故等效于实例化,后调用。同1.2

1.2、实例化SpringApplication,调用run方法

//实例化SpringApplication然后调用run方法        SpringApplication application = new SpringApplication(App.class);        ConfigurableApplicationContext context = application.run(args);

查看实现

public SpringApplication(Object... sources) {        initialize(sources);    }

查看initialize

@SuppressWarnings({ "unchecked", "rawtypes" })    private void initialize(Object[] sources) {        if (sources != null && sources.length > 0) {            this.sources.addAll(Arrays.asList(sources));        }        this.webEnvironment = deduceWebEnvironment();        setInitializers((Collection) getSpringFactoriesInstances(                ApplicationContextInitializer.class));        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));        this.mainApplicationClass = deduceMainApplicationClass();    }

二、运行流程分析

2.1、【new SpringApplication(App.class);初始化】

1、将source添加到set:中:this.sources.addAll(Arrays.asList(sources));

2、判断是不是web环境this.webEnvironment = deduceWebEnvironment();

private boolean deduceWebEnvironment() {        for (String className : WEB_ENVIRONMENT_CLASSES) {            if (!ClassUtils.isPresent(className, null)) {                return false;            }        }        return true;    }
View Code

内部

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

3、加载所有classpath下面的META-INF/spring.factoriesd的ApplicationContextInitializer, getSpringFactoriesInstances(ApplicationContextInitializer.class)

将所有的ApplicationContextInitializer放置到:private List<ApplicationContextInitializer<?>> initializers;中:

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

4、listener同3一致

加载所有classpath下面的META-INF/spring.factories的ApplicationListener, getSpringFactoriesInstances(ApplicationListener.class)

将所有的ApplicationListener放置到:private List<ApplicationListener<?>> listeners;中:

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

5、推断main方法所在的类

是this.mainApplicationClass = deduceMainApplicationClass();

2.2、【run方法】

6、开始执行run方法

public ConfigurableApplicationContext run(String... args) {        StopWatch stopWatch = new StopWatch();        stopWatch.start();        ConfigurableApplicationContext context = null;        FailureAnalyzers analyzers = null;        configureHeadlessProperty();        SpringApplicationRunListeners listeners = getRunListeners(args);        listeners.starting();        try {            ApplicationArguments applicationArguments = new DefaultApplicationArguments(                    args);            ConfigurableEnvironment environment = prepareEnvironment(listeners,                    applicationArguments);            Banner printedBanner = printBanner(environment);            context = createApplicationContext();            analyzers = new FailureAnalyzers(context);            prepareContext(context, environment, listeners, applicationArguments,                    printedBanner);            refreshContext(context);            afterRefresh(context, applicationArguments);            listeners.finished(context, null);            stopWatch.stop();            if (this.logStartupInfo) {                new StartupInfoLogger(this.mainApplicationClass)                        .logStarted(getApplicationLog(), stopWatch);            }            return context;        }        catch (Throwable ex) {            handleRunFailure(context, listeners, analyzers, ex);            throw new IllegalStateException(ex);        }    }
View Code

时间监视器

StopWatch stopWatch = new StopWatch();stopWatch.start();stopWatch.stop();

7、设置java.awt.headless系统变量

ConfigurableApplicationContext context = null;configureHeadlessProperty();

注意:新增FailureAnalyzers analyzers = null;

是为了失败分析调试时使用

FailureAnalyzers analyzers = null;analyzers = new FailureAnalyzers(context);

8、加载所有classpath下面的META-INF/spring.factories,SpringApplicationRunListeners

执行所有SpringApplicationRunListeners的所有started方法

SpringApplicationRunListeners listeners = getRunListeners(args);        listeners.starting();

作用:SpringApplicationRunListeners是Springboot扩展点。

  用来在执行过程中,不同的时间点来进行发送事件通知的。

9、实例化ApplicationArguments参数

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

10、创建ConfigurableEnvironment

ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);

内部

private ConfigurableEnvironment prepareEnvironment(            SpringApplicationRunListeners listeners,            ApplicationArguments applicationArguments) {        // Create and configure the environment        ConfigurableEnvironment environment = getOrCreateEnvironment();        configureEnvironment(environment, applicationArguments.getSourceArgs());        listeners.environmentPrepared(environment);        if (!this.webEnvironment) {            environment = new EnvironmentConverter(getClassLoader())                    .convertToStandardEnvironmentIfNecessary(environment);        }        return environment;    }
View Code

创建:ConfigurableEnvironment environment = getOrCreateEnvironment();

配置:configureEnvironment(environment, applicationArguments.getSourceArgs());

  主要是把run方法的参数配置到environment 

监听:listeners.environmentPrepared(environment);

  执行所有SpringApplicationRunListeners的所有environmentPrepared方法

非web环境转换

if (!this.webEnvironment) {            environment = new EnvironmentConverter(getClassLoader())                    .convertToStandardEnvironmentIfNecessary(environment);        }
View Code

11、打印Banner:Banner printedBanner = printBanner(environment);

12、创建ConfigurableApplicationContext:context = createApplicationContext();

protected ConfigurableApplicationContext createApplicationContext() {        Class
contextClass = this.applicationContextClass; if (contextClass == null) { try { contextClass = Class.forName(this.webEnvironment ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS); } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass); }
View Code

如果是WEB环境,实例化:org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext

否则实例化:org.springframework.context.annotation.AnnotationConfigApplicationContext

13、准备context:prepareContext(context, environment, listeners, applicationArguments,printedBanner);

内部

private void prepareContext(ConfigurableApplicationContext context,            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,            ApplicationArguments applicationArguments, Banner printedBanner) {        context.setEnvironment(environment);        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 sources = getSources();        Assert.notEmpty(sources, "Sources must not be empty");        load(context, sources.toArray(new Object[sources.size()]));        listeners.contextLoaded(context);    }
View Code

a、设置setEnvironment

b、后置调用:postProcessApplicationContext(context);

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {        if (this.beanNameGenerator != null) {            context.getBeanFactory().registerSingleton(                    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,                    this.beanNameGenerator);        }        if (this.resourceLoader != null) {            if (context instanceof GenericApplicationContext) {                ((GenericApplicationContext) context)                        .setResourceLoader(this.resourceLoader);            }            if (context instanceof DefaultResourceLoader) {                ((DefaultResourceLoader) context)                        .setClassLoader(this.resourceLoader.getClassLoader());            }        }    }
View Code

如果beanNameGenerator不为空,就把beanNameGenerator对象注入到context里面去,、

同样如果resourceLoader不为空,就设置:setResourceLoader、setClassLoader

c、回调所有的ApplicationContextInitializer:applyInitializers

@SuppressWarnings({ "rawtypes", "unchecked" })    protected void applyInitializers(ConfigurableApplicationContext context) {        for (ApplicationContextInitializer initializer : getInitializers()) {            Class
requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
View Code

d、执行所有SpringApplicationRunListeners的contextPrepared方法:listeners.contextPrepared(context);

e、日志输出

f、依次向Spring容器中注入springApplicationArguments、Banners对象

context.getBeanFactory().registerSingleton("springApplicationArguments",                applicationArguments);        if (printedBanner != null) {            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);        }
View Code

g、将所有的source加载到context中,类似于初始化一个AnnotationConfigApplicationContext然后将所有的容器注入

Set sources = getSources();        Assert.notEmpty(sources, "Sources must not be empty");        load(context, sources.toArray(new Object[sources.size()]));
View Code

h、执行所有SpringApplicationRunListeners的contextLoaded方法:listeners.contextLoaded(context);

14、执行refreshContext(context);方法,并且判断调用registerShutdownHook

private void refreshContext(ConfigurableApplicationContext context) {        refresh(context);        if (this.registerShutdownHook) {            try {                context.registerShutdownHook();            }            catch (AccessControlException ex) {                // Not allowed in some environments.            }        }    }
View Code

15、afterRefresh(context, applicationArguments);回调,获取容器中所有的ApplicationRunner、CommandLineRunner接口,然后排序,依次调用

protected void afterRefresh(ConfigurableApplicationContext context,            ApplicationArguments args) {        callRunners(context, args);    }    private void callRunners(ApplicationContext context, ApplicationArguments args) {        List runners = new ArrayList();        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());        AnnotationAwareOrderComparator.sort(runners);        for (Object runner : new LinkedHashSet(runners)) {            if (runner instanceof ApplicationRunner) {                callRunner((ApplicationRunner) runner, args);            }            if (runner instanceof CommandLineRunner) {                callRunner((CommandLineRunner) runner, args);            }        }    }    private void callRunner(ApplicationRunner runner, ApplicationArguments args) {        try {            (runner).run(args);        }        catch (Exception ex) {            throw new IllegalStateException("Failed to execute ApplicationRunner", ex);        }    }    private void callRunner(CommandLineRunner runner, ApplicationArguments args) {        try {            (runner).run(args.getSourceArgs());        }        catch (Exception ex) {            throw new IllegalStateException("Failed to execute CommandLineRunner", ex);        }    }
View Code

16、执行所有SpringApplicationRunListeners的finished方法:listeners.finished(context, null);;

17、结束,如果出现问题将使用日志handleRunFailure

 

转载地址:http://tfoda.baihongyu.com/

你可能感兴趣的文章
flask-uploads扩展的使用
查看>>
[ZJOI2014]力【FFT】
查看>>
SQL Server 无法连接到服务器。SQL Server 复制需要有实际的服务器名称才能连接到服务器。请指定实际的服务器名称。...
查看>>
[转] 前端性能的几个基础指标
查看>>
Eclipse 全屏插件
查看>>
Scrapy项目步骤
查看>>
python urlretrieve 下载图片
查看>>
基于springboot构建了一版本自动化测试框架,指定被测试环境,执行测试,支持配置化...
查看>>
聊聊dubbo的EagerThreadPool
查看>>
nginx 虚拟主机、反向代理服务器及负载均衡,多台主机分离php-fpm实验
查看>>
TiDB TechDay 巡讲启动!六城一起 High~
查看>>
利用Python进行两张图片比较
查看>>
jquery.autocomplete 模糊查询 支持分组
查看>>
找到系统盘被打满文件
查看>>
http接口测试工具,cookie自动追加
查看>>
基于OpenCv和swing的图片/视频展示Java实现
查看>>
阿里数据库内核月报:2017年03月
查看>>
SpringBoot系列——WebMvcConfigurer介绍
查看>>
monkey自动化测试(日志分析)
查看>>
sql server 2000,Log.LDF文件丢失,附加数据库失败的解决办法[转]
查看>>