Spring Boot:启动运行

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

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);
}

Spring Boot主程序main方法只做了两件事

一、创建SpringApplication实体类对象

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


public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {

    //resourceLoader = null
    //primarySources = DemoApplication.class
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

    /**
     * WebApplicationType.deduceFromClasspath()就是根据各种条件判断确定当前服务器类型
     * 该方法主要调用以下方法进行判断
     * ClassUtils.isPresent(String className, @Nullable ClassLoader classLoader)
     * className      全类名
     * classLoader    类加载器
     * 判断能否从classLoader(类加载器)中获取与className(全类名)相对应的Class类
     * (方法内部判断不止一个判断,但大致是这个意思,有兴趣可以自己研究)
     */
    this.webApplicationType = WebApplicationType.deduceFromClasspath();

    /**
     * 调用了两个方法
     * 1. getSpringFactoriesInstances(ApplicationContextInitializer.class)
     * 这个方法很重要,在下面有单独说明,看完再继续
     * 从所有META-INF/spring.factories文件中获取与ApplicationContextInitializer.class全类名相同Key的对应Value值的实体类对象
     * 
     * 2. setInitializers
     * 为this.initializers初始化并赋值
     */
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    /**
     * 和上面方法是一样的
     */
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

    /**
     * 保存main(Spring Boot主程序)所在类的Class对象
     */
    this.mainApplicationClass = deduceMainApplicationClass();
}





1.  getSpringFactoriesInstances

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) {

    /**
     * getClassLoader()返回本地类加载器,如果为空返回默认类加载器(默认返回的是线程上下文类加载器)
     */
    ClassLoader classLoader = getClassLoader();

    /**
     * SpringFactoriesLoader.loadFactoryNames(type, classLoader)
     * 这个方法很重要,在下面有单独说明,看完再继续
     */
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));

    /**
     * createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names)
     * 这个方法就是根据names(全类名)和classLoader(类加载器)来获取names对应的实例,反射机制
     */
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);

    /**
     * 返回获取到的实体类集合
     * 
     * 总结:
     * 这个方法就是从所有的META-INF/spring.factories文件中获取所传参type的全类名对应的Value,
     * 并把获取到的Value根据反射机制实体化,最后把实体化的对象集合返回
     */
    return instances;
}

2.  loadFactoryNames

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {

    /**
     * 获取Class对象的全类名
     */
    String factoryClassName = factoryClass.getName();
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {

    /**
     * 从cache中获取classLoader相对就的value值
     */
    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 properties = PropertiesLoaderUtils.loadProperties(resource);

                /**
                 * 获取配置数据的迭代器
                 */
                Iterator var6 = properties.entrySet().iterator();

                while(var6.hasNext()) {
                    /**
                     * 获取到一份配置数据的Key-Value键值对
                     */
                    Entry<?, ?> entry = (Entry)var6.next();
                    String factoryClassName = ((String)entry.getKey()).trim();
                    String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                    int var10 = var9.length;

                    /**
                     * Value默认是数组形式,遍历
                     */
                    for(int var11 = 0; var11 < var10; ++var11) {
                        String factoryName = var9[var11];

                        /**
                         * 这个添加方法其实是把数据添加到了该实体类的Map<K, List<V>>类型的成员变量中
                         */
                        result.add(factoryClassName, factoryName.trim());
                    }
                }
            }


            /**
             * 所有META-INF/spring.factories配置文件下的数据都被保存起来
             */
            cache.put(classLoader, result);
            
            /**
             * 返回获取到的LinkedMultiValueMap数据(就是数据集,内部封装了Map,Value值是List集合)
             * 
             * 总结:
             * 这个方法就是使用类加载器获取所有META-INF/spring.factories文件地址,并把所有文件以Key-Value的形式进行解析
             * 最后保存解析出来的数据并返回
             */
            return result;
        } catch (IOException var13) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
        }
    }
}

二、调用run方法

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

    /**
     * getRunListeners(args)方法内主要调用了getSpringFactoriesInstances方法,并用返回参数创建SpringApplicationRunListeners
     * getSpringFactoriesInstances上面说过,跳过
     */
    SpringApplicationRunListeners listeners = getRunListeners(args);

    /**
     * 使listeners对象变量this.listeners中的每个对象调用starting()方法(就是启动并初始化对象)
     */
    listeners.starting();
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

        /**
         * 配置环境并回调environmentPrepared方法
         */
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        configureIgnoreBeanInfo(environment);
        Banner printedBanner = printBanner(environment);

        /**
         * 创建IOC容器
         */
        context = createApplicationContext();

        /**
         * getSpringFactoriesInstances这个方法上面说过,略
         */
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);

        /**
         * 准备上下文,这个方法很重要下面单独说明
         */
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);

        /**
         * IOC容器初始化,加载IOC容器中所有组件
         */
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }

        /**
         * 所有SpringApplicationRunListener回调started方法
         */
        listeners.started(context);

        /**
         * 从容器中获取所有的ApplicationRunner和CommandLineRunner对象并回调run方法
         */
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {

        /**
         * 所有SpringApplicationRunListener对象回调running方法
         */
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

1.  prepareContext

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {

    /**
     * 为IOC容器设置环境
     */
    context.setEnvironment(environment);

    /**
     * IOC容器后置处理,根据需要设置其它处理
     */
    postProcessApplicationContext(context);

    /**
     * 所有ApplicationContextInitializer对象回调initialize方法
     */
    applyInitializers(context);

    /**
     * 所有SpringApplicationRunListener对象回调contextPrepared方法
     */
    listeners.contextPrepared(context);

    /**
     * 日志记录相关设置
     */
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }

    /**
     * 获取Bean工厂并根据条件添加组件
     */
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        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");
    
    /**
     * 将bean加载到应用程序上下文中
     */
    load(context, sources.toArray(new Object[0]));
    
    /**
     * 所有SpringApplicationRunListener对象回调contextLoaded方法
     */
    listeners.contextLoaded(context);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值