综合实战本章我们讲解了SpringBoot外化配置的原理与源码分析。在本节中,我们通过一个具体的例子来简要演示如何使用不同类型的参数和配置。我们还将对本??节示例中涉及的一些新知识点进行简单介绍和扩展。在本节的例子中,我们将使用命令行传递参数,默认配置文件application.properties和基于profile的配置参数,@Value注解获取参数,类型安全的@ConfigurationProperties注解关联bean等功能.由于SpringBoot简化了外部配置,相比前面章节介绍的相关原理,我们在实践中使用起来非常方便。这里我创建了一个标准的SpringBoot项目,版本为2.2.1.RELEASE。首先,让我们看一下项目的目录结构。pom.xml中引入的核心依赖是spring-boot-starter-web,对应的依赖源码如下。org.springframework.bootspring-boot-starter-webSpringbootConfigApplication类是SpringBoot项目的启动类,我们不会介绍的太多了。ConfigController类是接收请求的控制器,并在其中定义了一个默认的getConfigParams方法。在这个方法中,打印了不同方式得到的参数值。相关源码如下。@RestControllerpublicclassConfigController{@Value("${user.username}")privateStringusername;@Value("${user.password}")privateStringpassword;@ResourceprivateLoginUserConfigloginUserConfig;@Value("${projectName:unknown}")privateStringprojectName;@RequestMapping("/")publicStringgetConfigParams(){//启动命令传递参数System.out.println("CommandconfigprojectName:"+projectName);//通过应用配置文件配置的参数System.out.println("ApplicationconfigUsernameSystem.out.println("ApplicationconfigPassword:"+password);//通过@ConfigurationProperties注解配置的参数.getPassword());return"";}@RestController注解用来指定这个类是一个可以接收请求的Controller,并实例化它。在这个类内部,dif设置的参数通过@Value注解和@Resource注解获取ferent方法。访问请求通过getConfigParams方法对外提供。收到请求后,会打印通过不同方式获取到的参数值。首先我们来看一下通过@Value获取的值的来源。本例中,设置相应值的方式有两种:application.properties配置文件和命令行参数。关于命令行参数,我们之前也提到过,基本的传递方式是在执行启动项目的命令时以“name=value”的形式传递,结合实例,传递方式如下。java-jarspringboot-config-0.0.1-SNAPSHOT.jar--projectName=SpringBoot在ConfigController类中,我们可以看到@Value的基本格式是@Value("${param}"),但是我们在命令行中使用了@parametersValue("${param:default}")方法。这两种方法在实践中比较常用,第二种方法通过冒号分隔符传递默认值。当param参数不存在或者应用中没有配置时,会使用指定的默认值,以当前实例为例,如果在启动命令中没有指定projectName参数,并且获取@Value时也没有指定默认值"unknown",那么就会抛出异常执行启动命令时抛出不能不能开始。这是我们在使用@Value时需要注意的一种情况。application.properties配置文件中参数的设置比较简单,直接在对应的文件中设置对应的key=value值即可,比如本例中的application.properties中的配置源码如下。#公共配置,任何环境都以8080开头server.port=8080spring.profiles.active=dev但是在实践中,我们经常会遇到不同环境需要不同配置文件的情况,重新修改配置文件或者重新打包会很麻烦每次你改变一个环境。这时候可以使用SpringBoot提供的Profile配置功能来解决问题。我们示例中提供的三个属性配置文件是为了演示Profile配置的基本使用。通常,项目中会根据环境的数量创建一个或多个属性配置文件。通常,它们对应的命名格式和相关函数如下。*applcation.properties:公共配置。*application-dev.properties:开发环境配置。.application-test.properties:测试环境配置。application-prod.properties:生产环境配置。当然,命名中的“dev”test和“prod”是可以自定义的,何时使用这些配置可以通过激活application.properties配置文件中的spring.profiles.active参数来控制。例如在applcation.properties中进行public配置,然后通过如下配置激活指定环境的配置。spring.profiles.active=prod其中“prod”是指文件名中的application-prod.properties。SpringBoot在处理时会获取配置文件applcation.properties,然后通过指定profile的值prod进行拼接,获取application-prod.properties文件的名称和路径。加载和拼接的具体步骤和原理在前面的章节中已经讲过了,我们可以结合实例来回顾一下。在上面的例子中,我们激活了dev配置环境,application-dev.properties中的配置如下。#测试环境用户名和账号user.username=test-adminuser.password=test-pwd此时访问对应的请求,getConfigParams方法中打印的对应日志如下。ApplicationconfigUsername:test-adminApplicationconfigPassword:test-pwd如果要激活生产环境的配置,只需要在application.properties中配置spring.profiles.active=prod即可。我们在@Value参数值的获取和基于profile的参数配置上展开了这么多。@Value的使用还包括注入普通字符串、操作系统属性、表达式结果、文件资源、URL资源等,可以参考官方文档和相关示例进行深入学习。在上面@Value的使用中,我们可以注入和配置单个属性,但是如果配置属性很多或者配置属性本身有层次结构,就不够方便和灵活了。因此,SpringBoo提供了类型安全的配置方式。在ConfigController中,我们通过@Resource注入一个LoginUserConfig类,通过@ConfigurationProperties注解将properties属性与LoginUserConfig的属性关联起来,从而实现类型安全的配置。LoginUserConfig源码如下。@Component@ConfigurationProperties(prefix="user")publicclassLoginUserConfig{privateStringusername;privateStringpassword;//省略getter/setter方法}在LoginUserConfig类的源码中,@ConfigurationProperties注解指定要绑定以user为前缀的配置属性实例化时设置为LoginUserConfig类的相应属性,通过@Component实例化该类。这里,由于指定的配置文件是dev,所以上面dev配置文件中user.username和user.password的值会分别绑定到LoginUserConfig类的username和password属性上。而在ConfigController中注入后,就可以得到对应的属性值。同样在执行请求时,getConfigParams方法中打印的相应日志如下。ConfigurationPropertiesconfig用户名:test-adminConfigurationPropertiesconfig密码:test-pwd上面的例子只是演示了@ConfigurationProperties绑定属性的情况。当SpringBoot将Environment属性绑定到@ConfigurationProperties标记的beans时,你也可以使用一些松散的。规则,即Environment属性名和Bean属性名不需要完全匹配。比如User对象中有firstName属性,那么配置文件中对应的配置项就会匹配。user.firstName//标准驼峰命名语法user.first-name//用短划线分隔,推荐用于.properties和.yml文件user.first_name//带下划线,用于.properties和yml文件可选格式USER_FIRST_NAME//大写,推荐用于系统环境变量同时,基于类型安全的属性配置也可以结合@Validated注解进行属性约束校验,比如判断是否不为空,是否为正确的mobile电话号码(Email)格式,日期是否正确等,这里不再展开。您可以尝试使用此示例进行扩展。最后,我们来整体回顾一下本节中的例子的重点。首先,我们基于Profile机制为多个环境设置配置文件;然后通过spring.profiles.active配置指定使用哪些环境的参数值;然后通过@Value和@ConfigurationProperties注解将这些配置属性绑定到类属性或Bean对象上;最后在特定场景下获取并使用(本例为打印)。在实践中,我们也会遇到优先级问题。比如有些参数直接通过命令行参数指定,会覆盖配置文件中的同名参数。再比如,如果应用的配置文件和项目放在同一个目录下,那么它的优先级就比jar包里的配置高。这些内容我们已经在原理章节中进行了介绍,读者可以参考这个例子来一一验证和学习。小结本章重点介绍了SpringBoot中的参数传递过程和配置文件加载,特别是基于profile的加载机制。至于加载、默认配置、配置优先级等操作,都位于ConfigFileApplicationListener类中,值得读者朋友花时间研究。实战部分通过一个简单的例子演示了一些原理的使用,你可以通过这个例子来验证和使用更多的相关功能。最后,由于本章源码较多,逻辑层次较深,不同的配置方式会形成不同的组合,形成更多的场景。所以建议在学习过程中通过debug跟踪每一步的运行,这样才能更好的理解整个过程。