# Spring-Boot-Project
**Repository Path**: GuiGhost/Spring-Boot-Project
## Basic Information
- **Project Name**: Spring-Boot-Project
- **Description**: Spring Boot + Spring Security + Shiro + Swagger
- **Primary Language**: Java
- **License**: GPL-3.0
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-04-13
- **Last Updated**: 2021-04-13
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 微服务阶段
JavaSE:OOP思想
MySQL: 持久化
html+css+js+jQuery+框架:视图,框架不熟练
JavaWeb:独立开发MVC三层架构的网站了:原始
SSM:框架:简化了开发的流程,配置较为复杂
**war:tomcat运行**
Spring再简化——>SpringBoot - jar :内嵌tomcat;微服务架构
随着服务的增多,SpringCloud;
**阶段六学习:**

# 微服务
### 什么是微服务?
微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成一系列小服务的组合,可用通过http的方式进行互通。
### 单体应用架构
单体应用架构(all in one),将应用的所有服务都封装到一个应用中。
无论ERP、CRM或其他系统,都是把数据库、web访问等等各个功能放到一个war包中
优点:
* 易于开发和测试,方便部署,扩展时,将war复制后放到多个服务器,做个负载均衡即可
缺点:
* 维护不便,牵一发而动全身,修改非常小的地方也要停掉整个服务,重新打包、部署
### 微服务架构
微服务架构,就是把每个功能元素独立出来。把独立出来的功能元素动态组合,把我们所需要的功能元素组合,需要多一些可以整合多个功能元素。微服务架构是对功能元素进行复制,从而没有对整个应用进行复制
优点:
* 节省了资源调用
* 每个功能元素的服务都是可替换、可独立升级的软件代码
# 第一个SpringBoot程序
环境:
* jdk14
* maven3.6.3
* SpringBoot:最新版
* IDEA
创建:官网提供了快速生成的网站,IDEA集成了该网站
* 直接在官网创建,然后导入idea中进行开发
* 使用IDEA开发工具创建(推荐)
### SpringBoot程序目录结构

1. 程序的主启动类(@SpringBootApplication注解的HelloworldApplication)
2. 一个配置文件:application.properties
3. 一个测试类:@SpringBootTest注解的HelloworldApplicationTests
4. 一个pom.xml文件:
#### pom.xml分析
```xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.4.3
com.guighost
helloworld
0.0.1-SNAPSHOT
helloworld
Demo project for Spring Boot
14
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
```
#### 写一个http接口
1. 新建一个controller包(该包一定要在主程序的同级目录下,否则会找不到这个接口)
2. 在controller包中新建HelloController类
```java
package com.guighost.helloworld.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author GuiGhost
* @date 2021/03/15
* @className HelloController()
* 描述:
*/
@RestController
public class HelloController {
// 接口:http://localhost:8080/hello
@RequestMapping("/hello")
public String hello(){
//调用业务,接收前端参数
return "hello,world!——hello SpringBoot!";
}
}
```
3. 启动主程序,从浏览器发起请求,查看结果

4. 更改项目端口号
在SpringBoot核心配置文件中配置:`server.port=8056`
```properties
# 更改项目的端口号
server.port=8056
```
### 将项目打成jar包,点击maven的package命令

通过maven打jar包时,可能会遇到using 'utf-8' encoding to copy filtered resources的问题
解决:
修改 maven-plugins 版本
```xml
org.springframework.boot
spring-boot-maven-plugin
org.apache.maven.plugins
maven-resources-plugin
2.4.3
```
参考博客:https://blog.csdn.net/qq_35526165/article/details/112203197
**打好的jar包在项目的target目录下**
使用Powershell窗口,使用命令:`java -jar 打包好的jar包`就可以运行了
### 彩蛋
参考文献:https://mp.weixin.qq.com/s?__biz=Mzg2NTAzMTExNg%3D%3D&chksm=ce6107eff9168ef93424fc2422c74ec5ad5755e4944bbc8a07609f185ec1ad6037eb5ae0f8da&idx=1&mid=2247483724&scene=21&sn=77ce80187dbfdbaaafa0366f6a0c9151#wechat_redirect
如何更改启动时显示的字符拼成的字母,SpringBoot呢?也就是 banner 图案;
只需一步:到项目下的 resources 目录下新建一个banner.txt 即可。
图案可以到:https://www.bootschool.net/ascii 这个网站生成,然后拷贝到文件中即可!
# 原理初探
### 自动配置
pom.xml
* spring-boot-dependencies:核心依赖,在父工程中
* 在我们新增SpringBoot依赖时,不需要指定版本,原因就是父工程中有这些依赖的版本仓库
启动器
* ```xml
org.springframework.boot
spring-boot-starter
```
* 启动器:SpringBoot的启动场景
* 比如spring-boot-starter-web,它会自动导入web环境的所有依赖
* SpringBoot会将所有的功能场景,都变成一个个的启动器
* 如果我们需要什么功能,只需要找到对应的启动器就行了`starter`
### 主程序
`@SpringBootApplication`注解:标注这个类是一个springboot的应用
```java
package com.guighost;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//@SpringBootApplication:标注这个类是一个springboot的应用
@SpringBootApplication
public class Springboot01HelloworldApplication {
public static void main(String[] args) {
//将SpringBoot应用启动
SpringApplication.run(Springboot01HelloworldApplication.class, args);
}
}
```
* 注解
* ```java
@SpringBootConfiguration:springboot的配置
@Configuration:spring配置类
@Component:说明这是一个Spring组件
@EnableAutoConfiguration:自动配置
@AutoConfigurationPackage:自动配置包
@Import({Registrar.class}):自动配置’包注册‘
@Import({AutoConfigurationImportSelector.class}):自动配置导入选择
//获取所有的配置
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
```
获取候选的配置
```java
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
```
META-INF/spring.factories:自动配置的核心文件

```java
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
//所有的资源加载到配置中
```

### 学习方法:由简入深,依次展开——借助流程图
例如:SpringBoot的自动配置
首先从单一的一个`@SpringBootApplication`注解入手(该注解是一个集大成者),然后慢慢的、依次向下的去挖出该注解中的内容@SpringBootConfiguration、@EnableAutoConfiguration(自动导入包)、@ComponentScan(扫描当前主程序同级目录下的包),再从`@SpringBootApplication`注解中挖出的另外三个注解入手,逐一疏通,直到找到我们所需要的东西为止。
### 结论

* SpringBoot中的自动配置都是程序启动的时候通过`@SpringBootApplication`注解下的`@EnableAutoConfiguration`注解中的AutoConfigurationImportSelector(自动配置选择器类)
* AutoConfigurationImportSelector类中有一个获得自动配置实体的方法getAutoConfigurationEntry()
* 而这个自动获取配置实体方法中又调用了获取候选配置的方法getCandidateConfigurations()
* 获取候选配置的方法中则通过调用SpringFactoriesLoader类中的loadFactoryNames()方法,loadFactoryNames()方法是获取所有的加载配置,这个方法是怎么获取的呢?
* loadFactoryNames()方法通过调用loadSpringFactories()方法,loadSpringFactories()方法会根据@EnableAutoConfiguration注解所在项目的spring-boot-autoconfigure-2.4.3.jar报下的META-INF下的spring.factories项目资源中遍历所有自动配置元素并封装为Properties供我们使用;@EnableAutoConfiguration注解是什么呢?
* @EnableAutoConfiguration注解是loadFactoryNames()方法的一个参数,该参数是通过getSpringFactoriesLoaderFactoryClass()方法得到的,这个参数是一个标记了@EnableAutoConfiguration注解的类(这个类就是项目的入口,也就是主程序类【主程序类的@SpringBootApplication注解集成了@EnableAutoConfiguration注解】);
思考:在spring.factories项目资源中有很多自动配置类,但是为什么有些自动配置类需要导入对应starter才能生效
* 根据上面的问题,引出一个核心注解@ConditionalOnXXX(@ConditionalOnClass),但并不一定是Class结尾,
* 只有@ConditionalOnClass注解里面的条件全都满足时,才能生效,怎么才能满足全部条件呢?只有导入了对应的starter,就有了对应的启动器,有了启动器,我们的自动装配才能生效
* 以上就是为什么在spring.factories项目资源中有很多自动配置类,而有些这需要导入对应starter才能生效的原因
注意:
1. 整个JavaEE的解决方案和自动配置的东西都在spring-boot-autoconfigure-2.4.3.jar包下
2. springboot会把所有需要的组件,以类名的方式返回,这样这些组件就会自动装配到容器中
3. 容器中也会存在非常多的xxxAutoConfiguration的文件,就是这写类给容器中导入了这个场景需要的所有组件并自动配置,而这些类就是通过javaCoinfig形式(**@Configuration**)配置的


### 主启动类的运行
#### SpringApplication
我最初以为就是一个main方法,但是他却开启了一个服务;
```java
//@SpringBootApplication:标注这个类是一个springboot的应用;启动类下的所有资源被导入
@SpringBootApplication
public class Springboot01HelloworldApplication {
public static void main(String[] args) {
//将SpringBoot应用启动
//SpringApplication类
//run方法
SpringApplication.run(Springboot01HelloworldApplication.class, args);
}
}
```
**SpringApplication.run分析**
分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;
SpringApplication类主要做了一下四件事情:
1. 推断应用的类型是普通的项目还是Web项目
2. 查找并加载所有的可用初始化器,并设置到initializers属性中
3. 找出所有的应用程序监听器,设置到listeners属性中
4. 推断并设置main方法的定义类,找到运行的主类
查看构造器
```java
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = Collections.emptySet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
```
#### run方法流程分析

# SpringBoot配置:yaml语法学习
### 配置文件
SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的
* application.properties
* 语法结构:key=value
* application.yaml
* 语法结构:key:空格 value
**配置文件可以修改SpringBoot自动配置的默认值,(Why:因为SpringBoot在底层都配置好了的)**
### yaml概述
YAML是 "YAML Ain't a Markup Language" (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)
**注意:该语言是以数据作为中心,而不是标记语言**
对比xml配置文件:如配置端口
* xml配置:
```xml
8058
```
* yaml配置:
```yaml
server:
port: 8058
```
### yaml基础语法
**说明:yaml的语法要求极其严格!**
1. 空格不能省略
2. 以缩进来控制层级关系,只要左边对齐的一列数据都是同级的
3. 属性和值的大小写都是十分敏感的
**字面量: 普通的值【数字、布尔值、字符串】**
字面量直接写在后面就可以 , 字符串默认不用加上双引号或者单引号;
```yaml
k: guigui
```
注意:
* “ ” 双引号,不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;
比如 :name: "kuang \n shen" 输出 :kuang 换行 shen
* '' 单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出
比如 :name: ‘kuang \n shen’ 输出 :kuang \n shen
**对象、Map(键值对)**
```yaml
# 对象、Map格式
k:
v1: value1
v2: value2
# 在下一行来写对象的属性和值得关系,注意缩进;比如:
student:
name: guigui
age:8
```
行内写法
```yaml
student: {name: guigui,age: 3}
```
**数组(List、Set)**
用 - 值表示数组中的一个元素,比如:
```yaml
pets:
- cat
- dog
- pig
```
行内写法
```yaml
pets: [cat,dog,pig]
```
**修改SpringBoot的默认端口号:**
```yaml
server:
port: 8058
```
### 注入配置文件
1. 在SpringBoot项目中的resources目录下新建一个application.yaml文件

2. 编写一个实体类
```java
@Component
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map map;
private List