一、前言

一个quickstart程序仅仅让我们初步了解一个框架,我们还需要透过现象看本质才能学好一个框架。所以这篇文章分析一下我上次写的springboot的入门程序。

二、原理分析

1、依赖分析

1.1、父模块的parent结点

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/>
</parent>

1.2、点进去spring-boot-starter-parent

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>

1.3、点进去spring-boot-dependencies

<properties>
<activemq.version>5.15.9</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
...
<commons-pool.version>1.6</commons-pool.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
...
</dependencies>
</dependencyManagement>

在spring-boot-dependencies中对大部分的jar包进行版本管理,再点进去每一个所引用到的starter里面就能看见每个jar包具体的版本。在spring-boot-dependencies已经定义了版本号的jar包,在其他地方引用就不需再写版本号了,而在spring-boot-dependencies没有被依赖的jar包,自行引入的时候就需要写版本号。 特别之处就是spring-boot-dependencies中使用了< dependencyManagement >,dependencyManagement 用于版本管理,声明jar,并不实际引入jar,子模块默认不继承,子模块需要的jar需要在子模块引入,并不需重新写版本号,若子模块定义了新的版本号,则优先使用子模块中的版本。而使用 < dependencies >就是直接引入jar。

(我的入门程序只引用到了spring-boot-starter-web和spring-boot-starter-test)

1.4、Tomcat在哪里

以往的spring程序都需要把项目发布在Tomcat中,然后手动启动Tomcat服务器进行测试。Springboot的入门程序只需要Run启动类就可以访问url了。这是为什么呢?

我们先点进去spring-boot-starter-web(这里没有写版本号)

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

再点进去spring-boot-starter-tomcat

<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.21</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>tomcat-annotations-api</artifactId>
<groupId>org.apache.tomcat</groupId>
</exclusion>
</exclusions>
</dependency>
...
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>9.0.21</version>
<scope>compile</scope>
</dependency>

**Springboot内嵌了一个Tomcat ! **Springboot2.1.6内嵌的Tomcat版本号为9.0.21。

2、注解分析

2.1、主启动类中的 @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 {
}

三个重点注解:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。下面来分析一下这三个注解。

2.1.1、@SpringBootConfiguration

Springboot配置类。标注在某个类上,表示这是一个Springboot的配置类。

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

用了Spring的@Configuration,表明这是一个配置类,相当于配置文件

2.1.2、@EnableAutoConfiguration

自动配置

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

两个关键注解:@AutoConfigurationPackage、@Import。

2.1.2.1 、@AutoConfigurationPackage
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}

@Import({Registrar.class}) 引入了Registrar组件。一个很关键的步骤:将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器。 就是由这一句注解完成的。

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
} public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
} public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
2.1.2.2 、@Import({AutoConfigurationImportSelector.class})

将一些快速地导入到Spring容器中

我们可以看getCandidateConfigurations方法中引用的SpringFactoriesLoader.loadFactoryNames方法。

Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");

Springboot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration 指定的值,根据这些值将自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。

2.1.3、@ComponentScan

相当于Spring配置文件中的,作用就是将不需要扫描的组件在这里声明。

<context:component-scan base-package="xxx">
<context:exclude-filter type="annotation" expression="xxxx"/>
</context:component-scan>

总结

知所以然才能知其所以。学习原理非常重要。

springboot笔记03——quickstart程序原理的更多相关文章

  1. 机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试

    机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理.源码解析及测试 关键字:决策树.python.源码解析.测试作者:米仓山下时间:2018-10-2 ...

  2. springboot笔记02——快速入门quickstart

    前言 学习一个新的框架,往往会用一个quickstart快速入门,这次就写一下springboot的quickstart程序. 开发环境 JDK 1.8 Springboot 2.1.6 Maven ...

  3. SaToken学习笔记-03

    SaToken学习笔记-03 如果排版有问题,请点击:传送门 核心思想 所谓权限验证,验证的核心就是一个账号是否拥有一个权限码 有,就让你通过.没有?那么禁止访问! 再往底了说,就是每个账号都会拥有一 ...

  4. Java:并发笔记-03

    Java:并发笔记-03 说明:这是看了 bilibili 上 黑马程序员 的课程 java并发编程 后做的笔记 3. 共享模型之管程-2 本章内容-2 Monitor wait/notify 3.6 ...

  5. 《30天自制操作系统》笔记(03)——使用Vmware

    <30天自制操作系统>笔记(03)——使用Vmware 进度回顾 在上一篇,实现了用IPL加载OS程序到内存,然后JMP到OS程序这一功能:并且总结出下一步的OS开发结构.但是遇到了真机测 ...

  6. Java IO学习笔记:概念与原理

    Java IO学习笔记:概念与原理   一.概念   Java中对文件的操作是以流的方式进行的.流是Java内存中的一组有序数据序列.Java将数据从源(文件.内存.键盘.网络)读入到内存 中,形成了 ...

  7. JS自学笔记03

    JS自学笔记03 1.函数练习: 如果函数所需参数为数组,在声明和定义时按照普通变量名书写参数列表,在编写函数体内容时体现其为一个数组即可,再传参时可以直接将具体的数组传进去 即 var max=ge ...

  8. C++ GUI Qt4学习笔记03

    C++ GUI Qt4学习笔记03   qtc++spreadsheet文档工具resources 本章介绍创建Spreadsheet应用程序的主窗口 1.子类化QMainWindow 通过子类化QM ...

  9. Redis:学习笔记-03

    Redis:学习笔记-03 该部分内容,参考了 bilibili 上讲解 Redis 中,观看数最多的课程 Redis最新超详细版教程通俗易懂,来自 UP主 遇见狂神说 7. Redis配置文件 启动 ...

随机推荐

  1. Windows系统CPU和内存状态实时查询(Java)

    一.背景 需要查询Windows服务器的CPU和内存状态. Linux系统查询CPU和内存状态很简单,一个top命令搞定,Windows就稍微麻烦一些了. 经过资料查找,发现jdk目前不能直接查询系统 ...

  2. ROS Software update

    http://packages.ros.org/ros/ubuntu

  3. 【 Linux 】Systemd 配置文件说明及编写(2)

    1. 开机启动 对于支持 systemd 的软件,如果想要设置开机启动,就执行如下命令(以 http 为例): systemctl enable httpd 上面的命令相当于在 /etc/system ...

  4. 【Leetcode_easy】1029. Two City Scheduling

    problem 1029. Two City Scheduling 参考 1. Leetcode_easy_1029. Two City Scheduling; 完

  5. 【Leetcode_easy】917. Reverse Only Letters

    problem 917. Reverse Only Letters solution: class Solution { public: string reverseOnlyLetters(strin ...

  6. Ubuntu 新装服务器部署流程

    1.设定时区 rm -f /etc/localtime cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 2.配置apt-get源 sed -i ...

  7. 14、OpenCV实现图像的空间滤波——图像锐化及边缘检测

    1.图像锐化理论基础 1.锐化的概念 图像锐化的目的是使模糊的图像变得清晰起来,主要用于增强图像的灰度跳变部分,这一点与图像平滑对灰度跳变的抑制正好相反.而且从算子可以看出来,平滑是基于对图像领域的加 ...

  8. 封装transform函数(设置和获取transform的属性和属性值)

    (function (w) { /** * 设置或者获取元素的transform属性值 * @param node 要设置的元素 * @param param 变换属性: translate\scal ...

  9. laravel 提交空字符串会被转成null解决方法

    在app\Http\Kernel.php文件夹中,注释全局中间件: \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull:: ...

  10. 修复ubuntu 安装mysql后必须使用sudo问题

    修改root用户 查看用户的权限,是否是mysql_native_password,如果不是,则将auth_sock改为mysql_native_password update user set pl ...