SpringBoot启动流程2.4.5

SpringBoot启动类 2.4.5

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

启动类的代码非常简单,我们只需要在SpringBoot项目启动类加上注解@SpringBootApplication,即可标注该类是启动类。在该类的main方法中调用了

SpringApplication.run(Application.class),所以启动流程就在run中。通过debug,我们看一下源码。

//1、main方法进来之后,调用了这个run方法,然后这个run又封装了一下参数,调用另一个重载方法run
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class[]{primarySource}, args);
}
//2、该run方法,首先新创建一个SpringApplication,该类构造器接受一个启动类参数对象,在构造器中,SpringBoot进行了一系列参数初始化。
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return (new SpringApplication(primarySources)).run(args);
}

SpringApplication构造器,初始化

//3、run方法创建新的SpringApplication对象,调用该构造器,该构造器又调用另一个构造器
public SpringApplication(Class<?>... primarySources) {
    //默认资源加载器ResourceLoader为null
    this((ResourceLoader)null, primarySources);
}
//4、初始化,后期版本将这些直接赋值的成员变量变为静态成员变量,直接赋值了,因此重点是下面的getxxxx方法。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.sources = new LinkedHashSet();		//配置sources
    this.bannerMode = Mode.CONSOLE;		//配置横幅,默认打印到控制台。Mode枚举 OFF关闭,CONSOLE控制台打印,LOG日志打印;
    this.logStartupInfo = true;		//配置是否开启日志,默认开启
    this.addCommandLineProperties = true;		//配置是否添加命令行属性,默认开启
    this.addConversionService = true;		//是否添加转换服务,默认开启
    this.headless = true;		//headless模式
    this.registerShutdownHook = true;
    this.additionalProfiles = Collections.emptySet();
    this.isCustomEnvironment = false;
    this.lazyInitialization = false;
    this.applicationContextFactory = ApplicationContextFactory.DEFAULT;		
    this.applicationStartup = ApplicationStartup.DEFAULT;		//DefaultApplicationStartup
    this.resourceLoader = resourceLoader;		//null
    Assert.notNull(primarySources, "PrimarySources must not be null");		//如果没有启动类,启动失败。primarySources一般只有一个启动类,或者null
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));		//保存主配置类
    this.webApplicationType = WebApplicationType.deduceFromClasspath();		//判断web类型,SERVLET
    this.bootstrapRegistryInitializers = this.getBootstrapRegistryInitializersFromSpringFactories();		//获取所有的BootstrapRegistryInitializer实现类保存在List<BootstrapRegistryInitializer> bootstrapRegistryInitializers,锚点1
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));	//从资源文件配置ApplicationContextInitializer实例并存在List<ApplicationContextInitializer<?>> initializers;锚点2
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));		//从资源文件创建应用监听器,保存在List<ApplicationListener<?>> listeners
    this.mainApplicationClass = this.deduceMainApplicationClass();		//配置应用的主方法所在类
}
锚点1

SpringBoot启动时初始化上下文时,最终会调用该方法。再改方法中获取classLoader,因为构造器中resourceLoader是null,所以得到的是默认构造器

然后执行该方法SpringFactoriesLoader.loadFactoryNames(type, classLoader),锚点1之后的流程如下。

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 = this.getClassLoader();		//return this.resourceLoader != null ? this.resourceLoader.getClassLoader() : 		ClassUtils.getDefaultClassLoader();返回系统默认类加载器
    Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

然后进入SpringFactoriesLoader.loadFactoryNames(type, classLoader)。

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    ClassLoader classLoaderToUse = classLoader;		//默认加载器
    if (classLoader == null) {
        classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
    }

    String factoryTypeName = factoryType.getName();		//锚点1处是BootstrapRegistryInitializer.class类的全类名
    return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

获得全类名之后,进入loadSpringFactories(classLoaderToUse)方法,并得到一个Map类。该方法会从"META-INF/spring.factories"下的文件中读取配置。SpringBoot中只有如图三个路径下存在"META-INF/spring.factories"。我们以锚点1的BootstrapRegistryInitializer为例。
在这里插入图片描述

urls中存在3个地址,分别在spring-boot,spring-boot-autoconfigure,spring-beans中。循环将对应地址的文件读入为properties,内容如下图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K80fO7nl-1653270010887)(SpringBoot启动流程---SpringApplication类\2.png)]

如果缓存没有,则读取配置文件,获得Enumeration类型的urls,Enumeration的key是HashTable并且对应的值也存于HashTable中。因此该类将配置文件中的内容做映射。之后通过迭代,获得每一个key和对应的values。

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    //先从缓存获取,如果有就直接返回
    Map<String, List<String>> result = (Map)cache.get(classLoader);
    if (result != null) {
        return result;
    } else {
        HashMap result = new HashMap();

        try {
            //没有则从"META-INF/spring.factories"文件中读取,获取"META-INF/spring.factories"的url
            Enumeration urls = classLoader.getResources("META-INF/spring.factories");
			//遍历url
            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();		
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);		//从url中读入数据
                Iterator var6 = properties.entrySet().iterator();		//获得迭代器
				//迭代
                while(var6.hasNext()) {
                    Entry<?, ?> entry = (Entry)var6.next();		//String,String
                    String factoryTypeName = ((String)entry.getKey()).trim();		//去掉key字符串开头和结尾的空白
                    //value转为数组
                    String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());		//将value字符转为数组
                    String[] var10 = factoryImplementationNames;
                    int var11 = factoryImplementationNames.length;
					
                    
                    for(int var12 = 0; var12 < var11; ++var12) {
                        String factoryImplementationName = var10[var12];		
                        ((List)result.computeIfAbsent(factoryTypeName, (key) -> {		//第一次会返回空数组,并将第一个元素去掉开头和结尾的空白并添加到数组,之后都获取该数组并向其中添加元素。
                            return new ArrayList();
                        })).add(factoryImplementationName.trim());
                    }
                }
            }
			
            //最后将map中所有key对应的value去重后更新
            result.replaceAll((factoryType, implementations) -> {
                return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
            });
            cache.put(classLoader, result);		//放入缓存
            return result;		//返回map
        } catch (IOException var14) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
        }
    }
}

返回之后,会通过getOrDefault方法返回BootstrapRegistryInitializer.class对应的配置集合。然后执行List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);

该方法通过反射,用names中的全部类的全类名创建实例对象集合,然后排序之后返回。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AYnukl7C-1653270010888)(SpringBoot启动流程---SpringApplication类\3.png)]

返回之后,保存到SpringApplication对象的属性中。

锚点2

初始化BootstrapRegistryInitializer.class之后,会初始化ApplicationContextInitializer和ApplicationListener监听器相关的类。过程同锚点1一样。只不过在loadSpringFactories方法中,会直接返回缓存中的map并返回对应的list。

Run具体启动

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();		//计时
    stopWatch.start();
    DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
    ConfigurableApplicationContext context = null;
    this.configureHeadlessProperty();
    //创建并启动监听器
    SpringApplicationRunListeners listeners = this.getRunListeners(args);		//锚点3,获取监听器
    listeners.starting(bootstrapContext, this.mainApplicationClass);		//锚点4,启动监听器

    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);	//锚点7,准备环境
        this.configureIgnoreBeanInfo(environment);
        Banner printedBanner = this.printBanner(environment);		//根据配置打印banner
        //创建ioc
        context = this.createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        this.refreshContext(context);
        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);
    }
}
锚点3

SpringApplicationRunListeners listeners = this.getRunListeners(args);这个方法比较重要,目的是获取一个封装的SpringApplicationRunListeners对象。该类中一个属性List listeners中最后会有一个元素EventPublishingRunListener。

下面,通过断点,我们看一下封装过程。

可以看到getRunListeners直接new了一个SpringApplicationRunListeners。之后我们看该构造函数,现在我们先看参数this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)最后会是什么。

private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
}

这个方法,我们在之前SpringApplication构造其中,就见过多次。它从一个map中获取对应的List集合。我们进去看一下,果然,一样的配方。最后names只有一个元素,就是EventPublishingRunListener类的全限定类名。之后又调用了List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);这行代码进行反射获取实例。最后代码会运行到EventPublishingRunListener的构造器处。我们往下看。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7QSOznUp-1653270010888)(SpringBoot启动流程---SpringApplication类\5.png)]

标注的这一行,将过去的构造函数和参数传入,反射创建对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hrrOXq0w-1653270010889)(SpringBoot启动流程---SpringApplication类\6.png)]

ctor就是上一步的传入的构造函数,这里直接传入参数开始构建。参数中包含的就是之前new的并且初始化的SpringApplication对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hvcAEPdd-1653270010889)(SpringBoot启动流程---SpringApplication类\7.png)]

调用EventPublishingRunListener构造器创建对象。该类有三个参数,application是通过参数传递的,用来获取初始化时创建的监听器对象集合,并获取迭代器var3。然后将监听器封装到initialMulticaster属性中。initialMulticaster的类型是 public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster,它的父类中,有一个内部类,该内部类中有一个集合,最终这些listener会存到该集合中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dxN5zAZE-1653270010890)(SpringBoot启动流程---SpringApplication类\8.png)]

内部类部分代码

public void addApplicationListener(ApplicationListener<?> listener) {
        synchronized(this.defaultRetriever) {
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }

            this.defaultRetriever.applicationListeners.add(listener);
            this.retrieverCache.clear();
        }
}
//内部类
private class DefaultListenerRetriever {
        public final Set<ApplicationListener<?>> applicationListeners;		//最终存放监听器处
        public final Set<String> applicationListenerBeans;

        private DefaultListenerRetriever() {
            this.applicationListeners = new LinkedHashSet();
            this.applicationListenerBeans = new LinkedHashSet();
        }
}

因为初始化一共有9个监听器,所以最终这个集合里面会添加9个监听器。如下图,返回的参数就是instances,里面封装了一个EventPublishingRunListener,EventPublishingRunListener里面有个属性initialMulticaster,里面又封装了一个包含9个监听器的集合。封装套娃。。。。最后通过SpringApplicationRunListeners构造函数,赋值给listeners。最后返回生成的SpringApplicationRunListeners对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9brKmzQS-1653270010890)(SpringBoot启动流程---SpringApplication类\9.png)]

到此为止,锚点3结束。如果套的头晕,建议多看几遍就好了。

锚点4

获得监听器之后,启动监听器。这个方法最后调用了doWithListeners方法。我们可以看到里面将linsteners中的监听器(其实就是EventPublishingRunListener)分别执行lambda中listener.starting(bootstrapContext),所以我们去EventPublishingRunListener中找对应的方法。

void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
        this.doWithListeners("spring.boot.application.starting", (listener) -> {
            listener.starting(bootstrapContext);
        }, (step) -> {
            if (mainApplicationClass != null) {
                step.tag("mainApplicationClass", mainApplicationClass.getName());
            }

        });
}

 private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction, Consumer<StartupStep> stepAction) {
        StartupStep step = this.applicationStartup.start(stepName);
        this.listeners.forEach(listenerAction);
        if (stepAction != null) {
            stepAction.accept(step);
        }

        step.end();
}

调用该方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NeXYo18k-1653270010891)(SpringBoot启动流程---SpringApplication类\10.png)]

然后来到SimpleApplicationEventMulticaster,最终调用的是下面这个方法。该方法中,重要的是Iterator var5 = this.getApplicationListeners(event, type).iterator();获取符合eventType的监听器的迭代器。我们进入看下。

public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        Executor executor = this.getTaskExecutor();		//null
    
    	
        Iterator var5 = this.getApplicationListeners(event, type).iterator();	//锚点5
		
    
    	//从锚点6回来,遍历符合条件的监听器,并执行
        while(var5.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var5.next();
            if (executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                //执行
                this.invokeListener(listener, event);
            }
        }

    }

this.invokeListener(listener, event)最后会执行到这里,根据监听器执行不同的逻辑。

锚点5
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
        Object source = event.getSource();		//初始化创建的SpringApplication对象
        Class<?> sourceType = source != null ? source.getClass() : null;		//SpringApplication的全限定类名
        AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);		//将eventType和sourceType封装一个key,后面获取 existingRetriever
        AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null;
        AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey);		//因为开始缓存没有,所以是null,所以进入下边的if
        if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
            //因为第一次retrieverCache缓存没有,所以new了一个newRetriever,然后放入缓存,cacheKey作为key,newRetriever作为值
            newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever();
            //因为不存在,所以newRetriever被放入,返回null,所以existingRetriever是null
            existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
            if (existingRetriever != null) {
                newRetriever = null;
            }
        }
		//existingRetriever==null,不会执行
        if (existingRetriever != null) {
            Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();		//符合条件的监听器集合,分析见锚点6
            if (result != null) {
                return result;
            }
        }
		//这一步筛选符合条件的监听器并返回。锚点6
        return this.retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
锚点6

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XMzZgJIX-1653270010892)(SpringBoot启动流程---SpringApplication类\11.png)]

private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) {
        List<ApplicationListener<?>> allListeners = new ArrayList();
        Set<ApplicationListener<?>> filteredListeners = retriever != null ? new LinkedHashSet() : null;
        Set<String> filteredListenerBeans = retriever != null ? new LinkedHashSet() : null;
        LinkedHashSet listeners;
        LinkedHashSet listenerBeans;
    
        synchronized(this.defaultRetriever) {
            //我们 锚点3分析过,this.defaultRetriever.applicationListeners存放的是加载classpath路径下的9个监听器
            //这里加锁,为了防止在执行这一步的同时值被其他线程修改
            listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
            listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
        }
		
        Iterator var9 = listeners.iterator();
		
        while(var9.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var9.next();
            //通过方法名字,我们可以推测,如果listener符合eventType和sourceType,那么返回true,最终有4个监听器满足
            if (this.supportsEvent(listener, eventType, sourceType)) {
                if (retriever != null) {
                    //第一次加入filteredListeners
                    filteredListeners.add(listener);
                }
				//符合条件加入filteredListeners
                allListeners.add(listener);
            }
        }
		//listenerBeans大小为0,不会执行
        if (!listenerBeans.isEmpty()) {
            ConfigurableBeanFactory beanFactory = this.getBeanFactory();
            Iterator var16 = listenerBeans.iterator();

            while(var16.hasNext()) {
                String listenerBeanName = (String)var16.next();

                try {
                    if (this.supportsEvent(beanFactory, listenerBeanName, eventType)) {
                        ApplicationListener<?> listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                        if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) {
                            if (retriever != null) {
                                if (beanFactory.isSingleton(listenerBeanName)) {
                                    filteredListeners.add(listener);
                                } else {
                                    filteredListenerBeans.add(listenerBeanName);
                                }
                            }

                            allListeners.add(listener);
                        }
                    } else {
                        Object listener = beanFactory.getSingleton(listenerBeanName);
                        if (retriever != null) {
                            filteredListeners.remove(listener);
                        }

                        allListeners.remove(listener);
                    }
                } catch (NoSuchBeanDefinitionException var13) {
                }
            }
        }
		
        AnnotationAwareOrderComparator.sort(allListeners);
    	//将过滤的结果存入缓存,下次通过cacheKey直接获取
        if (retriever != null) {
            if (filteredListenerBeans.isEmpty()) {
                retriever.applicationListeners = new LinkedHashSet(allListeners);
                retriever.applicationListenerBeans = filteredListenerBeans;
            } else {
                retriever.applicationListeners = filteredListeners;
                retriever.applicationListenerBeans = filteredListenerBeans;
            }
        }
		
        return allListeners;		//锚点6结束,回到锚点4
}
锚点7
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
    ConfigurableEnvironment environment = this.getOrCreateEnvironment();		//获取系统配置信息,以及控制台配置
    this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach((Environment)environment);
    listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);		//处理环境准备完成相关的监听器,过程参考锚点3到锚点6,不同的是type,因此广播的监听器不同。
    DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
    this.configureAdditionalProfiles((ConfigurableEnvironment)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;
}

我们进入getOrCreateEnvironment方法,因为开始的时候环境是空,所以这里会创建StandardServletEnvironment(),里面进去这里会先调用父类的构造器,StandardEnvironment,AbstractEnvironment。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-29Mew8ws-1653270010892)(SpringBoot启动流程---SpringApplication类\12.png)]

所以最终调用的是AbstractEnvironment的构造器,具体逻辑也是在这里执行的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iH5CVVj9-1653270010893)(SpringBoot启动流程---SpringApplication类\13.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1oaVckuW-1653270010893)(SpringBoot启动流程---SpringApplication类\14.png)]

这段逻辑里面,进行了一些初始值的设置,然后再最后一行代码进行了重要的操作。最后一行代码执行的不是该类的方法,而是StandardServletEnvironment类的重写方法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WtPHaYnr-1653270010894)(SpringBoot启动流程---SpringApplication类\22.png)]

StandardServletEnvironment执行该方法后,又调用父类StandardEnvironment的重写方法。

这里进行了一些初值的设置。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EnX6Ttsy-1653270010894)(SpringBoot启动流程---SpringApplication类\15.png)]

重点在父类中。getSystemProperties方法中,会调用System.getProperties(),从这个方法里面就可以获取计算机系统的属性。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0GN8cl1F-1653270010895)(SpringBoot启动流程---SpringApplication类\16.png)]

接下来会执行这一句。具体作用就如同注释一样。因为到这里环境准备的差不多了,所以就要处理环境准备之后的一些监听器。因此eventType类型是ApplicationEnvironmentPreparedEvent,找到之后进行广播。

在这里插入图片描述

锚点8

web项目,会创建一个AnnotationConfigServletWebServerApplicationContext()类。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j7eCxcQY-1653270010896)(SpringBoot启动流程---SpringApplication类\18.png)]

之后创建启动器,在准备需要创建的beans。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JrxRCV4f-1653270010896)(SpringBoot启动流程---SpringApplication类\19.png)]

prepareContext中会调用下面这个方法。可以看到,这里将this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class))这个地方从配置中读到的初始化相关类进行遍历,并且初始化。初始化前会进行断言,如果不能初始化则抛出异常。

之后会执行相应的监听器。并且会注册单例对象的类名。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KpEUl3P4-1653270010896)(SpringBoot启动流程---SpringApplication类\20.png)]

prepareContext执行完毕之后,会调用refreshContext方法,该方法会将容器的对象刷新激活,之后处理刷新之后的操作。

在激活对象的时候,我们深入会发现,在refresh方法中,会调用onRefresh方法。在这个地方会启动tomcat。启动tomcat之后还会加载一些其他bean。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I77HKx8J-1653270010897)(SpringBoot启动流程---SpringApplication类\21.png)]

到此,springboot启动完毕。
下边的容器相关的代码,没看十分明白,希望大家指导交流,然后我继续完善。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值