SpringBoot入门篇 01、Springboot入门及配置(二)

简介: SpringBoot入门篇 01、Springboot入门及配置(二)

五、配置文件


前提介绍

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


参考文档:配置文件Common application properties


我们先看一下三种配置文件


xml配置:


<server>
    <port>8080</port>
</server>


properties配置:


server.port=8080


yaml配置:


server:
  port: 8080


对于springboot提供两种常用的配置文件格式,分别是properties与yaml。


1、properties配置

常见的配置文件格式,Spring中经常使用这种格式,结构为key=value形式


# 单个属性
name=changlu
# 给对象属性赋值
server.port=8080
student.name=changlu
student.age=20
# list集合
lists[0]=list1
lists[1]=list2
# list集合写法2
lists=list1,list2
# map集合
maps.name=changlu
maps.value=value
# map集合写法2
maps[name]=changlu
maps[value]=value



注意:对于springboot来说一般推荐使用yaml而不是用properties


配置文件两种方式

两个资源:/src/main/java/com/changlu/pojo/Person /src/resource/changlu.properties


方式一:需要通过SPEL表达式来取出并注入到属性中


Person.class:


@Component
@PropertySource("classpath:changlu.properties")
public class Person {
    @Value("${name}")
    private String name;
    @Value("${age}")
    private Integer age;
    @Value("${happy}")
    private Boolean happy;
    @Value("${birthday}")
    private Date birthday;
    @Value("#{'${lists}'}")
    private List<Object> lists;
     ...空/有参,set/get方法
}


changlu.properties:


name=changlu
age=18
happy=false
birthday=2001/07/21
lists=list1,list2,list3


方式二:通过配置文件中的前缀来进行自动注入


Person.class:


@Component
//这里是设置对应配置文件中的前缀名
@ConfigurationProperties(prefix = "person")
//默认加载xxx.properties类型的配置文件,不能加载YML格式的配置文件,这里是直接指定对应的properties文件
@PropertySource("classpath:changlu.properties")
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birthday;
    private Map<String, Object> maps;
    private List<Object> lists;
    private Dog dog;
    ...空/有参,set/get方法
}



changlu.properties:


person.name=changlu
person.age=18
person.happy=false
person.birthday=2001/07/21
person.lists[0]=cat
person.lists[1]=dog
person.lists[2]=monkey
person.dog.name=hashiqi
person.dog.age=10
person.maps[k1]=v1
person.maps[k2]=v2


2、yaml配置(推荐)

格式说明

yaml结构更加清晰,也是普通key: value键值对,对于:后的空格比较严格。


通过空格的缩进来控制层级关系,只要空格对齐则视为同一个级别,不能使用tab来代替空格。


大小写敏感,支持字面值,对象,数组三种数据结构,也支持复合结构


类型说明:


字面值:例如字符串(不加引号,单引号会转义字符)、布尔类型、数值、日期(支持yyyy/MM/dd HH:mm:ss)。

对象:键值对组成,如key: value形式,:后必须有空格,每组键值对占用一行可以使用行内写法{k1: v1,k2: v2}

数组:使用- value形式组成,-后必须有空格,行内写法为[v1,v2,v3]

复合结构:上面三组结构可以任意组合

yaml中格式:


# 字面量
name: changlu
date: 2020/12/21 14:17:20
# 字面量第二种方式
age:
 - 123
# 对象
student:
  name: changlu
  age: 15
# 对象的行内写法
student: {name: changlu,age: 15}
# 数组
pets:
  - cat
  - dog
  - pig
# 数组的行内写法
pets: [cat,dog,pig]
# map的行内写法  对应Map<String,Object> map
map: {k1: v1,k2: v2}
# List写法  对应List<String> list
list:
  - one,
  - two,
  - three



对应配置文件的实体类需要加上@Data以及@ToString



属性赋值

方式一:通过注解来进行赋值,通过@Value来进行赋值


@Component
public class Dog {
    @Value("旺财")
    private String name;
    @Value("3")
    private Integer age;
    无参/有参构造
    set/get方法
    toString()方法
}



方式二:对于一些配置来说,我们通过使用yaml来与实体类(组件)进行绑定值


注意你的pojo目录应当与启动类再同一个目录里



Person.class :


@Component  //创建bean实例
@ConfigurationProperties(prefix = "person") //通过找到application.yaml中person下的所有属性内容进行赋值
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birthday;
    private Map<String, Object> maps;
    private List<Object> lists;
    private Dog dog;
    ...无参/有参 set/get方法
}



application.yaml:


person:
  name: changlu
  age: 18
  happy: false
  birthday: 2001/07/21
  maps: {k1: v1,k2: v2}
  lists:
    - cat
    - dog
    - monkey
  dog:
    name: hashiqi
    age: 10



问题:若是使用@ConfigurationProperties注解出现Generating Your Own Metadata by Using the Annotation Processor,


我们可以到对应官网查看解答:configuration-metadata-annotation-processor


解决:在pom.xml中配置,可能需要重启IDEA即可


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>



yaml其他使用方式

我们可以在yaml文件中使用一些类如${}的springEL表达式来进行配置文件:


person:
  name: changlu${random.uuid}  # 可以使用spring的el表达式来自由设置
  age: ${random.int}
  happy: false
  birthday: 2001/07/21
  maps: {k1: v1,k2: v2}
  lists:
    - cat
    - dog
    - monkey
  dog:
    name: ${person.hello:hello}_wangcai  # 相当于三目运算符,若是不存在person,hello那么结果为hello_wangcai
    age: 10


结果:Person{name='changlubdde2a48-d5d4-49b2-a8a8-b9720b2c8539', age=-1136254345, happy=false, birthday=Sat Jul 21 00:00:00 CST 2001, maps={k1=v1, k2=v2}, lists=[cat, dog, monkey], dog=Dog{name='hello_wangcai', age=10}}



两个注入注解的比对说明



@ConfigurationProperties:批量注入


底层使用set方法来进行注入的,通过spring的前置处理器。


application.yml:


changlu:
  id: 18
  name: changlu
  url: https://e2tfu6fqrn.feishu.cn/docs/doccn0ZiE8u2oZ6OmPeBJP9lVec


自定义实体类:


@Component
@ConfigurationProperties(prefix = "changlu")  //根据前缀来进行批量注入
@ToString
@Setter
public class TestUser {
    private Integer id;
    private String name;
    private String url;
}
//测试
@SpringBootTest
class TestApplicationTests {
    @Autowired
    private TestUser testUser;
    @Test
    public void testSelect() {
        System.out.printf(testUser.toString());
    }
}





@Value:单个注入


底层是通过反射来注入到属性中的,在@ConfigurationProperties注入方式之前进行。


若是两个注解同时使用注入不同的数据内容,那么由于@ConfigurationProperties底层注入方式后注入,得到的结果就是@ConfigurationProperties对应注入值。(已进行测试)

yml配置属性就使用上面的。


@Component
@ToString
public class TestUser {
    @Value("${changlu.id}")
    private Integer id;
    @Value("${changlu.name}")
    private String name;
    @Value("${changlu.url}")
    private String url;
}
//测试
@SpringBootTest
class TestApplicationTests {
    @Autowired
    private TestUser testUser;
    @Test
    public void testSelect() {
        System.out.printf(testUser.toString());
    }
}


结论


通过上面实践,我们无论是使用yaml还是properties都可以通过一定的方法来获取到值,强烈推荐使用yaml。


情况1:若是我们在某个业务中,需要获取配置文件中的某个值,那么可以使用@Value()来确定单个属性值


情况2:若我们专门编写了一个JavaBean和配置文件进行映射,就直接使用@ConfigurationProperties!



3、JSR303数据校验

介绍及导入

@Validated:如果数据异常则会统一抛出异常,方便异常中心统一处理


使用@Validated注解,来开启下面的注解的使用:


pom.xml中导入依赖:


<!--导入JSR303校验相关的jar包-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>



常用功能介绍如下



实际使用(@Email)

这里我们使用@Email来进行检验一下


@Component
@ConfigurationProperties(prefix = "person")
@Data
@ToString
@Validated //数据校验
public class Person {
    @Email
    private String name;
    private Integer age;
    private Boolean happy;
    ...set/get方法  无/有参构造  toString()方法
}


Application.yaml:


person:
  name: changlu${random.uuid}  # 可以使用spring的el表达式来自由设置
  age: ${random.int}
  happy: false


运行一下,看到校验的结果:



我们也可以自定义对应的提示信息,如@Email(message="您输入的不是合法的邮件地址!")



IDEA的FileEncoding问题

设置Settings中的File Encodings中的Encoding为UTF-8格式:防止之后打开项目中的配置文件有乱码情况



六、配置优先级及多环境配置


1、配置优先级

springboot启动会扫描对应下方位置的application.properties或者yaml文件作为springboot的默认配置文件


我们可以在项目的不同位置来进行配置springboot的配置文件,如下:classpath


The classpath root

The classpath /config package

The current directory

The /config subdirectory in the current directory

Immediate child directories of the /config subdirectory

具体说明可以见springboot官网:External Application Properties


说明:classpath指代三个路径 src/main/java src/main/resource 第三方jar包路径;directory指的就是项目


对于配置文件我们对于classpath一般都是放置在src/main/resource目录下的。


测试:我们将配置文件设置在不同的目录下设置不同的端口号来进行优先级测试,这里仅仅使用yaml配置文件,properties配置文件同理


测试后优先级如图:



总结:


无论你是使用yaml还是properties在不同目录下其优先级与上图相同;

若是在同一个目录下有properties与yaml配置文件,yaml配置文件更加优先!

2、多环境配置

目的:对应实际开发中,我们对于一个项目会在多个环境下运行,如普通环境,测试环境,生产环境,那么我们应当事先进行多环境配置,根据对应环境来进行选择配置。


properties配置文件

此时我们对应多个环境准备了多个配置文件,那么如何进行配置来进行选择相应的配置文件呢?



我只要在properties中使用spring.profiles.active来进行动态加载对应配置文件,其值为application-xxx.properties后的xxx即可


server.port=8091
# 使用的是application-test.properties配置文件
spring.profiles.active=test

缺点:需要多个配置文件占空间


yaml配置文件



对于yaml我们只需要一个配置文件中设置即可,通过使用---来作为分隔表示为多版本:


其中spring.profiles.active用来动态加载对应环境的配置,这里加载的就是下面的环境
server:
  port: 8091
spring:
  profiles:
    active: dev
---
server:
  port: 8092
spring:
  config:
    activate:
      on-profile: dev
---
server:
  port: 8093
spring:
  config:
    activate:
      on-profile: test



说明:在设置其他环境配置出现这个标志,原因是我们现在使用的是springboot 2.4.1版本,这个方式已经弃用,应当使用上面的最佳写法来设置环境名称。可查看文档:Config file processing in Spring Boot 2.4



七、自动装配原理


探索spring.factories

我们从spring.factories中进行探究其中的原理



我们选择其中的一个Configuraction来进行分析:



// 表示一个配置类,都会被spring接管配置
@Configuration(proxyBeanMethods = false)
// 自动配置属性
@EnableConfigurationProperties(ServerProperties.class)
// spring的底层注解,根据不同的条件,判断当前配置或者类是否生效,下面能够使用许多@ConditionalOnxxx的注解
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
// 系统中是否有指定的类
@ConditionalOnClass(CharacterEncodingFilter.class)
//系统中指定的属性是否有值
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
  ...
}


我们点进上面@EnableConfigurationProperties(ServerProperties.class)中的ServerProperties.class类中查看:


@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
   /**
    * Server HTTP port.
    */
   private Integer port;
   /**
    * Network address to which the server should bind.
    */
   private InetAddress address;
   ...
}


能够注意到该类使用了@ConfigurationProperties注解,是用来将对应配置文件的前缀的属性自动装配到类中的属性中去


我们看一下还有哪些@Conditional扩展注解



简而言之:


也就是说我们在配置文件中配置的一些值,其实是本来就写好的一个配置文件,在springboot程序启动时会首先默认加载那些配置类,接着那些配置类会去加载对应的配置文件,而我们之后仅仅只需要更改对应配置文件的值即可!!!!


通俗点就是我们原先需要在bean中手打的属性(property)封装成一个类,然后通过yaml文件注入,而我们在application.yaml文件中自定义这些property属性


精髓:


springboot启动会加载大量的自动配置类

我们看我们所需要的功能有没有在SpringBoot默认写好的自动配置类当中

我们再来看这个自动配置类中到底配置了那些组件(若是要用的组件存在其中,我们就不需要手动来配置)

在容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可!

xxxAutoConfiguration:自动配置类,用于给容器中添加组件


xxxProperties:封装配置文件中相关属性,与对应类来进行绑定


debug=true使用

在yaml中配置查看详细的自动配置报告,启动时看到日志输出,哪些自动配置类生效,哪些没有生效。



debug: true


启动程序来进行查看配置是否生效的日志信息:


============================
CONDITIONS EVALUATION REPORT
============================
# 第一类:已经配置且生效的配置类
Positive matches:
-----------------
   AopAutoConfiguration matched:
      - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
   AopAutoConfiguration.ClassProxyingConfiguration matched:
      - @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition)
      - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)
   DispatcherServletAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet' (OnClassCondition)
      - found 'session' scope (OnWebApplicationCondition)
   DispatcherServletAutoConfiguration.DispatcherServletConfiguration matched:
      # 表示已经找到
      - @ConditionalOnClass found required class 'javax.servlet.ServletRegistration' (OnClassCondition)
      - Default DispatcherServlet did not find dispatcher servlet beans (DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition)
...
# 第二类:没有匹配到,未生效的
Negative matches:
-----------------
   ActiveMQAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
   AopAutoConfiguration.AspectJAutoProxyingConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'org.aspectj.weaver.Advice' (OnClassCondition)
...
# 其余除外的类
Exclusions:
-----------
    None
# 无条件的类
Unconditional classes:
----------------------
    org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
相关文章
|
8月前
|
XML Java Spring
SpringBoot2.0入门(详细文档)(下)
SpringBoot2.0入门(详细文档)(下)
SpringBoot2.0入门(详细文档)(下)
|
1月前
|
Java Docker 容器
美团大牛精心整理SpringBoot学习笔记,从Web入门到系统架构
近期慢慢复工,为了准备面试,各路码友们都开始磨拳擦脚,背面试题、知识点。小编最近得一良友赠送了一份关于SpringBoot的学习笔记,简直不要好用,理论解析言简意赅,每一步操作都有图片展示。这么好的东西肯定不能私藏,为了感谢大家在2019年里的支持,我现在将这份笔记赠送给大家,祝大家前程似锦,Offer不断!
|
8月前
|
Java Go 开发者
Spring Boot 简介与入门
Spring Boot 简介与入门
60 0
|
8月前
|
SQL 存储 开发框架
SpringBoot2.0入门(详细文档)二
SpringBoot2.0入门(详细文档)二
|
8月前
|
Java 关系型数据库 MySQL
[笔记]Springboot入门《一》springboot+jpa+bootstrap+crud
[笔记]Springboot入门《一》springboot+jpa+bootstrap+crud
|
8月前
|
Java 测试技术 Maven
SpringBoot2.0入门(详细文档)(上)
SpringBoot2.0入门(详细文档)(上)
|
2天前
|
Java 关系型数据库 MySQL
Mybatis入门之在基于Springboot的框架下拿到MySQL中数据
Mybatis入门之在基于Springboot的框架下拿到MySQL中数据
12 4
|
2天前
|
Java 应用服务中间件 Maven
Springboot入门基础知识详解 parent starter 引导类 辅助功能
Springboot入门基础知识详解 parent starter 引导类 辅助功能
9 2
|
2天前
|
Java 程序员
浅浅纪念花一个月完成Springboot+Mybatis+Springmvc+Vue2+elementUI的前后端交互入门项目
浅浅纪念花一个月完成Springboot+Mybatis+Springmvc+Vue2+elementUI的前后端交互入门项目
15 1
|
1月前
|
安全 Java 数据库连接
在IntelliJ IDEA中通过Spring Boot集成达梦数据库:从入门到精通
在IntelliJ IDEA中通过Spring Boot集成达梦数据库:从入门到精通
178 6