2020-11-29springboot启动分析

一、springboot启动创建SpringApplication对象

1、启动SpringApplication,调用构造方法创建SpringApplication对象。在这里插入图片描述

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

2、运行到构造方法中,调用带参构造,此方法中又调用了另一个SpringApplication构造方法。

public SpringApplication(Class<?>... primarySources) {
        this((ResourceLoader)null, primarySources);
    }

3、在这个SpringApplication构造方法中,为对象进行初始化赋值。

 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        判断当前环境
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

3、在执行到this.webApplicationType = WebApplicationType.deduceFromClasspath();,对是不是web项目进行进行了判断,最后返回而得到项目环境。

 static WebApplicationType deduceFromClasspath() {
        if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
            return REACTIVE;
        } else {
            String[] var0 = SERVLET_INDICATOR_CLASSES;
            int var1 = var0.length;

            for(int var2 = 0; var2 < var1; ++var2) {
                String className = var0[var2];
                if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                    return NONE;
                }
            }

            return SERVLET;
        }
    }

4、随后调用setInitializers();保存得到各个配置类的初始化器ApplicationContextInitializer
(1)然而这个方法中又调用了getSpringFactoriesInstances()

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

(2)继续调用getSpringFactoriesInstances()

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return this.getSpringFactoriesInstances(type, new Class[0]);
    }

(3)通过SpringFactoriesLoader l调用其静态方法loadFactoryNames

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

(4)loadFactoryNames调用了loadSpringFactories,而在这个方法中,就得到了各个配置类的路径。即在"META-INF/spring.factories"路径下去寻找各个类的初始化器,最后封装后返回。

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

 private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

(5)随后getSpringFactoriesInstances就使用返回全类名进行初始化器对象创建。在createSpringFactoriesInstances中遍历这些类名,创建对象后封装到集合中返回。最后保存到SpringApplication对象中。

   List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);

5、随后,以同样的方式获取监听器ApplicationListener,保存到SpringApplication对象中

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

6、随后调用deduceMainApplicationClass(),在这方法中,获得栈运行轨迹,获得到方法名进行对比,从各个配置类找到main方法的主配置类。

private Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();
            StackTraceElement[] var2 = stackTrace;
            int var3 = stackTrace.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                StackTraceElement stackTraceElement = var2[var4];
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
            }

7、至此,SpringApplication对象创建完毕。

二、SpringApplication调用run()方法

run()代码如下,分析见后。

 public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(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, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

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

1、调用run方法,开启时间记录工具类StopWatch。并进行相关组件的准备工作。

  StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();

2、执行到SpringApplicationRunListeners listeners = this.getRunListeners(args);时,使用与获取ApplicationListener相同的方法和地址META-INF/spring.factories,去获取获取SpringApplicationRunListeners,紧接着开启这个监听器。

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

3、封装命令行参数

 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

4、准备项目启动的环境
准备环境的方法中,调用了getOrCreateEnvironment()方法,即获取或者创建环境。如果已经有相关环境就直接返回。如没有,就再创建一个环境,由于在创建SpringApplication对象时,对当前是否是web环境进行了判断,并存储了webApplicationType,此时就会在这个方法中进行对比,再返回相应的环境。返回后,就会调用SpringApplicationRunListener.environmentPrepared()方法,告知环境准备完成。

ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach((Environment)environment);
        listeners.environmentPrepared((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;
    }
private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        } else {
            switch(this.webApplicationType) {
            case SERVLET:
                return new StandardServletEnvironment();
            case REACTIVE:
                return new StandardReactiveWebEnvironment();
            default:
                return new StandardEnvironment();
            }

5、打印图案信息

 Banner printedBanner = this.printBanner(environment);

在这里插入图片描述
6、创建ioc容器ApplicationContext
通过环境信息,创建项目相应的环境的ioc容器。

context = this.createApplicationContext();
protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }

7、准备上下文执行环境

this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);

(1)首先是将environment保存到ioc中。并调用applyInitializers();方法,

 private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        this.postProcessApplicationContext(context);
        this.applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }
		…………
		listeners.contextLoaded(context);

(2)在applyInitializers();中获取到最开始存储在SpringApplication中的Initializer初始化器,并遍历,初始化容器。

protected void applyInitializers(ConfigurableApplicationContext context) {
        Iterator var2 = this.getInitializers().iterator();

        while(var2.hasNext()) {
            ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }

    }

(3)listeners.contextPrepared(context),通知上下准备完成
(4)prepareContext运行完成以后回调所有的SpringApplicationRunListenercontextLoaded(),加载容器。

8、刷新容器,ioc容器初始化,扫描,加载配置类,组件,自动配置到容器中。
部分执行代码如下:

 public void refresh() throws BeansException, IllegalStateException {
        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();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();

(1)postProcessBeanFactory扫描包和注解

  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.postProcessBeanFactory(beanFactory);
        if (this.basePackages != null && this.basePackages.length > 0) {
            this.scanner.scan(this.basePackages);
        }

        if (!this.annotatedClasses.isEmpty()) {
            this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
        }

(2)onRefresh,创建嵌入式Servlet

 protected void onRefresh() {
        super.onRefresh();

        try {
            this.createWebServer();
        } catch (Throwable var2) {
            throw new ApplicationContextException("Unable to start web server", var2);
        }
    }

 private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = this.getServletContext();
        if (webServer == null && servletContext == null) {
            StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
            ServletWebServerFactory factory = this.getWebServerFactory();
            createWebServer.tag("factory", factory.getClass().toString());
            this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
            createWebServer.end();
            this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));

(3)this.finishBeanFactoryInitialization(beanFactory);创建各个配置类的对象,组件。
(4)this.finishRefresh();ioc创建结束
9、 this.callRunners(context, applicationArguments);从ioc容器中获取所有的ApplicationRunnerCommandLineRunner进行回调,ApplicationRunner先回调,CommandLineRunner再回调,用于预先加载数据。

private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList();
        //获取ApplicationRunner并回调
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
         //获取ApplicationRunner并回调
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        AnnotationAwareOrderComparator.sort(runners);
        Iterator var4 = (new LinkedHashSet(runners)).iterator();

        while(var4.hasNext()) {
            Object runner = var4.next();
            if (runner instanceof ApplicationRunner) {
                this.callRunner((ApplicationRunner)runner, args);
            }

10、 整个SpringBoot应用启动完成以后返回启动的ioc容器;

  return context;

三、自定义监听机制
1、定义最先执行的ApplicationContextInitializer

public class MyApplictionContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("初始化执行了..................");
    }

2、第二执行的SpringApplicationRunListener

注意:此处必须要有一个带参构造,否则会出现NoSuchClassException。

public class MyApplicationRunListener implements SpringApplicationRunListener {


    public MyApplicationRunListener(SpringApplication application, String[] args) {

    }
    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("开始了.........");
    }
    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("环境准备好了.........");
    }
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("上下文准备好了.........");
    }
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("上下文加载了.........");
    }
    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("???.........");
    }
    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("~~~~!!!.........");
    }
    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("出错了.........");
    }
}

3、在META-INF/spring.factories中配置上述类
在这里插入图片描述

# Application Listeners
org.springframework.boot.SpringApplicationRunListener=\
com.example.springbootlistener.runner.MyApplicationRunListener

# Auto Configuration Import Listeners
org.springframework.context.ApplicationContextInitializer=\
com.example.springbootlistener.runner.MyApplictionContextInitializer

4、第三执行ApplicationRunner

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner运行了");
    }
}

4、最后执行CommandlineRunner

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner启动了.........");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值