springboot源码解析 - 构建SpringApplication

简介: 1 package com.microservice.framework; 2 3 import org.springframework.boot.SpringApplication; 4 import org.
复制代码
 1 package com.microservice.framework;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 
 6 @SpringBootApplication
 7 public class MySpringAplication {
 8 
 9     public void run(String[] args) {
10         SpringApplication sa = new SpringApplication(MySpringAplication.class);
11         sa.run(args);
12     }
13 
14 }
复制代码

SpringBoot启动过程:

1、构建SpringApplication对象

2、执行run()

一、构建SpringApplication对象

1     /**
2      * The application context will load beans from the specified sources 
3      */
4     public SpringApplication(Object... sources) {
5         initialize(sources);
6     }

说明:

  • 实例化该类的时候会加载bean到applicationContext中去
  • 这里的入参是MySpringApplication.class这样一个Class<com.microservice.framework.MySpringApplication>对象
复制代码
    private final Set<Object> sources = new LinkedHashSet<Object>();
    private boolean webEnvironment;
    private Class<?> mainApplicationClass;

    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();
    }
复制代码

步骤:

  • 将传入的MySpringApplication.class对象放入Set集合
  • 判断是否是web环境
  • 创建ApplicationInitializer列表
  • 初始化ApplicationListener列表
  • 初始化主类mainApplicationClass

1.1、将传入的MySpringApplication.class对象放入Set集合

1.2、判断是否是web环境:

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

    private boolean deduceWebEnvironment() {
        for (String className : WEB_ENVIRONMENT_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return false;
            }
        }
        return true;
    }
复制代码

说明:通过在classpath中查看是否存在WEB_ENVIRONMENT_CLASSES这个数组中所包含的所有类(实际上就是2个类),如果存在那么当前程序即是一个Web应用程序,反之则不然。

1.3、创建ApplicationContextInitializer列表

复制代码
 1     private List<ApplicationContextInitializer<?>> initializers;
 2 
 3     public void setInitializers(
 4             Collection<? extends ApplicationContextInitializer<?>> initializers) {
 5         this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
 6         this.initializers.addAll(initializers);
 7     }
 8 
 9     private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
10         return getSpringFactoriesInstances(type, new Class<?>[] {});
11     }
12 
13     private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
14             Class<?>[] parameterTypes, Object... args) {
15         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
16 
17         // Use names and ensure unique to protect against duplicates
18         Set<String> names = new LinkedHashSet<String>(
19                 SpringFactoriesLoader.loadFactoryNames(type, classLoader));
20         List<T> instances = new ArrayList<T>(names.size());
21 
22         // Create instances from the names
23         for (String name : names) {
24             try {
25                 Class<?> instanceClass = ClassUtils.forName(name, classLoader);
26                 Assert.isAssignable(type, instanceClass);
27                 Constructor<?> constructor = instanceClass.getConstructor(parameterTypes);
28                 T instance = (T) constructor.newInstance(args);
29                 instances.add(instance);
30             }
31             catch (Throwable ex) {
32                 throw new IllegalArgumentException(
33                         "Cannot instantiate " + type + " : " + name, ex);
34             }
35         }
36 
37         AnnotationAwareOrderComparator.sort(instances);
38         return instances;
39     }
复制代码

步骤:

  • 调用SpringFactoriesLoader.loadFactoryNames(type, classLoader)来获取所有Spring Factories的名字,(这里是获取了四个ApplicationContextInitializer实现类的全类名,见下边)
  • 为每一个Spring Factories根据读取到的名字创建其对象。(这里创建了4个对象)
  • 将创建好的对象列表排序并返回。

其中,SpringFactoriesLoader.loadFactoryNames(type, classLoader)如下:

复制代码
 1     /**
 2      * The location to look for factories.
 3      * <p>Can be present in multiple JAR files.
 4      */
 5     public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
 6 
 7     /**
 8      * Load the fully qualified class names of factory implementations of the
 9      * given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
10      * class loader.
11      */
12     public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
13         String factoryClassName = factoryClass.getName();
14         try {
15             Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
16                     ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
17             List<String> result = new ArrayList<String>();
18             while (urls.hasMoreElements()) {
19                 URL url = urls.nextElement();
20                 Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
21                 String factoryClassNames = properties.getProperty(factoryClassName);
22                 result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
23             }
24             return result;
25         }
26         catch (IOException ex) {
27             throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
28                     "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
29         }
30     }
复制代码

META-INF/spring-factories

1 # Application Context Initializers
2 org.springframework.context.ApplicationContextInitializer=\
3 org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
4 org.springframework.boot.context.ContextIdApplicationContextInitializer,\
5 org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
6 org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer

说明:

  • 从所有jar获取所有的META-INF/spring-factories文件。(这里只有spring-boot-1.3.0.RELEASE.jar下有一个)
  • 遍历每一个spring-factories文件,并获取其下key为factoryClass.getName()(这里是入参

    org.springframework.context.ApplicationContextInitializer)的value(这里有以上四个ApplicationContextInitializer实现类)

以上四个类的作用:

 

至此,设置ApplicationContextInitialize就完成了。

总结:整个setInitializers实际上就是初始化了SpringApplication的属性List<ApplicationContextInitializer<?>> initializers为一个ArrayList列表,该列表中有四个实例:

  • ConfigurationWarningsApplicationContextInitializer的实例
  • ContextIdApplicationContextInitializer的实例
  • DelegatingApplicationContextInitializer实例
  • ServerPortInfoApplicationContextInitializer实例

1.4、初始化ApplicationListener列表

复制代码
 1     private List<ApplicationListener<?>> listeners;    
 2 
 3         /**
 4      * Sets the {@link ApplicationListener}s that will be applied to the SpringApplication
 5      * and registered with the {@link ApplicationContext}.
 6      * @param listeners the listeners to set
 7      */
 8     public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
 9         this.listeners = new ArrayList<ApplicationListener<?>>();
10         this.listeners.addAll(listeners);
11     }    
复制代码

META-INF/spring-factories

复制代码
 1 # Application Listeners
 2 org.springframework.context.ApplicationListener=\
 3 org.springframework.boot.builder.ParentContextCloserApplicationListener,\
 4 org.springframework.boot.context.FileEncodingApplicationListener,\
 5 org.springframework.boot.context.config.AnsiOutputApplicationListener,\
 6 org.springframework.boot.context.config.ConfigFileApplicationListener,\
 7 org.springframework.boot.context.config.DelegatingApplicationListener,\
 8 org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
 9 org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
10 org.springframework.boot.logging.LoggingApplicationListener
复制代码

以上八个listener的作用如下:

至此,整个setListeners方法结束,初始化了一个包含以上8个ApplicationListener实例的List集合。

 

1.5、初始化主类mainApplicationClass

复制代码
 1     private Class<?> mainApplicationClass;
 2 
 3     private Class<?> deduceMainApplicationClass() {
 4         try {
 5             StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
 6             for (StackTraceElement stackTraceElement : stackTrace) {
 7                 if ("main".equals(stackTraceElement.getMethodName())) {
 8                     return Class.forName(stackTraceElement.getClassName());
 9                 }
10             }
11         }
12         catch (ClassNotFoundException ex) {
13             // Swallow and continue
14         }
15         return null;
16     }
复制代码

说明:获取main()方法所在的主类Class对象,并赋值给SpringApplication的mainApplicationClass属性。

至此,SpringApplication对象初始化完成了。

总结:整个SpringApplication初始化的过程,就是初始化了

  • 一个包含入参MySpringApplication.class的sources的Set<Object>
  • 一个当前环境是否是web环境的boolean webEnvironment
  • 一个包含4个ApplicationContextInitializer实例的List
  • 一个包含8个ApplicationListener实例的List
  • 一个main方法所在的主类的Class对象。

注意:

本文基本参照http://zhaox.github.io/java/2016/03/22/spring-boot-start-flow 完成,该文的作者已经解析的很好了,我这里再抄一遍,只是为了加深记忆!!!

 

http://www.cnblogs.com/java-zhao/p/5540309.html

 

目录
打赏
0
0
0
0
97
分享
相关文章
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。
265 1
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
293 7
Java 对象模型现代化实践 基于 Spring Boot 与 MyBatis Plus 的实现方案深度解析
本文介绍了基于Spring Boot与MyBatis-Plus的Java对象模型现代化实践方案。采用Spring Boot 3.1.2作为基础框架,结合MyBatis-Plus 3.5.3.1进行数据访问层实现,使用Lombok简化PO对象,MapStruct处理对象转换。文章详细讲解了数据库设计、PO对象实现、DAO层构建、业务逻辑封装以及DTO/VO转换等核心环节,提供了一个完整的现代化Java对象模型实现案例。通过分层设计和对象转换,实现了业务逻辑与数据访问的解耦,提高了代码的可维护性和扩展性。
76 1
Spring Boot 框架超级详细总结及长尾关键词应用解析
本文深入讲解Spring Boot框架的核心概念、功能特性及实际应用,涵盖自动配置、独立运行、starter依赖等优势。通过Web开发、微服务架构、批处理等适用场景分析,结合在线书店实战案例,演示项目初始化、数据库设计、分层架构实现全流程。同时探讨热部署、多环境配置、缓存机制与事务管理等高级特性,助你高效掌握Spring Boot开发技巧。代码示例详尽,适合从入门到进阶的学习者。
151 0
Java 开发中基于 Spring Boot 3.2 框架集成 MQTT 5.0 协议实现消息推送与订阅功能的技术方案解析
本文介绍基于Spring Boot 3.2集成MQTT 5.0的消息推送与订阅技术方案,涵盖核心技术栈选型(Spring Boot、Eclipse Paho、HiveMQ)、项目搭建与配置、消息发布与订阅服务实现,以及在智能家居控制系统中的应用实例。同时,详细探讨了安全增强(TLS/SSL)、性能优化(异步处理与背压控制)、测试监控及生产环境部署方案,为构建高可用、高性能的消息通信系统提供全面指导。附资源下载链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)。
231 0
springboot+redis互联网医院智能导诊系统源码,基于医疗大模型、知识图谱、人机交互方式实现
智能导诊系统基于医疗大模型、知识图谱与人机交互技术,解决患者“知症不知病”“挂错号”等问题。通过多模态交互(语音、文字、图片等)收集病情信息,结合医学知识图谱和深度推理,实现精准的科室推荐和分级诊疗引导。系统支持基于规则模板和数据模型两种开发原理:前者依赖人工设定症状-科室规则,后者通过机器学习或深度学习分析问诊数据。其特点包括快速病情收集、智能病症关联推理、最佳就医推荐、分级导流以及与院内平台联动,提升患者就诊效率和服务体验。技术架构采用 SpringBoot+Redis+MyBatis Plus+MySQL+RocketMQ,确保高效稳定运行。
151 0
|
2月前
|
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
350 8
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
258 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发

推荐镜像

更多
  • DNS
  • AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等