SpringBoot——高级特性
1. Profile功能
为了方便多环境适配,SpringBoot简化了profile功能。
Ⅰ. application-profile功能
-
默认配置文件
application.yaml
任何时候都会加载。 -
指定环境配置文件
application-{env}.yaml
application-test.yaml
person: name: test-张三 server: port: 7000
application-prod.yaml
person: name: prod-张三 server: port: 8000
-
激活指定环境
➢ 配置文件激活
application.properties
# 激活prod配置文件(指定激活的环境,默认配置文件和指定环境的配置文件都会生效) spring.profiles.active=prod
➢ 命令行激活:
java -jar xxx.jar --spring.profiles.active=prod --person.name=haha
◽️ 修改配置文件的任意值,命令行优先
-
默认配置与环境配置同时生效
-
同名配置项,profile配置优先
Ⅱ. @Profile条件装配功能
public interface Person {
String getName();
Integer getAge();
}
@Profile("test") // 加载application-test.yaml里的
@Component
@ConfigurationProperties("person")
@Data
public class Worker implements Person {
private String name;
private Integer age;
}
@Profile(value = {"prod", "default"}) // 加载application-prod.yaml里的
@Component
@ConfigurationProperties("person")
@Data
public class Boss implements Person {
private String name;
private Integer age;
}
Controller
@RestController
public class HelloController {
@Autowired
private Person person;
@GetMapping("/")
public String hello() {
return person.getClass().toString();
}
}
@Profile
还可以修饰在方法上
class Color {
}
@Configuration
public class MyConfig {
@Profile("prod") // 标志在方法上 指定的环境 这个方法组件才生效
@Bean
public Color red() {
return new Color();
}
@Profile("test")
@Bean
public Color green() {
return new Color();
}
}
Ⅲ. Profile分组
spring.profiles.active=production
spring.profiles.group.production[0]=proddb
spring.profiles.group.production[1]=prodmq
# 使用:--spring.profiles.active=production 激活
2. 外部化配置
官方文档 - Externalized Configuration
Spring Boot使用一个非常特殊的PropertySource顺序,该顺序旨在允许合理地重写值。属性按以下顺序考虑(较低项的值优先于较早项的值):
- Default properties (specified by setting
SpringApplication.setDefaultProperties
). @PropertySource
annotations on your@Configuration
classes. Please note that such property sources are not added to theEnvironment
until the application context is being refreshed. This is too late to configure certain properties such aslogging.*
andspring.main.*
which are read before refresh begins.- Config data (such as
application.properties
files) - A
RandomValuePropertySource
that has properties only inrandom.*
. - OS environment variables.
- Java System properties (
System.getProperties()
). - JNDI attributes from
java:comp/env
. ServletContext
init parameters.ServletConfig
init parameters.- Properties from
SPRING_APPLICATION_JSON
(inline JSON embedded in an environment variable or system property). - Command line arguments.
properties
attribute on your tests. Available on@SpringBootTest
and the test annotations for testing a particular slice of your application.@TestPropertySource
annotations on your tests.- Devtools global settings properties in the
$HOME/.config/spring-boot
directory when devtools is active.
为了提供一个具体示例,假设您开发了一个使用name
属性的@
组件,如以下示例所示:
import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
}
Ⅰ. 外部配置源
Spring Boot允许您将配置外部化,以便您可以在不同的环境中使用相同的应用程序代码。
您可以使用各种外部配置源,包括 Java properties文件
、YAML文件
、环境变量
和 命令行参数
。
Ⅱ. 配置文件查找位置
Spring Boot将自动查找并加载应用程序、特性和应用。应用程序启动时,来自以下位置的yaml文件:
- classpath 根路径。
- classpath 根路径下config目录。
- jar包当前目录。
- jar包当前目录的config目录。
- /config子目录的直接子目录(Linux系统中)。
列表按优先级排序(较低项的值优先于较早项)。加载文件中的文档作为PropertySources
添加到Spring环境中。
Ⅲ. 配置文件加载顺序
- 当前jar包内部的
application.properties
和application.yml
。 - 当前jar包内部的
application-{profile}.properties
和application-{profile}.yml
。 - 引用的外部jar包的
application.properties
和application.yml
。 - 引用的外部jar包的
application-{profile}.properties
和application-{profile}.yml
。
指定环境优先,外部优先,后面的可以覆盖前面的同名配置项。
3. 自定义starter
Ⅰ. starter启动原理
- starter的pom.xml引入autoconfigure依赖包
-
autoconfigure包中配置使用
META-INF/spring.factories
中EnableAutoConfiguration
的值,使得项目启动加载指定的自动配置类 -
编写自动配置类
xxxAutoConfiguration
=>xxxxProperties
➢
@Configuration
➢
@Conditional
➢
@EnableConfigurationProperties
➢
@Bean
➢ …
-
引入starter —
xxxAutoConfiguration
— 容器中放入组件 ----绑定xxxProperties
---- 配置项
Ⅱ. 自定义starter
-
目标:创建
HelloService
的自定义starter。 -
创建两个工程,分别命名为
hello-spring-boot-starter
(普通Maven工程),hello-spring-boot-starter-autoconfigure
(需用用到Spring Initializr创建的Maven工程)。 -
hello-spring-boot-starter
无需编写什么代码,只需让该工程引入hello-spring-boot-starter-autoconfigure
依赖:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.atguigu</groupId> <artifactId>hello-spring-boot-starter</artifactId> <version>1.0.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>com.atguigu</groupId> <artifactId>hello-spring-boot-starter-autoconfigure</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> </dependencies> </project>
-
hello-spring-boot-starter-autoconfigure
的pom.xml如下:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.atguigu</groupId> <artifactId>hello-spring-boot-starter-autoconfigure</artifactId> <version>1.0.0-SNAPSHOT</version> <name>hello-spring-boot-starter-autoconfigure</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> </dependencies> </project>
-
创建4个文件:
➢
com/atguigu/hello/auto/HelloServiceAutoConfiguration
import com.atguigu.hello.bean.HelloProperties; import com.atguigu.hello.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 @EnableConfigurationProperties(HelloProperties.class) // 默认HelloProperties放在容器中 public class HelloServiceAutoConfiguration { @ConditionalOnMissingBean(HelloService.class) @Bean public HelloService helloService(){ return new HelloService(); } }
➢
com/atguigu/hello/bean/HelloProperties
import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("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; } }
➢
com/atguigu/hello/service/HelloService
import com.atguigu.hello.bean.HelloProperties; import org.springframework.beans.factory.annotation.Autowired; /** * 默认不要放在容器中 */ public class HelloService { @Autowired private HelloProperties helloProperties; public String sayHello(String userName) { return helloProperties.getPrefix() + ": " + userName + " > " + helloProperties.getSuffix(); } }
➢
src/main/resources/META-INF/spring.factories
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.atguigu.hello.auto.HelloServiceAutoConfiguration
-
用maven插件,将两个工程install到本地。
-
接下来,测试使用自定义starter,用Spring Initializr创建名为
hello-spring-boot-starter-test
工程,引入hello-spring-boot-starter
依赖,其pom.xml如下:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.atguigu</groupId> <artifactId>hello-spring-boot-starter-test</artifactId> <version>1.0.0-SNAPSHOT</version> <name>hello-spring-boot-starter-test</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 引入hello-spring-boot-starter依赖 --> <dependency> <groupId>com.atguigu</groupId> <artifactId>hello-spring-boot-starter</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
添加配置文件
application.properties
hello.prefix=ATGUIGU hello.suffix=6666
-
编写新项目的
Controller
import com.atguigu.hello.service.HelloService; // 来自自定义starter import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Autowired HelloService helloService; @GetMapping("/hello") public String sayHello() { String s = helloService.sayHello("张三"); return s; } }