前言:
学习B站UP主狂神说视频笔记整理视频链接
笔记链接
Spring Boot是由Pivotal团队提供的脚手架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置
Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。也就是说,它并不是用来替代 Spring 的解决方案,而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具。Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用。
为所有Spring开发者更快的入门
开箱即用,提供各种默认配置来简化项目配置
内嵌式容器简化Web项目
没有冗余代码生成和XML配置的要求
微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成―系列小服务的组合;可以通过http的方式进行互通。要说微服务架构,先得说说过去我们的单体应用架构。
所谓单体应用架构(allin one)足指,我们将一个应用中的所有服务都制装在一个应用中。
无论是ERP,CRM或是其他什么系统,你都把数据库访问,web访问,等等各个功能放到一个war包内。
all in one的架构方式,我们把所有的功能单元放在一个应用里面。然后我们把整个应用部署到服务器上。如果负载能力不行,我们将整个应用进行水平复制,进行扩展,然后在负载均衡。
所谓微服务架构,就是打破之前all in one的架构方式,把每个功能元素独立出来。把独立出来的功能元素的动态组合,需要的功能元素才去拿来组合,需要多一些时可以整合多个功熊元素。所以微服务架构是对功能元素进行复制,而没有对整个应用进行复制。
Martin Fowler微服务架构论文-译文
Spring官方提供了非常方便的工具让我们快速构建应用
官网地址:
Spring Initializr:https://start.spring.io/
如果访问缓慢可以使用阿里云镜像地址:
https://start.aliyun.com/
项目创建方式一 : 使用Spring Initializr 的 Web页面创建项目
1、打开 https://start.spring.io/
2、填写项目信息
3、点击”Generate Project“按钮生成项目;下载此项目
4、解压项目包,并用IDEA以Maven项目导入,一路下一步即可,直到项目导入完毕。
5、如果是第一次使用,可能速度会比较慢,包比较多、需要耐心等待一切就绪。
项目创建方式二:使用 IDEA 直接创建项目
1、创建一个新项目
2、选择spring initalizr , 可以看到默认就是去官网的快速构建工具那里实现
1、在主程序的同级目录下,新建一个controller
包,一定要在同级目录下,否则识别不到
2、在包中新建一个HelloController
类
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "Hello World";
}
}
3、编写完毕后,从主程序启动项目,浏览器发起请求,看页面返回;控制台输出了 Tomcat 访问的端口号!
简单几步,就完成了一个web接口的开发,SpringBoot就是这么简单。所以我们常用它来建立我们的微服务项目!
点击 maven的 package
如果遇到以上错误,可以配置打包时 跳过项目运行测试用例
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-surefire-pluginartifactId>
<configuration>
<skipTests>trueskipTests>
configuration>
plugin>
如果打包成功,则会在target目录下生成一个 jar 包
如何更改启动时显示的字符拼成的字母,SpringBoot呢?也就是 banner 图案;
只需一步:到项目下的 resources 目录下新建一个banner.txt
即可。
图案可以到:https://www.bootschool.net/ascii 这个网站生成,然后拷贝到文件中即可!
我们之前写的HelloSpringBoot,到底是怎么运行的呢,Maven项目,我们一般从pom.xml
文件探究起;
其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.5.RELEASEversion>
<relativePath/>
parent>
点进去,发现还有一个父依赖
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.2.5.RELEASEversion>
<relativePath>../../spring-boot-dependenciesrelativePath>
parent>
这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;
以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了;
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
springboot-boot-starter-xxx
:就是spring-boot的场景启动器
spring-boot-starter-web
:帮我们导入了web模块正常运行所依赖的组件;
SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;
//@SpringBootApplication 来标注一个主程序类
//说明这是一个Spring Boot应用
@SpringBootApplication
public class SpringBootStudyApplication {
public static void main(String[] args) {
//将springboot 应用启动
SpringApplication.run(SpringBootStudyApplication.class, args);
}
}
但是一个简单的启动类并不简单!我们来分析一下这些注解都干了什么
扫描主启动类同级的包
开启自动配置功能
以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效
点进注解接续查看:
@AutoConfigurationPackage :自动配置包
@Import({AutoConfigurationImportSelector.class}) :给容器导入组件 ;
AutoConfigurationImportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码
// 获得候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> 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;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
// 启动类下的所有资源被导入
return EnableAutoConfiguration.class;
}
1.1 进入loadFactoryNames()方法
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
//这里它又调用了 loadSpringFactories 方法
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
1.2 进入loadSpringFactories ()方法
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
//去获取一个资源 "META-INF/spring.factories"
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
//将读取到的资源遍历,封装成为一个Properties
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
2.发现一个多次出现的文件:spring.factories
,全局搜索它
WebMvcAutoConfiguration
我们在上面的自动配置类随便找一个打开看看,比如 :WebMvcAutoConfiguration
这里就是关于SpringMVC的相关配置
所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories
配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。
SpringBoot在启动的时候从类路径下的META-INF/spring.factories
中获取EnableAutoConfiguration
指定的值
将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure
的jar包中;
它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;
spring.factories的配置类那么多,为什么只生效了部分?
需要导入start才能生效
核心注解:@ConditionalOnClass
括号内的条件满足才会生效
我最初以为就是运行了一个main方法,没想到却开启了一个服务;
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
//启动了一个服务
SpringApplication.run(SpringbootApplication.class, args);
}
}
分析该方法主要分两部分,
一部分是SpringApplication的实例化,二是run方法的执行;
这个类主要做了以下四件事情:
1、推断应用的类型是普通的项目还是Web项目
2、查找并加载所有可用初始化器 , 设置到initializers属性中
3、找出所有的应用程序监听器,设置到listeners属性中
4、推断并设置main方法的定义类,找到运行的主类
springboot是通过main方法下的SpringApplication.run方法启动的,启动的时候他会调用refshContext方法,先刷新容器,然后根据解析注解或者解析配置文件的形式注册bean,而它是通过启动类的SpringBootApplication注解进行开始解析的,他会根据EnableAutoConfiguration开启自动化配置,里面有个核心方法ImportSelect选择性的导入,根据loadFanctoryNames根据classpash路径以MATA-INF/spring.factorces下面以什么什么EnableAutoConfiguration开头的key去加载里面所有对应的自动化配置,他并不是把这一百二十多个自动化配置全部导入,在他每个自动化配置里面都有条件判断注解,先判断是否引入相互的jar包,再判断容器是否有bean再进行注入到bean容器
SpringBoot使用一个全局的配置文件,配置文件名称是固定的- application.properties
配置文件的作用︰修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了;
application.properties写法
# 应用名称
spring.application.name=springBootStudy
# 应用服务 WEB 访问端口
server.port=8080
application.yml写法
# 对空格要求十分高 格式 key:空格 value
# 应用名称
spring:
application:
name: springBootStudy
# 应用服务 WEB 访问端口
server:
port: 8080
# 行内写法
student: {name: 秦疆,age: 3}
# 数组
pets: [cat,dog,pig]
yml的强大之处是可以给属性赋值
以下是原来给属性赋值的方式:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component //被spring管理
public class Dog {
//通过@Value 为属性赋值
@Value("周去")
private String name;
@Value("3")
private int age;
}
当我们使用yml之后可以给属性这样赋值:
使用@ConfigurationProperties
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component//spring管理
@ConfigurationProperties(prefix = "person") //此注解将yml配置文件的值赋值给属性
public class Person {
private String name;
private int age;
private Boolean happy;
private Date date;
private Map<String,Object> map;
private List<Object> list;
private Dog dog;
}
yml配置文件如下:
# 属性赋值
Person:
name: 陈平安
age: 3
happy: true
date: 2011/11/02
map: {k1: v1,K2: v2}
list:
- java
- python
- js
dog:
name: 剑来
age: 1000
使用@ConfigurationProperties
注解会爆红,可根据官方提示在pom.xml配置文件中添加如下依赖:
<dependency>
<groupId> org.springframework.boot groupId>
<artifactId> spring-boot-configuration-processor artifactId>
<optional> true optional>
dependency>
重启IDEA即可,当然不添加此依赖不会影响程序正常运行
可以自定义properties
配置文件为属性赋值
# zhouqu.properties
Dog.name=周去
Dog.age=3
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component //被spring管理
//绑定配置文件
@PropertySource(value = "classpath:zhouqu.properties")
public class Dog {
@Value("${Dog.name}")
private String name;
@Value("${Dog.age}")
private int age;
}
需要在IDEA settings中设置properties
UTF-8编码以防出现中文乱码
@ConfigurationProperties | @properties | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 使用Value一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 部支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
这里我们看到一个松散绑定,这个是什么意思呢
比如我的yml中写的last-name
,这个和lastName
是一样的, –
后面跟着的字母默认是大写的。这就是松散绑定
跟与mybatis中的驼峰命名规则映射有点相似
配置文件还可以编写占位符生成随机数
person:
name: qinjiang${random.uuid} # 随机uuid
age: ${random.int} # 随机int
happy: false
birth: 2000/01/01
maps: {k1: v1,k2: v2}
lists:
- code
- girl
- music
dog:
name: ${person.hello:other}_旺财
age: 1
前情回顾:
SpringBoot自动装配会在启动的时候从类路径下的META-INF/spring.factories
中获取EnableAutoConfiguration
指定的值
我们用HttpEncodingAutoConfiguration
来举例说明
// 标注自动装配类
@Configuration(
proxyBeanMethods = false
)
//自动装配的属性 ServerProperties.class
@EnableConfigurationProperties({ServerProperties.class})
//spring底层注解 根据不同的条件 来判断当前配置类是否生效
@ConditionalOnWebApplication(
type = ConditionalOnWebApplication.Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
prefix = "server.servlet.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
public HttpEncodingAutoConfiguration(ServerProperties properties) {
this.properties = properties.getServlet().getEncoding();
}
自动配置类可以配置哪些内容,我们完全可以找到@EnableConfigurationProperties({ServerProperties.class})
注解后标注的class
点击ServerProperties.class
在application.yml
配置文件中,使用server能点出来的内容都可以在ServerProperties.class
中找到!
在其中我们发现了一些规律,所有能点出来的配置都会有一个XXXXProperties.class
这个类又会和XXXXAutoConfiguration
自动配置类绑定(默认值) 我们可以通过改变XXXXProperties.class
来实现自定义配置
由此我们可以得到自动配置原理:
# 在application.yml中配置
# 可以在日志中查看到哪些自动配置类是否生效
debug: true
spring-boot中可以用@validated
来校验数据,如果数据异常则会统一抛出异常,方便异常中心统—处理。我们这里来写个注解让我们的name
只能支持Email
格式
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component //被spring管理
@PropertySource(value = "classpath:zhouqu.properties")//绑定配置文件
@Validated//数据校验
public class Dog {
@Email(message="不是一个邮箱!")
private String email;
}
如果@Email
注解报红 是因为新版本需要validation启动器
解决方法:在pom.xml
加入下面依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-validationartifactId>
dependency>
使用数据校验,可以保证数据的正确性;
常见参数:
otNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")
private String email;
//空检查
@Null //验证对象是否为null
@NotNull //验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank //检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty //检查约束元素是否为NULL或者是EMPTY.
//Booelan检查
@AssertTrue //验证 Boolean 对象是否为 true
@AssertFalse //验证 Boolean 对象是否为 false
//长度检查
@Size(min=, max=) //验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) //string is between min and max included.
//日期检查
@Past //验证 Date 和 Calendar 对象是否在当前时间之前
@Future //验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern //验证 String 对象是否符合正则表达式的规则
方式一:
在application.yml
配置文件中选择激活哪个配置文件
# SpringBoot多环境配置可以选择激活哪一个配置文件
spring:
profiles:
active: dev #只需要写 - 后面的名字 application-dev.yml
方式二:
如果觉得分成三个配置文件较为麻烦,可以都写在application.yml
这一个配置文件中
# 多个环境通过 ---分割
spring:
profiles:
active: dev
---
server:
port: 8002
spring:
profiles: dev
---
server:
port: 8003
spring:
profiles: test