springboot 动态配置与动态打包
通常在开发环境和生产环境,我们的应用程序会需要很多动态配置信息,有的应用程序的jar包也需要根据不同环境来动态打包。
要实现两点核心功能:
- 在pom.xml中根据环境配置变量,供Java代码或properties.xml中获取变量内容
- maven打包时可动态指定环境编译出不同环境配置的app。
开始学习之前,您需要做如下准备
- springboot v2.3.6.RELEASE版本
- JDK1.8
- 一个好用的IDE。推荐使用Spring推出的STS项目工具来写demo,免费且占用内存小,另外一点可以参照本教程作对比,当然用IDEA也行。
- STS下载:https://spring.io/tools/
快速创建一个springboot项目
这里我使用一个已经创建好的springboot项目做案例
项目结构如下:
简单介绍一下项目结构说明
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.3.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lb</groupId>
<artifactId>springboot-quickstart</artifactId>
<version>1.0.0</version>
<name>springboot-quickstart</name>
<description>springboot-quickstart</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
主应用程序
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import com.lb.springboot.config.AppConfig;
@SpringBootApplication
public class QuickstartApplication {
/**
* 应用程序入口
* @param args
*/
public static void main(String[] args) {
// 启动springboot应用程序
ConfigurableApplicationContext context = SpringApplication.run(QuickstartApplication.class, args);
// 测试自定义配置
AppConfig appConfig = context.getBean(AppConfig.class);
// 打印日志
appConfig.output();
}
}
自定义配置
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
/**
* 应用的自定义配置
* @author lb
* <h2>说明</h2>
* <p> {@code @Configuration}的作用相当于引入web.xml --> applicationContext-web.xml --> ApplicationConfig.xml </p>
* <p> {@code @ComponentScan}的作用相当于applicationContext-web.xml 配置的扫描</p>
* <p> {@code @PropertySource}加载自定义的配置</p>
*
*/
@Configuration
@ComponentScan(basePackages = {"com.lb.springboot.*"})
@PropertySource("classpath:myconfig.properties")
public class AppConfig{
private static final Logger LOGGER = LoggerFactory.getLogger(AppConfig.class);
@Value("${applicationfile.coustom.testname}")
private String coustomName;
@Value("${coustomfile.username}")
private String username;
@Autowired
private Environment env;
public void output() {
LOGGER.info("使用 @Value 读取到的自定义配置: {}", coustomName);
LOGGER.info("使用 @Autowired Environment 读取到的自定义配置: {}", env.getProperty("applicationfile.coustom.testname"));
LOGGER.info("加载自定义配置文件 - username: {},",username);
}
}
测试controller
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexController.class);
@GetMapping(value = "index")
public String index() {
LOGGER.info("index is running...");
return "Hello,Springboot !";
}
}
应用主配置文件 application.properties
# 服务端口
server.port=8080
# 服务路径,配置此路径,请求API需要增加 /qs 再进行请求
server.servlet.context-path=/qs
# 自定义配置
applicationfile.coustom.testname=Tom
自定义配置文件 myconfig.properties
coustomfile.username=jack
启动项目测试,在主程序上,鼠标右键 ---> Run As ---> 选择Java application 或者Springboot App 启动
启动成功后,控制台打印如下:
我们来测试一下服务可用性,在控制台terminal或者iterm2 curl localhost:8080/qs/index
,结果如下:
好了,准备工作完毕。接下来我们开始修改pom.xml,让其支持spring动态配置及动态打包
动态配置&动态打包
一、修改pom.xml
1. 新增maven profile相关配置
这个配置在应用打包的时候,会动态将profile标签配置的properties打包到应用jar或war中
<!-- profile配置切换. 使用maven命令: mvn clean install -P local ( dev 、 qa 、 pro ) -->
<profiles>
<!-- 开发环境配置 -->
<profile>
<id>dev</id>
<activation>
<!-- 设置本profile为默认配置,在进行Maven打包时不指定-P参数,使用 dev的配置进行打包 -->
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
</dependencies>
<properties>
<!-- /src/main/resources/application.properties 中的配置-->
<spring.profiles.active>dev</spring.profiles.active>
<!-- 跟随环境变化的自定义参数 -->
<lb.env.dynamic.attr>2020-12-12-dev</lb.env.dynamic.attr>
</properties>
</profile>
<!-- 生产环境配置 -->
<profile>
<id>pro</id>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
</dependencies>
<properties>
<spring.profiles.active>pro</spring.profiles.active>
<!-- 动态参数 -->
<lb.env.dynamic.attr>2020-12-15-pro</lb.env.dynamic.attr>
</properties>
</profile>
</profiles>
1.2 修改build配置
我们会在build中增加如下几项maven插件
- maven-compiler-plugin (编译Java代码)
- maven-resources-plugin (处理资源文件 )
- maven-surefire-plugin (忽略测试用例)
- maven-source-plugin (处理源代码)
<build>
<!-- 最终打出来的jar包名称 -->
<finalName>lb-springboot-quickstart</finalName>
<plugins>
<!-- springboot的maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- 解决maven update project 后JDK版本降低为1.5的bug -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- 打包时忽略单元测试文件,防止由于单元测试编写错误导致打包失败的情况 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
<includes>
<include>**/*Test*.java</include>
</includes>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
<!-- 需要对于Maven工程的源代码进行源文件的打包,可以利用source插件来完成,在install时,会同时将源码包安装到本地仓库 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<!-- 绑定到特定的生命周期之后,运行maven-source-pluin 运行目标为jar-no-fork -->
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- maven-resources-plugin用来处理资源文件 -->
<!-- 利用此插件实现Maven动态打包: mvn clean install -P pro/dev/local -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>default-resources</id>
<phase>validate</phase>
<!-- goals包含以下三种配置项:
1. resources:resources,拷贝main resources到main output directory。它绑定了process-resources生命周期阶段,当执行Compiler:compile插件目标前就会执行此阶段。
2. resources:testResources,拷贝test resources到test output directory。它绑定了process-test-resources生命周期阶段,当执行surefire:test插件目标前就会执行此阶段。
3. resources:copy-resources,手动拷贝资源到输出目录 -->
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target/classes</outputDirectory>
<useDefaultDelimiters>false</useDefaultDelimiters>
<delimiters>
<delimiter>$</delimiter>
</delimiters>
<resources>
<!-- 打包时包含properties、xml
比如mybatis的mapper.xml文件,我们习惯把它和Mapper.java放一起,都在src/main/java下面,
这样利用maven打包时,就需要修改pom.xml文件,来把mapper.xml文件一起打包进jar或者war -->
<resource>
<!-- 是否替换资源中的属性 -->
<filtering>true</filtering>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources/</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
<include>**/*.yml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
二、修改application.properties
在修改前,我们要知道一点,就是springboot启动时会自动加载以 application开头的配置文件,例如
application-*.properties
。 我们要在application.properties
里新增spring.profiles.active=$spring.profiles.active$
配置项 为什么使用前后$符号来获取参数,是因为在/pom.xml文件中maven-resources-plugin插件指定的delimiter符号是$符号。
然后我们在src/main/resources目录下新增2个新的配置文件,文件名分别为:application-dev.properties 、application-pro.properties
application-dev.properties 内容如下:
# DEV服务端口
server.port=8081
application-pro.properties 内容如下:
# PRO服务端口
server.port=8082
myconfig.properties,新增如下配置
# pom.xml中自定义的环境变量 profiles--->profile--->properties配置
lb.env.dynamic.attr=$lb.env.dynamic.attr$
三、测试验证
接下来我们在程序中读取
pom.xml
的动态配置信息,在com.lb.springboot.config.AppConfig
获取pom.xml
中定义的配置
@Configuration
@ComponentScan(basePackages = {"com.lb.springboot.*"})
@PropertySource("classpath:myconfig.properties")
public class AppConfig{
private static final Logger LOGGER = LoggerFactory.getLogger(AppConfig.class);
@Value("${applicationfile.coustom.testname}")
private String coustomName;
@Value("${coustomfile.username}")
private String username;
@Autowired
private Environment env;
// lb.env.dynamic.attr 为pom.xml配置的信息
// 这里会根据application.properties配置的spring.profiles.active值动态获取pom.xml配置的信息
// 例如spring.profiles.active=dev,那么dynamicAttr=2020-12-12-dev
// 如果spring.profiles.active=pro,那么dynamicAttr=2020-12-15-pro
@Value("${lb.env.dynamic.attr}")
private String dynamicAttr;
public void output() {
LOGGER.info("使用 @Value 读取到的自定义配置: {}", coustomName);
LOGGER.info("使用 @Autowired Environment 读取到的自定义配置: {}", env.getProperty("applicationfile.coustom.testname"));
LOGGER.info("加载自定义配置文件 - username: {},",username);
// 打印动态配置内容
LOGGER.info("动态获取pom.xml配置 - dynamicAttr value: {}",dynamicAttr);
}
}
1. 在项目上,鼠标右键选择 --->Run As ---> Maven build...
2. 弹出对话框后,在Goals输入框 输入clean install -P pro
,点击run
3. 等待maven打包完毕后,项目 /target 目录显示如下:
4. 我们把第一个文件lb-springboot-quickstart.jar
复制一份,放在桌面,解压后查看编译后的内容。
打开BOOT-ROOT ---> classes 查看application.properties
内容。因为打包时指定的-P pro
所以编译后的文件获取的是pro环境的配置
我们再查看下 myconfig.properties
的内容,看有没有动态获取到 pom.xml配置的变量。答案很明显,说明properties动态获取pom.xml的变量没有问题。
接下来我们来测试一下,项目中[@Value](https://my.oschina.net/u/3193899)
读取的pom.xml
变量是否有问题。
使用命令 java -jar lb-springboot-quickstart.jar
启动项目,查看控制台如下:
结果如下:
- spring.profiles.active=pro
- 并且应用端口是获取的application-pro.properties的配置
- 同时也在appconfig.java获取到了POM.xml中的变量 lb.env.dynamic.attr的值。
有兴趣的同学可以使用 clean install -P dev 打包,打包后使用命令 java -jar lb-springboot-quickstart.jar 启动项目进一步校验结果。 案例代码下载:https://github.com/yunnasheng/springboot-quickstart-001.git