说明:

本系列基于SpringBoot 2.2.9.RELEASE 版本,对SpringBoot的原理进行分析,一共分为四节:

SpringBoot原理发现(一):创建Hello World,对pom依赖以及@SpringBootApplication注解进行分析

SpringBoot原理发现(二):分析SpringBoot自动配置原理

SpringBoot原理发现(三):通过主配置类main方法分析SpringBoot启动配置原理

SpringBoot原理发现(四):了解SpringBoot启动中的几个重要回调机制

Hello World

创建Hello World,主启动类如下:

@SpringBootApplication
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} @RestController
public class HelloController{ @GetMapping("/")
public String helloWorld(){
return "hello world";
}
}
}

1. POM文件

 1.1 父POM

<!-- 当前项目pom -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.9.RELEASE</version>
<relativePath/>
</parent> <!-- spring-boot-starter-parent 的父pom -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.9.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>

  可以看出当前项目pom中的parent 依赖了 spring-boot-dependencies,而spring-boot-dependencies中管理的就是SpringBoot应用里面的所有依赖版本。(如果其中没包含,需要自定义在父pom中进行依赖)

<!-- spring-boot-dependencies 部分代码 -->
<properties>
<activemq.version>5.15.13</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.81</appengine-sdk.version>
<artemis.version>2.10.1</artemis.version>
<aspectj.version>1.9.6</aspectj.version>
<assertj.version>3.13.2</assertj.version>
<atomikos.version>4.0.6</atomikos.version>
<awaitility.version>4.0.3</awaitility.version>
<bitronix.version>2.1.4</bitronix.version>

  .......

 1.2  启动器

    SpringBoot将所有的功能场景都抽取成一个个的starter,只需要依赖某个starter,便有了相关依赖信息及功能,这样的starter称之为场景启动器。

  可以通过点击官网进行查看包含哪些starter,如下图:

  

  如开发web应用,只需要引入spring-boot-starter-web便有了web模块的相关功能

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency> ......

  spring-boot-starter-web:管理了web模块需要引用的依赖文件,如下图:

<!-- spring-boot-starter-web.pom部分依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.2.9.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.2.9.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.2.9.RELEASE</version>
<scope>compile</scope>
</dependency>

2.主程序分析

@SpringBootApplication
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} @RestController
public class HelloController{ @GetMapping("/")
public String helloWorld(){
return "hello world";
}
}
}

  2.1 @SpringBootApplication

   该注解标注在某个类上,说明这个类是SpringBoot的主配置类,SpringBoot应用应该使用这个类的main方法进行启动。

   进入该注解,可以看到@SpringBootApplication是一个组合注解,代码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

   2. 1.1 @SpringBootConfiguration

    SpringBoot的配置类。进去会发现其实就是一个Spring的配置类@Configuration,而@Configuration其实就是一个组件@Component。

    @SpringBootConfiguration是SpringBoot提供的,而@Configuration是Spring提供的

    代码如下:

/**
* SpringBootConfiguration
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration { ..... /**
* Configuration
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

  2 .2 @EnableAutoConfiguration

    作用:开启自动配置功能

    所谓开启自动配置:以前需要提供各种配置文件,如包扫描等,现在使用@EnableAutoConfiguration标注,SpringBoot就会开启自动配置功能。

    点开这个注解,会发现它同样是组合注解,如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    2.2.1 @AutoConfigurationPackage

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage { }
@Import(AutoConfigurationPackages.Registrar.class):向容器中导入一个组件,组件由@Import后面传入的类指定
AutoConfigurationPackages.Registrar.class 关键代码如下:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

        @Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}

  通过debug可以查看该注解是标注是在主启动类上,获取主启动类所在的包位置路径,将该路径下面的所有包扫描注入到容器中。类似spring配置文件xml中 <context:component-scan base-package="xx.yyy" />功能。

@AutoConfigurationPackage 其实就是自动获取主配置类下面的所有包并扫描注入进IOC容器中。

    2.2.2 @Import(AutoConfigurationImportSelector.class)

    同样是往IOC容器中导入AutoConfigurationImportSelector.class中指定的组件。

    AutoConfigurationImportSelector主要代码:

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}

  通过debug可以看出,它会返回各种XXXAutoConfiguration。而有了这些XXXAutoConfiguration,就不需要我们在手动去编写相关场景的注入功能组件等工作,如下图:

这些XXXAutoConfiguration又是从何而来呢?
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
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;
}

SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader())
 第一个参数:EnableAutoConfiguration.class
 第二个参数:ClassLoader

进入loadFactoryNames方法,SpringBoot会扫描类路径下的META-INF/spring.factories 文件中定义的数据,并返回第一个参数EnableAutoConfiguration指定的值,并将这些值作为自动配置类导入到容器中,
 在后续该方法会经常出现,用于扫描spring.factories中定义的值,如下图:

  

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\ ......

  至此基本上可以看出SpringBoot是如何进行加载且工作的。说到底spring的配置文件一个也没少,只是SpringBoot底层将我们的配置文件进行自动配置到容器中了,少了手动编写大量的组件配置。

SpringBoot原理发现(一)的更多相关文章

  1. 深入springboot原理——动手封装一个starter

    从上一篇文章<深入springboot原理——一步步分析springboot启动机制(starter机制)> 我们已经知道springboot的起步依赖与自动配置的机制.spring-bo ...

  2. 深入springboot原理——一步步分析springboot启动机制(starter机制)

    前言 使用过springboot的同学应该已经知道,springboot通过默认配置了很多框架的使用方式帮我们大大简化了项目初始搭建以及开发过程.本文的目的就是一步步分析springboot的启动过程 ...

  3. Spring-boot原理(附带实现一个spring-boot-starter实例和代码下载)

    ​ (我就是个封面) Spring-boot自出现后,到现在火的很,大家貌似都在用,连招聘里面也要求会这个.但是说实话,spring-boot无外乎想实现一种可插拔的编程方式,说是简化配置,其实并没有 ...

  4. SpringBoot原理讲解

    一.问题的引入 首先我们来看一个最简单的例子. 我们先创建一个SpringBoot的工程,如何创建一个SpringBoot工程就不说了,不会请自行解决.然后写一个controller类,通过请求路径, ...

  5. SpringBoot原理分析与配置

    1.1 起步依赖原理分析 1.1.1 分析spring-boot-starter-parent 按住Ctrl点击pom.xml中的spring-boot-starter-parent,跳转到了spri ...

  6. SpringBoot原理—分析SpringBoot启动机制(starter机制)

    一:前言使用过springboot的同学应该已经知道,springboot通过默认配置了很多框架的使用方式帮我们大大简化了项目初始搭建以及开发过程.本文的目的就是一步步分析springboot的启动过 ...

  7. SpringBoot原理深入及源码剖析(一) 依赖管理及自动配置

    前言 传统的Spring框架实现一个Web服务需要导入各种依赖jar包,然后编写对应的XML配置文件等,相较而言,SpringBoot显得更加方便.快捷和高效.那么,SpringBoot究竟是如何做到 ...

  8. Springboot原理

    1. SpringBoot特点 一个starter导入所有 依赖管理 父项目做依赖管理:声明了所需依赖的版本号 依赖管理 <parent> <groupId>org.sprin ...

  9. Spring-Boot原理及应用布署

    一.Spring Boot的理念 从最根本上来讲,Spring Boot就是一些库的集合,它能够被任意项目的构建系统所使用.简便起见,该框架也提供了命令行界面,它可以用来运行和测试Boot应用.框架的 ...

随机推荐

  1. 第一次的博客-简单的Markdown语法

    第一次开通博客 从网上寻找了许多写博客的方法 我觉得对于我来说还是使用 Markdowm 比较容易一些 用我的第一篇博客来记一下一些比较简单常用的Markdown语法 本文参考来源Markdown语法 ...

  2. Go-The process cannot access the file because it is being used by another process.

    where? Go程序在读取文件时候 why? 因为有其他进程也在读取和Go程序想要读取的文件,参数冲突 way? 关闭其他程序进程对该文件的读取操作

  3. SpringBoot2.3中@Async实现异步

    启动加上@EnableAsync ,需要执行异步方法上加入@Async. 在方法上加上@Async之后 底层使用多线程技术. 不使用异步 先关代码: package com.yiyang.myfirs ...

  4. 042 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 04 案例演示while循环的使用——循环输出英文字母

    042 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 04 案例演示while循环的使用--循环输出英文字母 本文知识点:案例演示while循环的使用2 ...

  5. Python之路——变量

    什么是变量 #变量即变化的量,核心是"变"与"量"二字,变即变化,量即衡量状态. 为什么要有变量 #程序执行的本质就是一系列状态的变化,变是程序执行的直接体现, ...

  6. Python+Appium自动化测试(2)-appium连接真机启动app

    app自动化测试的第一步,是启动被测app.appium环境搭建好后,我们就可以连接真机启动app了.环境为windows,Appium1.18.0,Android手机,被测app为今日头条app,让 ...

  7. 持续集成工具之Jenkins使用配置

    在上一篇博客中,我们主要介绍了DevOps理念以及java环境和jenkins的安装,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13805666.html: ...

  8. nrf528xx bootloader 模块介绍

    1. bootloader 的基本功能: 启动应用 几个应用之间切换 初始化外设 nordic nrf52xxx的bootloader主要功能用来做DFU, 可以通过HCI, UART 或BLE通信的 ...

  9. 实验二 HTML中图片和超链接的应用

    实验二 HTML中图片和超链接的应用 [实验目的] 1.通过本例要求掌握常见的图像格式及图像的插入方法. 2.能够修改图像属性,利用外部图像处理软件编辑图像. 3.掌握设置各类超级连接的方法. 4.灵 ...

  10. 一入Java深似海

    Java的基础语法 一个java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来写协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象: 对象是一个类的实例,有状态和行为.例如 ...