Spring Boot深入系列--配置文件

SpringBoot


开发环境:

  • win10
  • jdk1.8
  • idea2019
  • maven 3.2.5
  • Spring Boot v2.1.5.RELEASE (版本)

SpringBoot的配置文件

1. yml文件的语法概览:

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

person:
lastNAME: carson
age: 18
boss: true
birth: 1234/12/12
#map写法: {k: v,k2: v2}
maps: {k1: v1,k2: v2}
#数组写法: -值
lists:
- lisi
- zhangsan
- wangwu
- zhaoliu
dog:
name: 小狗
age: 3

spring:
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
datasource:
url: jdbc:mysql:///ssm
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
jpa:
hibernate:
ddl-auto: update

server:
port: 9090

2. @Value获取值和 @ConfigurationProperties获取值比较

@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个个指定
松散绑定(松散语法)大小写 支持 不支持
SpEL表达式 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持

这两种方式都能获取值:

  • 如果,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value
  • 如果,我们专门编写了一个javaBean来和配置文件进行映射;@ConfigurationProperties

@Validated

@Value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Getter@Setter
@ToString
@Component
//@ConfigurationProperties (prefix = "person")
@Validated // 来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。
public class Person {

// @Email
@Value("${person.lastNAME}")
private String lastNAME;
@Value("#{3*3}")
private Integer age;
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;

private Dog dog;
}

3. @PropertySource&@ImportResource

因为 @ConfigurationProperties 是全局注解,如果想指定的话

  • @PropertySource:可以指定某个文件 @PropertySource(“classpath: xxx.properties)

@ImportResource: 导入Spring配置文件,让配置文件里面的内容生效

  • 创建一个HelloService 类
    • 如果没有注解情况下
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="helloService" class="com.carson.springboot.service.impl.HelloService"></bean>
</beans>
1
2
3
4
5
6
7
8
9
@Autowired
ApplicationContext ioc;

@Test
public void testHelloService(){
// 是否是包含 这个 bean
boolean b = ioc.containsBean("helloService");
System.out.println(b);//false
}

false 说明Spring Boot 里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别

如果想让Spring的配置文件生效,加载进来; 就 把@ImportResource标注在一个配置类上

  • 主类
1
2
3
4
5
6
7
8
9
@ImportResource(locations = {"classpath:beans.xml"})
@SpringBootApplication
public class SpringbootApplication {

public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}

}
1
2
3
4
5
6
7
8
9
@Autowired
ApplicationContext ioc;

@Test
public void testHelloService(){
// 是否是包含 这个 bean
boolean b = ioc.containsBean("helloService");
System.out.println(b);//true
}

SpringBoot推荐给容器中添加组件的方式:

使用 @Bean

  • 1, 配置类======Spring配置文件
    • 建一个包 config,专门放配置类:MyAppConfig
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15

      /**
      * @Configuration: 指明当前类是一个配置类;就是来代替之前的Spring配置文件
      *
      * 以前配置文件总 用 <bean></bean> 标签添加组件
      */
      @Configuration
      public class MyAppConfig {

      // 将方法的返回值添加到容器中,容器中这几个组件默认的id就是方法名
      @Bean
      public HelloService helloService(){
      return new HelloService();
      }
      }

记得把之前主类的@ImportResource注解 去掉!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
输出结果:

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.5.RELEASE)

2019-06-29 16:53:48.081 INFO 11084 --- [ main] c.c.s.SpringbootApplicationTests : Starting SpringbootApplicationTests on DESKTOP-JBSD6AK with PID 11084 (started by My in F:\code\springboot)
2019-06-29 16:53:48.083 INFO 11084 --- [ main] c.c.s.SpringbootApplicationTests : No active profile set, falling back to default profiles: default
2019-06-29 16:53:52.689 INFO 11084 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-06-29 16:53:53.988 INFO 11084 --- [ main] c.c.s.SpringbootApplicationTests : Started SpringbootApplicationTests in 7.259 seconds (JVM running for 10.759)
true
2019-06-29 16:53:54.433 INFO 11084 --- [ Thread-3] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'

也是 true

4. 配置文件里的 ${}

random随机数

1
2
3
4
5
${random.value}
${random.int}
${random.long}
${random.int(10)}
${random.int[1024,65536]}

${} 获取 之前配置的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
person:
lastNAME: bob${random.uuid}
age: ${random.int}
boss: true
birth: 1234/12/12
maps: {k1: v1,k2: v2}
lists:
- lisi
- zhangsan
- wangwu
- zhaoliu
dog:
name: ${person.lastNAME}_dog
age: 3

如果

1
2
  dog:
name: ${person.lastNAME}_dog

如果lastNAME没有的话, 那就

1
2
  dog:
name: ${person.lastNAME:hello}_dog

5. Profile

5.1 多个Profile 文件

Profile是Spring对不同环境提供不同配置功能的支持,可以通过指定参数等方式快速切换环境

比如我配置3个端口,一个默认的,一个dev(开发),一个prod(测试)

主配置文件名可以是 application.yml/application.properties

默认使用application.yml的配置;

5.2 yml的多文档块

以 — 分隔 文档快

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
spring:
profiles:
active: dev

server:
port: 9090
---

server:
port: 9091
spring:
profiles: dev
---

server:
port: 9092
spring:
profiles: prod
  • active:是指定哪个文档快
  • profiles: 指定一个名称,让active识别的

5.3 激活指定profile

1, 在配置文件中指定 spring.profiles.active=dev

2, 命令行:

idea功能栏中的 run > edit > program arguments 添加上

–spring.profiles.active=prod

–spring.profiles.active=dev

3,cmd中 将 项目打成 jar包

java -jar (jar包名) –spring.profiles.active=prod

4, 虚拟机 参数:

idea功能栏中的 run > edit >VM options 添加上

-Dspring.profiles.active=prod/dev


6.Spring Boot配置文件的加载位置

Spring Boot 启动会扫描以下位置的application.yml或application.properties文件作为默认配置文件

  • file: ./config/
  • file: ./
  • classpath: ./config/
  • classpath: /

以上是按照优先级从高到低的顺序,所有的配置文件都会被加载,高优先级配置会覆盖 低优先级配置

file : 跟src平级的目录

classpath: resources目录下的

我们也可以通过配置spring.config.location来改变默认配置文件位置:

1.将项目打包

2.命令行格式: java -jar 包名 –spring.config.location= F:/app/application.properties(配置文件绝对路径)

项目打包之后可能后来会需要修改一些配置,就可以使用这种方式,并且旧配置还会存在,新配置也会应用上

7.外部配置加载顺序

SpringBoot也可以从以下位置加载配置,优先级从高到低,高优先级覆盖低优先级,如果有不同的配置,就会形成互补

  1. 命令行参数

    java -jar xxx.jar –server.port=8081 –xxx

    多个配置用空格分开: –xxx –xxx

  2. 来自java:comp/env的NDI属性

  3. Java系统属性(System.getProperties())

  4. 操作系统环境变量

  5. RandomValuePropertySource配置的random.*属性值

由jar包外向jar包内进行寻找:

优先加载带profile的

  1. jar包”外”部的application-{profile}.properties或application.yml(带spring.profile)的配置文件
  2. jar包’’内’’部的application-{profile}.properties或application.yml(带spring.profile)的配置文件

再来加载不带profile的

  1. jar包’’外’’部的application.properties或application.yml(不带spring.profile)的配置文件
  2. jar包’’内’’部的application.properties或application.yml(不带spring.profile)的配置文件

还有其他的:

  1. @Configuration注解类上的@PropertySource
  2. 通过SrpingApplication.setDefaultProperties指定默认属性

    详情参考官网文档的第 24章

8.自动配置原理(重点)

自动配置到底能些什么?怎么写?自动配置原理:

文档地址

查看目录最后一章 X. Appendices官方文档

这里面说明了都有哪些配置项

其实:

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

xxxxAutoConfigurartion: 自动配置类;

给容器中添加组件

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

技巧:

idea双击Shift,搜索 *AutoConfiguration

carson

点开缓存相关的自动配置

我们将会看到以下源码:

1
2
3
4
5
6
@EnableConfigurationProperties({CacheProperties.class})
@AutoConfigureAfter({CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class, HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class})
@Import({CacheAutoConfiguration.CacheConfigurationImportSelector.class})
public class CacheAutoConfiguration {
public CacheAutoConfiguration() {
}

ctrl+鼠标左键点击:

1
2
@EnableConfigurationProperties({CacheProperties.class})
//点击 CacheProperties

我们会看到在CacheProperties类上:

1
2
3
4
@ConfigurationProperties(
prefix = "spring.cache"
)
public class CacheProperties {

prefix = “spring.cache” : 就是在yml/properties配置文件的语法前缀

至于能配置哪些具体东西?

就是这些

carson

或者你可以利用idea的代码提示在配置文件里,比如我调用 第一个getType

carson

这就是通过源码的方式,来了解到我们可以在配置文件里配置什么东西

比如我想连接数据库,我来搜索一下

carson

carson

carson

我看到了我们的需要的字段,以及下面很多的方法(这里就不截图了)

carson

接下来就是到配置文件配置了:

carson

9.细节

@Conditional派生注解

carson

我发现源码中有很多的 @ConditionalOn***

它其实就是利用Spring底层的 @Conditional注解

作用: 必须是 @Conditional 指定的条件成立,才给容器中添加组件,配置类里面的内容才会生效,如果返回false那么,你配的东西都不会生效的

SpringBoot 扩展了 @Conditional注解 比如:

carson

所以其实自动配置类必须在一定的条件下才能生效

我们该怎么知道哪些类生效哪些没生效呢?很简单,在配置文件里添加:

1
debug: true

然后运行我们的朱类:

​ 我们会看到:

 carosn

还有:

carosn

都会在控制台打印输出

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×