使用IDEA快速创建一个springboot项目

创建Spring Initializr,然后一直下一步下一步直至完成

选择web,表示创建web项目

运行原理分析

我们先来看看pom.xml文件

核心依赖的父项目如下:

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2..RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

进入spring-boot-starter-parent,可以看到管理SpringBoot应用里面所有依赖版本的地方和配置加载的地方。

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>//管理SpringBoot应用里面所有依赖版本的地方
<version>2.2..RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>

在进入spring-boot-dependencies,就可以看到所依赖的所有版本了,由于太过,这里只截取部分。

所以,以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了。

springboot自动配置原理分析

主程序

//@SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
@SpringBootApplication
public class Springboot01Application {
public static void main(String[] args) {
SpringApplication.run(Springboot01Application.class, args);
}
}
@SpringBootApplication意义:SpringBoot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
进入@SpringBootApplication会发现有三个重要的注解
  • @SpringBootConfiguration:SpringBoot的配置类 ;标注在某个类上 , 表示这是一个SpringBoot的配置类;
  • @EnableAutoConfiguration:开启自动配置功能
  • @ComponentScan:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中 ;

下面我们依次看一下这三个注解

@SpringBootConfiguration

进入@SpringBootConfiguration后,会看到@Configuration这个注解。

@Configuration:配置类上来标注这个注解,说明这是一个配置类 ,配置类,即:配置文件

在进入@Configuration后,会看到@Component注解,这个注解大家都很熟悉了吧,说明容器中的一个组件,也就是说启动类本身也是Spring中的一个组件而已,负责启动应用而已

返回来我们再看@ComponentScan

@ComponentScan

@ComponentScan在Spring中非常重要,它对应XML配置中的元素。功能就是自动扫描并加载符合条件的组件或者bean,将这个bean定义加载到IOC容器中 ;

接下来在看最重要的一个@EnableAutoConfiguration

@EnableAutoConfiguration

@EnableAutoConfiguration的作用是:开启自动配置功能,无须我们在自己配置,自动就告诉SpringBoot开启自动配置功能,这样自动配置才能生效;

进入@EnableAutoConfiguration后会发下有两个注解,@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)

@AutoConfigurationPackage //自动配置包
@Import(AutoConfigurationImportSelector.class) //导入哪些组件的选择器
public @interface EnableAutoConfiguration {
... ...
}

进入@AutoConfigurationPackage(自动配置包),有一个@Import(AutoConfigurationPackages.Registrar.class)。

@Import注解大家都知道,是Spring底层注解, 给容器中导入一个组件。

Registrar.class 将主配置类【即@SpringBootApplication标注的类】的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage { }

接下返回@EnableAutoConfiguration看下@Import(AutoConfigurationImportSelector.class)(给容器导入组件)。

AutoConfigurationImportSelector:自动配置导入选择器。

我们来思考下,它会导入哪些组件的选择器呢?进入这个类,我们来看源码

在类中找到这样一个方法

// 获得候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   //这里的getSpringFactoriesLoaderFactoryClass()方法
//返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}

getSpringFactoriesLoaderFactoryClass()

这个方法又调用了 SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
     //这里它又调用了 loadSpringFactories 方法
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

我们继续点击查看 loadSpringFactories 方法

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    //获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
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<>();
        //将读取到的资源遍历,封装成为一个Properties
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}

我们进入FACTORIES_RESOURCE_LOCATION

看到了这个路径:META-INF/spring.factories
FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"
接下来我们就找一下这个配置文件
找到spring-boot-autoconfigure-2.2.1.RELEASE.jar - META-INF - spring.factories文件

这些都是自动配置根源

进入我们熟悉的WebMvcAutoConfiguration,都是JavaConfig配置类,而且都注入了一些Bean

总结

springboot所有自动配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这里面,但不一定生效,要判断条件是否成立,只要导入对应的start,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功。

结论

1、SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
2、将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
3、以前我们需要自己配置的东西 , 自动配置类都帮我们解决了
4、整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
5、它将所有需要导入的组件以全类名的方式返回 , 这些组件就会被添加到容器中 ;
6、容器中存在非常多xxxAutoConfiguration的文件(@Bean), 就是给容器中导入这个场景需要的所有组件 ,并自动配置 ,@Configuration,javaConfig;
7、有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;

流程图:https://www.processon.com/view/link/5de763fee4b00e6d9017b5e5

run()方法

@SpringBootApplication
public class Springboot01Application {
public static void main(String[] args) {
//该方法返回一个ConfigurableApplicationContext对象
//参数一:应用入口的类 参数类:命令行参数
SpringApplication.run(Springboot01Application.class, args);
}
}

run()做了四件事:

  1. 推断应用的类型是普通的项目还是Web项目
  2. 查找并加载所有可用初始化器,设置到initializers属性中
  3. 找出所有的应用程序监听器,设置到listeners属性中
  4. 推断并设置main方法的定义类,找到运行的主类

springboot创建,自动装配原理分析,run方法启动的更多相关文章

  1. 【springboot】自动装配原理

    摘自:https://mp.weixin.qq.com/s/ZxY_AiJ1m3z1kH6juh2XHw 前言 Spring翻译为中文是"春天",的确,在某段时间内,它给Java开 ...

  2. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  3. Spring Boot 自动装配原理

    Spring Boot 自动装配原理 Spring Boot 在启动之前还有一系列的准备工作,比如:推断 web 应用类型,设置初始化器,设置监听器,启动各种监听器,准备环境,创建 applicati ...

  4. springboot自动装配原理回顾、配置文件分析

    配置文件 spring boot官方文档 官方外部配置文件说明参考文档 自动配置原理分析 1. SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfigurat ...

  5. SpringBoot:带你认认真真梳理一遍自动装配原理

    前言 Spring翻译为中文是“春天”,的确,在某段时间内,它给Java开发人员带来过春天,但是随着我们项目规模的扩大,Spring需要配置的地方就越来越多,夸张点说,“配置两小时,Coding五分钟 ...

  6. SpringBoot:认认真真梳理一遍自动装配原理

    前言 Spring翻译为中文是“春天”,的确,在某段时间内,它给Java开发人员带来过春天,但是随着我们项目规模的扩大,Spring需要配置的地方就越来越多,夸张点说,“配置两小时,Coding五分钟 ...

  7. SpringBoot自动装配原理解析

    本文包含:SpringBoot的自动配置原理及如何自定义SpringBootStar等 我们知道,在使用SpringBoot的时候,我们只需要如下方式即可直接启动一个Web程序: @SpringBoo ...

  8. SpringBoot | 2.1 SpringBoot自动装配原理

    @ 目录 前言 1. 引入配置文件与配置绑定 @ImportResource @ConfigurationProperties 1.1 @ConfigurationProperties + @Enab ...

  9. springboot自动装配原理

    最近开始学习spring源码,看各种文章的时候看到了springboot自动装配实现原理.用自己的话简单概括下. 首先打开一个基本的springboot项目,点进去@SpringBootApplica ...

随机推荐

  1. [LC] 767. Reorganize String

    Given a string S, check if the letters can be rearranged so that two characters that are adjacent to ...

  2. POJ3276 Face The Right Way 开关问题

    ①每个K从最左边进行考虑 ②f[i]=[i,i+k-1]是否进行反转:1代表是,0代表否 ③∑ (i)(i=i+1-K+1) f[j]=∑ (i-1)(i=i-K+1) f[j]+f[i]-f[i-K ...

  3. ioctl函数的使用之查看终端屏幕大小

    要想查看一个终端屏幕的大小,可以使用ioctl()函数,步骤如下. 1.首先找到对应终端的文件号,一般在   /dev/pts/....(0,1,2..).具体几号需要自己验证.如在pts目录下使用命 ...

  4. 实战_3:新建产品配置(product)并导出项目

    产品配置Product 产品配置用于定义和管理RCP应用的多个方面特征.并支持将RCP项目导出为部署包(类似eclipse压缩包),可以直接部署到其他环境上使用. 产品配置必须新建一个 扩展名为 .p ...

  5. yii执行流程简单介绍

    1. 用户访问 http://www.example.com/index.php?r=post/show&id=1,Web 服务器执行入口脚本 index.php 来处理该请求.  2. 入口 ...

  6. Leetcode9_回文数

    哈哈哈哈哈哈哈太开心了,今天的代码耗时和内存消耗比官方少了一半哈哈 (因为官方用C#写的,我用C++,手动狗头) 题目 判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样 ...

  7. Serializable中的serialVersionUID是必须的吗

    不写serialVersionUID就没有吗 即使不写, jdk反序列化时也会自动检查这个id, 反编译.class文件你也看不到这个值 rpc反序列化 如果使用jdk的方式, 这个必须配置 如果使用 ...

  8. HDU-1711-Number Sequence(KMP)(Rabin-Karp)

    Rabin-Karp Accepted 1711 904MS 5272K 1310 B G++ #include "bits/stdc++.h" using namespace s ...

  9. Mybatis-Plus的分页插件

    使用的是:Mybatis-Plus的分页插件https://baomidou.gitee.io/mybatis-plus-doc/#/?id=%E7%AE%80%E4%BB%8B 1.Mapper.j ...

  10. 聊聊H5与JS近几年的黑科技

    聊聊H5与JS近几年的黑科技 自ajax技术的诞生,编程界兴起了一股WEB开发热,facebook,Twitter等众多大佬级企业都在网页应用上大放异彩,这十年我们见证了前端技术的崛起.这期间产生了众 ...