文章目录
- SpringBoot高级特性
- 1、Profile
- 1.1、定制我们不同环境下的配置文件
- 1.2、定制我们不同环境下的类和方法
- 1.3、Profile分组
- 2、外部化配置
- 2.1 SpringBoot常用外部化配置源
- 2.2 SpringBoot配置源的优先级
- 2.2 SpringBoot配置文件的查找顺序和加载顺序
- 3、自定义我们自己的starter
SpringBoot高级特性
1、Profile
1.1、定制我们不同环境下的配置文件
Profile主要用于环境切换。让我们在不同的环境下(比如测试和生产环境)能快速地切换所需的配置等等。
怎么用呢?首先,新建一个Controller如下:
package com.example.boot.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
/**
* @Value注解中加${}用于获取yaml文件的值,取不到则用默认值李四
*/
@Value("${person.name: 李四}")
private String name;
@GetMapping("/hello")
public String toHello(){
return "Hello, "+ name;
}
}
然后写生产环境下的yaml文件和测试环境下的yaml文件。(可以通过-prop和-test来区别)
application-prop.yaml
person:
name: prop-张三
application-test.yaml
person:
name: test-张三
此时运行结果:(因为默认读取的是application.yaml,而在application.yaml中,我们并没有配置person.name的值)
那么,我们怎么让他去读取我们的test或者prop后缀的yaml文件呢?简单。在我们的application.yaml文件中,我们配置下面这个属性的值为test,就读取application-test.yaml文件,赋值prop,就读取application-prop.yaml文件。
spring:
profiles:
active: test
比如我们设置他为test,那么,此时我们的结果为:
注意:
1、环境配置与默认配置是同时生效的。换言之,如果是在默认环境中配的属性,那么所有的环境都生效。
2、如果同一个属性在默认配置和环境配置中都配置的话,那么优先使用环境配置的属性。
1.2、定制我们不同环境下的类和方法
我们还可以通过@Profile注解为我们不同的环境配置不同的类或方法。
这里,我们以类为例,方法其实也一样,就是@Profile加在类上还是方法上的区别而已:
先写一个Person接口
package com.example.boot.bean;
public interface Person {
public String getName();
public Integer getAge();
}
然后写两个类:Boss和Worker分别实现Person。
1、@Profile(“prop”):用来配置他属于哪个环境
2、@ConfigurationProperties(“person”):用来告诉SpringBoot,他跟配置文件的哪个属性捆绑在一起。
Boss.java
package com.example.boot.bean;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Profile("prop")
@Data
@Component
@ConfigurationProperties("person")
public class Boss implements Person{
private String name;
private Integer age;
}
Worker.java
package com.example.boot.bean;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties("person")
@Profile("test")
public class Worker implements Person{
private String name;
private Integer age;
}
之后,我们给我们的配置文件添加age属性(也可以不加,不加的话age就是null)
application-prop.yaml
person:
name: prop-张三
age: 28
application-test.yaml
person:
name: test-张三
age: 18
然后修改我们的Controller方法:(注入Person并返回,如果没有配置环境的话,其实他是会报错的,因为Person接口有两个实现类。)
package com.example.boot.controller;
import com.example.boot.bean.Person;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class HelloController {
@Resource
private Person person;
@GetMapping("/hello")
public Person toHello(){
return person;
}
}
结果:
1.3、Profile分组
有些时候,我们的环境配置文件可能还不止一个。这个时候,我们就可以对他们进行分组。
情景假设:
假如现在,我们的生产环境要引用的环境配置文件有application-prod.yaml和application-haha.yaml,而我们的测试环境要引用的环境配置文件有application-test.yaml。那么,我们在生产环境下就可以这么用。
spring:
profiles:
#激活的配置文件为myProd
active: myProd
#分组,一个叫myProd,一个叫myTest。其中,prod包括prop和haha两个环境
group:
myProd: ['prop','haha']
myTest: test
2、外部化配置
什么是外部化配置呢?举个实例吧,以前在学Spring的时候,我们写过一个jdbc.properties文件,这个jdbc.properties就是外部化配置文件。
2.1 SpringBoot常用外部化配置源
那么,我们SpringBoot中常用的外部化配置源都有哪些呢?
1、Java属性文件(properties)
2、Yaml文件
3、环境变量(系统或者用户的环境变量)
4、命令行参数
2.2 SpringBoot配置源的优先级
Spring Boot 使用一个非常特殊的PropertySource顺序,旨在允许合理地覆盖值。属性按以下顺序考虑(下面是他们的优先级,且优先级低的可以覆盖优先级高的配置):
- 默认属性(由 setting 指定SpringApplication.setDefaultProperties)。
- @PropertySource你的@Configuration类的注释。请注意,Environment在刷新应用程序上下文之前,不会将此类属性源添加到。现在配置某些属性(例如在刷新开始之前读取的logging.和)为时已晚spring.main.。
- 配置数据(如application.properties文件)最常用
- 一RandomValuePropertySource,只有在拥有性能random.*。
- 操作系统环境变量。
- Java 系统属性 ( System.getProperties())。
- JNDI 属性来自java:comp/env.
- ServletContext 初始化参数。
- ServletConfig 初始化参数。
- 来自SPRING_APPLICATION_JSON(嵌入在环境变量或系统属性中的内联 JSON)的属性。
- 命令行参数。
- properties属性在您的测试中。可用于测试应用程序的特定部分@SpringBootTest的测试注释。
- @TestPropertySource 测试中的注释。
- $HOME/.config/spring-boot当 devtools 处于活动状态时,目录中的Devtools 全局设置属性。
2.2 SpringBoot配置文件的查找顺序和加载顺序
配置文件的查找顺序:
- classpath 根路径
- classpath 根路径下的config目录
- jar包当前目录
- jar包当前目录的config目录
- /config 的一级子目录
配置文件的加载顺序:(后面加载的会覆盖前面同名的加载项)
- 当前jar包内部的application.properties和application.yaml
- 当前jar包内部的application-{profile}.properties和application-{profile}.yaml
- 引用的外部jar包的application.properties和application.yaml
- 引用的外部jar包的application-{profile}.properties和application-{profile}.yaml
3、自定义我们自己的starter
先创建一个空项目(空项目可以放多个springboot的moodle)
然后我们整个maven模块:
这个moodle就按照Springboot官方规定的第三方starter的命名格式来:thirdpartyproject-spring-boot-starter
然后我再创建一个Moodle:这个Moodle以SpringInitializr来创建:(无需自动导入任何的依赖)
完成后,我们在hello场景的依赖导入hello-configure场景,将我们的配置都写在hello-configure中即可:
由于我们的hello-configure不单独启动,所以,我们可以删掉他的test场景和他的插件(蓝色区域都可以删掉):
test文件夹以及他给我们的类和配置文件也都可以删了。
然后我们可以写我们的业务逻辑代码:
比如我们经常用这个HelloService组件,他的sayHello方法可以通过自定义前后缀的方式,对传入的name值进行问候。
HelloService.class
package com.example.hellospringbootstarterautoconfigure.service;
import com.example.hellospringbootstarterautoconfigure.properties.HelloProperties;
import javax.annotation.Resource;
public class HelloService {
@Resource
HelloProperties properties;
public String sayHello(String name){
return properties.getPrefix() + name + properties.getSuffix();
}
}
然后我们就写一下他的绑定类(Properties)
HelloProperties.class
package com.example.hellospringbootstarterautoconfigure.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties("hstc.hello")
public class HelloProperties {
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
最后,我们模仿以前那些场景,写一下他的自动配置类:
HelloServiceAutoConfiguration.class
package com.example.hellospringbootstarterautoconfigure.auto;
import com.example.hellospringbootstarterautoconfigure.properties.HelloProperties;
import com.example.hellospringbootstarterautoconfigure.service.HelloService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
//没有HelloService类的时候,该配置才生效
@ConditionalOnMissingBean(HelloService.class)
//绑定我们的HelloProperties
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
@Bean
public HelloService helloService(){
HelloService helloService = new HelloService();
return helloService;
}
}
最后,我们在resource目录下新建一个META-INF的文件夹,放我们的spring.factories,并加入以下代码,让SpringBoot默认加载我们的配置类:
#自动配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.hellospringbootstarterautoconfigure.auto.HelloServiceAutoConfiguration
完成后,咱们就可以打包了,使用clean,然后install将他放到我们的本地仓库。
将我们的hello场景也放入仓库:
接下来,我们再新建一个Moodle,这个是我们的实际的开发场景。
整一个Web开发场景。
此时,我们的hello场景和hello-configure场景已经在我们的仓库中了。我们只需要在我们的开发场景demo中引入就可以直接用他了。(注意引入的是hello场景不是hello-configure场景)
<dependency>
<groupId>org.example</groupId>
<artifactId>hello-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
然后我们在我们的配置文件中,配置我们刚才的prefix和suffix:
hstc.hello.prefix= Dear
hstc.hello.suffix= , Nice to meet you!!!
然后我们写我们的控制器方法来看看刚才那个能不能用:
package com.example.demo.controller;
import com.example.hellospringbootstarterautoconfigure.service.HelloService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class HelloController {
@Resource
HelloService helloService;
@GetMapping("/hello")
public String sayHello(){
return helloService.sayHello("张三");
}
}
启动我们SpringBoot的主程序,我们来看下运行结果: