SpringBoot启动原理

# SpringBoot启动原理 #
1.创建SpringBoot时默认生成一个启动类

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

2.启动时调用SpringApplication的run方法

    public static ConfigurableApplicationContext run(Class<?> primarySource,
            String... args) {
        //调用SpringApplication类中的重载run方法
        return run(new Class<?>[] { primarySource }, args);
    }

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

3.此时调用两个方法:先创建一个SpringApplication对象,运行run方法

    //创建SpringApplication对象,参数为Class<?>[SpringBootWebApplication.class]
    new SpringApplication(primarySources);
    //运行run方法
    run(args);

4.创建SpringApplication对象时执行下面代码

    public SpringApplication(Class<?>... primarySources) {
        //调用重载构造方法
        this(null, primarySources);
    }

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        //resourceLoader为null
        this.resourceLoader = resourceLoader;

        //primarySources为Class<?>[SpringBootWebApplication.class]
        Assert.notNull(primarySources, "PrimarySources must not be null");

        //此时primarySources由数组变为LinkedHashSet集合
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

        //4.1判断应用类型
        this.webApplicationType = WebApplicationType.deduceFromClasspath();

        //4.2从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));

        //4.3从类路径下找到ETA‐INF/spring.factories配置的所有ApplicationListener
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        //4.4从多个配置类中找到有main方法的主配置类
        this.mainApplicationClass = deduceMainApplicationClass();
    }

4.1.调用WebApplicationType.deduceFromClasspath()方法判断应用类型

    //判断当前应用是普通web应用、响应式web应用还是非web应用
    static WebApplicationType deduceFromClasspath() {
        //isPresent方法判断所提供的类名的类是否存在,且可以被加载
        if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
            //应用是响应式web应用
            return WebApplicationType.REACTIVE;
        }
        for (String className : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                //非web应用
                return WebApplicationType.NONE;
            }
        }
        //普通web应用
        return WebApplicationType.SERVLET;
    }

4.2.从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来

    setInitializers(
        //4.2.1获取Spring工厂实例
        (Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));

4.2.1.获取Spring工厂实例

    getSpringFactoriesInstances(
                ApplicationContextInitializer.class)
    
    //此处type参数为ApplicationContextInitializer.class
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        //调用重载方法
        return getSpringFactoriesInstances(type, new Class<?>[] {});
    }

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        //获取类加载器
        ClassLoader classLoader = getClassLoader();
        //4.2.1.1使用LinkedHashSet存放加载的工厂名称防止重复
        Set<String> names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        //4.2.1.2创建Spring工厂实例
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);
        //对实例进行排序
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

4.2.1.1使用LinkedHashSet存放加载的工厂名称防止重复

    Set<String> names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));

    //加载工厂名称,此处factoryClass参数为ApplicationContextInitializer.class
    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        //此时factoryClassName为org.springframework.context.ApplicationContextInitializer
        String factoryClassName = factoryClass.getName();

        //加载Spring工厂,并从中获取key为org.springframework.context.ApplicationContextInitializer的value.此时值为:
        //org.springframework.context.ApplicationContextInitializer=\
        //org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
        //org.springframework.boot.context.ContextIdApplicationContextInitializer,\
        //org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
        //org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
        return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    //加载Spring工厂
    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        //第一次调用该方法,此时cache只是一个空集合
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }

        try {
            //加载所有的/META-INF/spring.factories文件
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                
                //将spring.factories文件转为properties文件
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryClassName = ((String) entry.getKey()).trim();
                    for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        result.add(factoryClassName, factoryName.trim());
                    }
                }
            }

            //将所有的spring.factories文件中的数据存入cache中
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }

4.2.1.2创建Spring工厂实例
    
    //创建Spring工厂实例
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);

    //遍历传入的names,对其进行实例化,放入instances中返回
    private <T> List<T> createSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
            Set<String> names) {
        List<T> instances = new ArrayList<>(names.size());
        for (String name : names) {
            try {
                //根据name和classLoader获取Class对象
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);

                //获取指定参数类型的所有构造器,包括public的和非public的
                Constructor<?> constructor = instanceClass
                        .getDeclaredConstructor(parameterTypes);

                //创建实例化对象
                T instance = (T) BeanUtils.instantiateClass(constructor, args);
                
                //加如instances中
                instances.add(instance);
            }
            catch (Throwable ex) {
                throw new IllegalArgumentException(
                        "Cannot instantiate " + type + " : " + name, ex);
            }
        }
        return instances;
    }
4.3从类路径下找到ETA‐INF/spring.factories配置的所有ApplicationListener和4.2流程类似

5.运行run方法

    /**
     * 运行spring应用,创建并刷新新的spring容器
     */
    public ConfigurableApplicationContext run(String... args) {
        //首先创建开始停止的监听
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        //与awt应用有关的配置
        configureHeadlessProperty();
        //5.1从类路径下找到META‐INF/spring.factories获取SpringApplicationRunListeners
        SpringApplicationRunListeners listeners = getRunListeners(args);
        //回调所有的SpringApplicationRunListeners的starting方法
        listeners.starting();
        try {
            //封装命令行参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            //5.2准备环境
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);
            //打印banner图标
            Banner printedBanner = printBanner(environment);
            //创建ioc容器,根据环境不同创建不同的ioc容器
            context = createApplicationContext();
            //出现异常用来查看异常报告
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            //5.3准备上下文环境
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            //5.4刷新容器,ioc容器初始化流程
            refreshContext(context);
            //5.5从ioc容器中获取ApplicationRunner和CommandLineRunner并进行回调
            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);
        }
        //springboot启动完成返回ioic容器
        return context;
    }

5.2准备环境

    private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // 获取或创建环境
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        //配置环境
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        //回调所有的SpringApplicationRunListeners的environmentPrepared方法,表示环境准备完成
        listeners.environmentPrepared(environment);
        //将环境绑定到spring应用中
        bindToSpringApplication(environment);
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader())
                    .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
    }

5.3准备上下文环境

    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        //设置环境到ioc容器中
        context.setEnvironment(environment);
        //使用后置处理器给ioc容器注册bean
        postProcessApplicationContext(context);
        //回调4.2步骤中获取的所有ApplicationContextInitializer的initialize方法
        applyInitializers(context);
        //回调5.1步骤中获取的所有SpringApplicationRunListener的contextPrepared方法
        listeners.contextPrepared(context);
        //记录日志
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // 注册命令行参数
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            //将banner注册进来
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // 获取主类
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[0]));
        //回调5.1步骤中获取的所有SpringApplicationRunListener的contextLoaded方法
        listeners.contextLoaded(context);
    }

5.5从ioc容器中获取ApplicationRunner和CommandLineRunner并进行回调,其中ApplicationRunner优先级高于CommandLineRunner

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

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> 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);
            }
        }
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值