SpringBoot 源码解析 (一)----- SpringBoot核心原理入门
Spring Boot 概述
Build Anything with Spring Boot:Spring Boot is the starting point for building all Spring-based applications. Spring Boot is designed to get you up and running as quickly as possible, with minimal upfront configuration of Spring.
上面是引自官网的一段话,大概是说: Spring Boot 是所有基于 Spring 开发的项目的起点。Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序并且尽可能减少你的配置文件。
什么是 Spring Boot
- 它使用 “习惯优于配置” (项目中存在大量的配置,此外还内置一个习惯性的配置,让你无须手动配置)的理念让你的项目快速运行起来。
- 它并不是什么新的框架,而是默认配置了很多框架的使用方式,就像 Maven 整合了所有的 jar 包一样,Spring Boot 整合了所有框架
使用 Spring Boot 有什么好处
回顾我们之前的 SSM 项目,搭建过程还是比较繁琐的,需要:
- 1)配置 web.xml,加载 spring 和 spring mvc
- 2)配置数据库连接、配置日志文件
- 3)配置家在配置文件的读取,开启注解
- 4)配置mapper文件
- .....
而使用 Spring Boot 来开发项目则只需要非常少的几个配置就可以搭建起来一个 Web 项目,并且利用 IDEA 可以自动生成生成
- 划重点:简单、快速、方便地搭建项目;对主流开发框架的无配置集成;极大提高了开发、部署效率。
Spring Boot HelloWorld
导入依赖spring boot相关的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>cn.chenhao</groupId>
<artifactId>springboot</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging> <name>springboot</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
编写主程序
/**
* @SpringBootApplication来标注一个主程序类,说明这是一个SpringBoot应用
*/
@SpringBootApplication
public class HelloWorldMainApplication { public static void main(String[] args) {
//Spring应用启动
SpringApplication.run(HelloWorldMainApplication.class, args);
}
}
编写Controller、Service
@RestController
public class HelloController { @RequestMapping("/hello")
public String hello(){
return "Hello world";
}
}
运行主程序测试
使用maven打包命令将其打包成jar包后,直接使用命令:
java -jar xxx.jar
Hello World探究
POM文件
父项目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/>
</parent>
其父项目是
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
该父项目是真正管理Spring Boot应用里面的所有依赖的版本:Spring Boot的版本仲裁中心,所以以后导入的依赖默认是不需要版本号。如下

还有很多版本号没有截图出来
启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
spring-boot-starter : spring boot场景启动器;帮助导入web模块正常运行所依赖的组件;
Spring Boot将所有的功能场景抽取出来,做成一个个的starter(启动器),只需要在项目中引入这些starter,那么相关的场景的所有依赖都会导入进项目中。要用什么功能就导入什么场景的启动器。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
添加了 spring-boot-starter-web 依赖,会自动添加 Tomcat 和 Spring MVC 的依赖
spring-boot-starter-web中又引入了spring-boot-starter-tomcat
主程序类(主入口类)
@SpringBootApplication
public class HelloWorldMainApplication { public static void main(String[] args) {
//Spring应用启动
SpringApplication.run(HelloWorldMainApplication.class, args);
}
}
@SpringBootApplication
- Spring Boot应用标注在某个类上,说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用。
注解定义如下:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}
@SpringBootConfiguration
- Spring Boot的配置类
- 标注在某个类上,表示这是一个Spring Boot的配置类
注解定义如下:
@Configuration
public @interface SpringBootConfiguration {}
其实就是一个Configuration配置类,意思是HelloWorldMainApplication最终会被注册到Spring容器中
@EnableAutoConfiguration
- 开启自动配置功能
- 以前使用Spring需要配置的信息,Spring Boot帮助自动配置;
- @EnableAutoConfiguration通知SpringBoot开启自动配置功能,这样自动配置才能生效。
注解定义如下:
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
@AutoConfigurationPackage
- 自动配置包注解
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}
@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//默认将会扫描@SpringBootApplication标注的主配置类所在的包及其子包下所有组件
register(registry, new PackageImport(metadata).getPackageName());
} @Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.<Object>singleton(new PackageImport(metadata));
}
}
@Import(EnableAutoConfigurationImportSelector.class)
EnableAutoConfigurationImportSelector: 导入哪些组件的选择器,将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中。
//EnableAutoConfigurationImportSelector的父类:AutoConfigurationImportSelector
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
我们主要看第11行List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);会给容器中注入众多的自动配置类(xxxAutoConfiguration),就是给容器中导入这个场景需要的所有组件,并配置好这些组件。我们跟进去看看
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
//...
return configurations;
} protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
} public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
//从类路径的META-INF/spring.factories中加载所有默认的自动配置类
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
//获取EnableAutoConfiguration指定的所有值,也就是EnableAutoConfiguration.class的值
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}

最终有96个自动配置类被加载并注册进Spring容器中

J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-xxx.jar中。在这些自动配置类中会通过@ConditionalOnClass等条件注解判断是否导入了某些依赖包,从而通过@Bean注册相应的对象进行自动配置。后面我们会有单独文章讲自动配置的内容
SpringBoot 源码解析 (一)----- SpringBoot核心原理入门的更多相关文章
- 【spring-boot 源码解析】spring-boot 依赖管理梳理图
在文章 [spring-boot 源码解析]spring-boot 依赖管理 中,我梳理了 spring-boot-build.spring-boot-parent.spring-boot-depen ...
- 【spring-boot 源码解析】spring-boot 依赖管理
关键词:spring-boot 依赖管理.spring-boot-dependencies.spring-boot-parent 问题 maven 工程,依赖管理是非常基本又非常重要的功能,现在的工程 ...
- SpringBoot源码解析系列文章汇总
相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的SpringBoot源码解析系列文章的汇总,当你使用SpringBoot不仅仅满足于基本使用时.或者出去面试被面试官虐了时.或者说想要深入了解一下 ...
- springboot源码解析-管中窥豹系列之aware(六)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之BeanDefinition(八)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之BeanDefine如何加载(十三)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之bean如何生成?(十四)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之总体结构(一)
一.简介 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之项目类型(二)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之Runner(三)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
随机推荐
- Windows 10 删除C盘的用户,恢复技巧
起因 入域不成功,然后强制删除了C盘 Users里面 账户 然后再进行入域的时候就入域不成功了,如果再进行登录就会提示 无法登录到你的账户 通常可以通过从你的账户注销,然后重新登录解决此问题 如果不立 ...
- 编程杂谈——使用emplace_back取代push_back
近日在YouTube视频上看到关于vector中emplace_back与push_back区别的介绍,深感自己在现代C++中还是有不少遗漏的知识点,遂写了段代码,尝试比较两者的差别. 示例代码 #i ...
- iOS RGBA转YV12
引言 因为项目中要做画面共享,所以需要学一点图像相关的知识,首当其冲就是RGB转YUV了,因为图像处理压缩这一块是由专业对口的同事做的,所以呢,我这就是写一下自己的理解,如有不对的地方,还望指正,谢谢 ...
- 【前端词典】4 个实用有趣的 JS 特性
前言 最近在学习的过程中发现了我之前未曾了解过的一些特性,发现有些很有趣并且在处理一些问题的时候可以给我一个新的思路. 这里我将这些特性介绍给大家. 4 个有趣的 JS 特性 利用 a 标签解析 UR ...
- PHP ksort
1.例子一: <?php /** * 根据 c1 对元素排序 */ $arrays = [ 'b' => [ 'c1' => 10, 'c2' => 5, ], 'a' =&g ...
- PMBOK(第六版) PMP笔记-质量审计、风险审计、采购审计的区分
质量审计.风险审计.采购审计的区分 三个概念的相同之处: 都是审计的概念 都是特定知识领域的审计 三个概念的区别: (1)三个概念虽然都是审计,但分布在不同的管理过程组. ·质量审计:执行过程组, ...
- ASP.NET Core 使用 JWT 自定义角色/策略授权需要实现的接口
目录 ① 存储角色/用户所能访问的 API ② 实现 IAuthorizationRequirement 接口 ③ 实现 TokenValidationParameters ④ 生成 Token ⑤ ...
- 使用zepto中animate报错“Uncaught TypeError: this.bind is not a function”的解决办法
在使用zepto时,我先引入zepto.min.js,然后引入fx.js,但是在使用animate函数时,控制台却报如下错误: Uncaught TypeError: this.bind is not ...
- CSS布局解决方案(终结版)
作者:无悔铭 https://segmentfault.com/a/1190000013565024 前端布局非常重要的一环就是页面框架的搭建,也是最基础的一环.在页面框架的搭建之中,又有居中布局.多 ...
- 百万年薪python之路 -- 基础数据类型的补充
基础数据类型的补充 str: 首字母大写 name = 'alexdasx' new_name = name.capitalize() print(new_name) 通过元素查找下标 从左到右 只查 ...