Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

SpringBoot简介

核心:约定大于配置

Spring是如何简化java开发的

为了降低java开发的复杂性,Spring采用了以下4种关键策略

  1. 基于pojo的轻量级和最小侵入性编程
  2. 通过IOC,依赖注入(DI)和面向接口实现松耦合
  3. 基于切面(AOP)和惯例进行声明式编程
  4. 通过切面和模板减少样式代码

SpringBootd的主要优点

  • 为所有Spring开发者更快的入门
  • 开箱即用,提供各种默认配置来简化项目配置
  • 内嵌式容器简化Web项目
  • 没有冗余代码生成和XML配置的要求

springboot原理(一丢丢)

自动配置

pom.xml

  • spring-boot-denpendencies:核心依赖在父工程
  • 我们在写入或者引入一些springboot依赖的时候,不需要指定版本,就是因为有版本仓库

image-20200806190652282


启动器

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
  • 启动器:就是springboot的启动场景

  • 比如上面这个启动器,他就会帮我们自动导入web环境所有的依赖

  • springboot会将所有的功能场景都变成一个个的启动器

  • 我们要使用什么功能,就只需要找到对应的启动器就可以了 starter

小结:springboot所有的配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的start,就有对应的启动器有了启动器,我们自动装配就会生效,然后就配置成功了。

  1. SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
  2. 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作
  3. 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;它会把所有需要导入的组件以类名的方式返回,这些组件就会被添加到容器
  4. 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件
  5. 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作

SpringApplication

这个类主要做了一下四个事情

  1. 推断这个应用是普通项目还是Web项目
  2. 查找并加载所有可用初始化器,设置带initializers属性中
  3. 找出所有的应用程序监听器,设置到listeners属性中
  4. 推断并设置main方法的定义类,找到运行的主类

run方法流程分析

img

SpringBoot中常用的注解

  • @Controller: 控制器(注入服务)用于标注控制器
  • @Service:用于标注服务层,主要来进行业务的逻辑处理
  • @Repository实现dao访问用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件
  • @Component:(把普通pojo实例化到spring容器中,相当于存在配置文件中)泛指各种组件,就是说我们的类不属于归类的时候(不属于@Controller、@Services等的时候),我们可以用@Component来标注这个类
  • @Validated:开启数据校验,然后在属性上加@Email等注解(JSR303校验)

yaml语法

配置文件

SpringBoot使用一个全局的配置文件,配置文件名称是固定的

  • application.properties
  • 语法结构:key=value
  • application.yml
  • 语法结构:key:空格 value

配置文件的作用:修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们配置好了。

yaml概述

YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:”Yet Another Markup Language”(仍是一种标记语言)

这中语言以数据为中心,而不是以标记语言为重点!

以前的配置文件,大多数都是使用xml来配置,比如一个简单的端口配置,简单的对比一下xml和yaml;

传统的xml配置

1
2
3
<server>
<port>8081<port>
</server>

yaml配置:

1
2
server:
prot: 8080

yaml基础语法

说明:语法要求严格。

  1. 空格不能省略

  2. 以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。(类似于python)

  3. 属性和值的大小都是十分敏感的。

    字面量: 普通的值[数字,布尔值,字符串]

    字面量直接写在后面就可以,字符串默认不用加上双引号或者单引号;

    1
    key: value

注意:

  • “” 双引号,不会转字符串里面的特殊字符,特殊字符会作为本身想表示的意思;比如 name: “bestrooki \n e” 输出 bestrooki 换行 e
  • ‘’ 单引号,会转义特殊字符,特殊字符最终会变成和普通字符一样输出;比如 name: ‘bestrooki \n e’ 输出:bestrooki \n e

对象、map(键值对)

1
2
3
4
#对象、Map格式
k:
v1:
v2:

在下一行来写对象的属性和值的关系,注意缩进;

1
2
3
student:
name: qinjiang
age: 3

行内写法

1
student: {name: qinjiang,age: 3}

数组(List、set)

用- 值表示数组中的一个元素,比如;

1
2
3
4
pets:
- cat
- dog
- pig

行内写法

1
pets: [cat,dog,pig]

修改SpringBoot的默认端口号

配置文件中添加,端口号的参数,就可以切换端口;

1
2
server:
port: 8082

yaml注入配置文件

  1. 在SpringBoot项目中的resource目录新建一个文件application.yml

  2. 编写一个实体类Dog;

    1
    2
    3
    4
    5
    6
    7
    package com.bestrookie.springboot.pojo;
    @Component //注册bean到容器中
    public class Dog {
    private String name;
    private Integer age;
    //有参无参构造、get、set方法、toString()方法
    }
  3. 原来的方法是用过Value注解注入属性值

    1
    2
    3
    4
    5
    6
    7
    @Component //注册bean
    public class Dog {
    @Value("阿黄")
    private String name;
    @Value("18")
    private Integer age;
    }
  4. 在SpringBoot的测试类下测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @SpringBootTest
    class DemoApplicationTests {
    @Autowired //将狗狗自动注入进来
    Dog dog;
    @Test
    public void contextLoads() {
    System.out.println(dog); //打印看下狗狗对象
    }
    }

    结果成功输出

    image-20200907174408597

  5. 我们再编写一个复杂一点的实体类:Person

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Component //注册bean到容器中
    public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
    //有参无参构造、get、set方法、toString()方法
    }
  6. 使用yaml的方式进行注入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    person:
    name: bestrookie
    age: 3
    happy: false
    birth: 2000/01/01
    maps: {k1: v1,k2: v2}
    lists:
    - code
    - girl
    - music
    dog:
    name: 旺财
    age: 1
  7. 现在将person这个对象的值注入到这个类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /*
    @ConfigurationProperties作用:
    将配置文件中配置的每一个属性的值,映射到这个组件中;
    告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
    参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
    */
    @Component //注册bean
    @ConfigurationProperties(prefix = "person")
    public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
    }
  8. 绑定完之后可能idea会提示爆红,可以点击查看文档找到一个依赖导入,但是如果不导入也没有问题不会影响程序的运行。

  9. 确认以上配置都完事之后,我们测试一下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @SpringBootTest
    class DemoApplicationTests {
    @Autowired
    Person person; //将person自动注入进来
    @Test
    public void contextLoads() {
    System.out.println(person); //打印person信息
    }
    }

配置文件占位符

配置文件还可以编写占位符生成随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
person:
name: bestrookie${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

对比小结

@Value这个使用起来并不友好,我们需要为每个属性单独注解赋值,比较下面功能对比图

@ConfigurationProperties @value
功能 批量注入配置文件中的属性 一个个指定
松散绑定 支持 不支持
SpEl 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持
  1. @ConfigurationProperties只需要写一次即可,@Value需要每个字段都添加
  2. 松散绑定:这个是什么意思呢?比如我的yaml中写的last-name,这个和lastName是一样的,-后面跟着的字母默认是大写的。这就松散绑定,
  3. JSR303数据校验:这个就是我们可以在字段中增加一层过滤器验证,可以保证数据的合法性
  4. 复杂类型封装,yaml中可以封装对象没使用value就不支持

结论:

配置yaml和配置properties都可以获取到值,强烈推荐yaml

如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用@value;

如果说,我们专门编写了一个javaBean来和配置文件一一映射,就直接使用@configurationProperties。

JSR303数据校验及多环境切换

如何使用

Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。我们举例name只能支持Email格式。

1
2
3
4
5
6
7
@Component //注册bean
@ConfigurationProperties(prefix = "person")
@Validated //数据校验
public class Person {
@Email(message="邮箱格式错误") //name必须是邮箱格式
private String name;
}

运行结果:default message [不是一个合法的电子邮件地址];

使用数据校验,可以保证数据的正确性

常见参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@NotNull(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 对象是否符合正则表达式的规则

多环境切换

profile是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境

例如:

application-test.properties 代表测试环境配置

application-dev.properties 代表开发环境配置

但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件

我们需要通过一个配置来选择需要激活的环境

1
2
3
#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active=de

yaml的多文档块

和properties配置文件中一样,但是使用yaml去实现不需要创建多个配置文件,更加方便了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server:
port: 8081
#选择要激活那个环境块
spring:
profiles:
active: prod


---
server:
port: 8083
spring:
profiles: dev #配置环境的名称




---


server:
port: 8084
spring:
profiles: prod #配置环境的名称

注意:如果yaml和properties同时都配置了端口,并且没有激活其他的环境,默认properties文件的

配置文件加载位置

外部加载配置文件的方式十分多,我们选择最常用的即可,在开发的资源文件中进行配置

官方外部配置文件说明参考文档

image-20200907232008590

springboot启动会扫描以下位置的application。properties或者application.yaml文件作为springboot的默认配置文件:

-
优先级1:项目路径下的config文件夹配置文件

  • 优先级2:项目路径下配置文件
  • 优先级3:资源路径下的config文件夹配置文件
  • 优先级4:资源路径下配置文件

优先级由高到低,高优先级的配置会覆盖低优先级的配置

springboot会从这四个位置加载主配置文件。

自动配置原理

我们以8HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件;
@Configuration


//启动指定类的ConfigurationProperties功能;
//进入这个HttpProperties查看,将配置文件中对应的值和HttpProperties绑定起来;
//并把HttpProperties加入到ioc容器中
@EnableConfigurationProperties({HttpProperties.class})


//Spring底层@Conditional注解
//根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效;
//这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(
type = Type.SERVLET
)


//判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnClass({CharacterEncodingFilter.class})


//判断配置文件中是否存在某个配置:spring.http.encoding.enabled;
//如果不存在,判断也是成立的
//即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)


public class HttpEncodingAutoConfiguration {
//他已经和SpringBoot的配置文件映射了
private final Encoding properties;
//只有一个有参构造器的情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}

//给容器中添加一个组件,这个组件的某些值需要从properties中获取
@Bean
@ConditionalOnMissingBean //判断容器没有这个组件?
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
return filter;
}
//。。。。。。。
}

一句话总结:根据当前不同的条件判断,决定这个配置类是否生效

  • 一旦这个配置类生效,这个配置类就会给容器添加各种组件
  • 这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的
  • 所有在配置文件中能配置的属性都是在xxxproperties类中封装着
  • 配置文件能配置什么就可以参照某个功能对应的这个属性类
1
2
3
4
5
//从配置文件中获取指定的值和bean的属性进行绑定
@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {
// .....
}

总结

  1. Springboot启动会加载大量的自动配置类
  2. 我们看我们需要的功能在Springboot默认写好的自动配置类当中
  3. 我们再来看这个自动配置类中到底配置了哪些组件(只要我们要用的组件存在其中,我们就不需要再手动配置了)
  4. 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可

xxxxAutoConfigurartion:自动配置类给容器中添加组件

xxxxProperties:封装配置文件中相关属性

评论