
大家好! 本书主要面向Java和JVM计算机的开发人员,他们正在寻找使用Spring Boot,Spring Cloud和Cloud Foundry在短时间内创建更好的软件的方法。 它适用于那些已经听到微服务周围的噪音上升的人。 您可能已经了解了Spring Boot所达到的平流层高度,并且让当今的企业使用Cloud Foundry平台感到惊讶。 如果是这样,那么这本书适合您。
摘录。 3.十二因素应用程序配置样式
本章将讨论如何实现应用程序配置。
定义许多词汇。 关于Spring的配置,通常是指进入Spring环境中应用程序上下文的各种实现
-ApplicationContext ,它可以帮助容器了解如何连接Bean组件。 可以将这种配置表示为XML文件,该文件必须在
ClassPathXmlApplicationContext中提供 ,或者以可以提供给
AnnotationConfigApplicationContext对象的方式注释的Java类。 当然,在研究最后一个选项时,我们将参考
Java配置。但是在本章中,我们将以
12因子应用程序清单中定义的形式查看配置。 在这种情况下,它涉及可以从一种环境更改为另一种环境的文字值:我们在谈论密码,端口和主机名,或者关于属性标志。 该配置将忽略代码中内置的魔术常数。 清单包含正确配置的极好的标准:应用程序代码库是否可以在不泄露和损害重要凭据的情况下随时开源? 这种配置专门指的是在一个环境与另一个环境之间变化的值,并且不适用于例如连接Spring Bean或配置Ruby路由。
在Spring框架中的支持
在Spring中,自
PropertyPlaceholderConfigurer类问世以来,已支持12因子配置样式。 定义其实例后,它将使用从扩展名为.properties的文件中提取的值替换XML配置中的文字。 在Spring环境中,从2003年开始提供
PropertyPlaceholderConfigurer类。 Spring 2.5引入了对XML名称空间的支持,并同时支持此空间中的属性替换。 这允许用分配给外部属性文件(在这种情况下,在simple.properties文件中,可以出现在类路径中或位于应用程序外部)中的键的值,在Bean定义的文字值的XML配置中进行替换。
具有12个因素的样式的配置旨在消除现有魔术字符串的不可靠性,也就是说,诸如数据库的地址和用于连接它们的帐户,端口等值在编译的应用程序中进行了硬编码。 如果将配置移到应用程序外部,则可以在不借助新代码汇编的情况下将其替换。
类PropertyPlaceholderConfigurer
让我们看一个示例,该示例使用PropertyPlaceholderConfigurer类,Spring bean组件的XML定义以及一个超出应用程序限制的扩展名为.properties的文件。 我们只需要打印此属性文件中可用的值。 这将有助于执行示例3.1中所示的代码。
范例3.1 属性文件:some.properties
configuration.projectName=Spring Framework
这是Spring的ClassPathXmlApplicationContext类,因此我们使用Spring上下文中的XML名称空间并指向我们的some.properties文件。 然后,在bean组件的定义中,我们使用$ {configuration.projectName}形式的文字,并且Spring将用属性文件中的值替换它们(示例3.2)。
示例3.2 Spring配置XML文件
<context:property-placeholder location="classpath:some.properties"/> (1) <bean class="classic.Application"> <property name="configurationProjectName" value="${configuration.projectName}"/> </bean>
(1)classpath:引用当前编译代码块(.jar,.war等)中的文件的位置。 Spring支持许多替代方案,包括file:和url:,它们允许文件与代码块分开存在。
最后,让我们看一下Java类的外观,由于这个原因,可以将所有这些组合在一起(示例3.3)。
示例3.3 必须使用属性值配置的Java类
套餐经典;
import org.apache.commons.logging.LogFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { new ClassPathXmlApplicationContext("classic.xml"); } public void setConfigurationProjectName(String pn) { LogFactory.getLog(getClass()).info("the configuration project name is " + pn); } }
第一个示例使用Spring bean配置XML格式。 在Spring 3.0和3.1中,使用Java配置的开发人员的情况已大大改善。 在这些发行版中引入了
Value注释和Environment抽象。
抽象环境与价值
在代码执行期间,
环境抽象表示其与运行环境之间的间接关系,并允许应用程序提出有关环境属性的问题(“此平台上的line.separator是什么行分隔符?”)。 抽象充当键和值的映射。 通过在环境中配置PropertySource,可以配置从何处读取这些值。 默认情况下,Spring加载系统键和环境值,例如line.separator。 您可以使用@PropertySource批注指示Spring按照与在Spring的属性替换解决方案的早期版本中使用的顺序相同的顺序从文件中加载配置密钥。
Value注释提供了一种将环境值嵌入到构造函数,setter,字段等中的方法。可以使用Spring Expression Language或属性替换语法(如果
已注册
PropertySourcesPlaceholderConfigurer来计算这些值),如示例3.4中所示。
示例3.4 注册PropertySourcesPlaceholderConfigurer
包环境;
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.env.Environment; import javax.annotation.PostConstruct; (1) @Configuration @PropertySource("some.properties") public class Application { private final Log log = LogFactory.getLog(getClass()); public static void main(String[] args) throws Throwable { new AnnotationConfigApplicationContext(Application.class); } (2) @Bean static PropertySourcesPlaceholderConfigurer pspc() { return new PropertySourcesPlaceholderConfigurer(); } (3) @Value("${configuration.projectName}") private String fieldValue; (4) @Autowired Application(@Value("${configuration.projectName}") String pn) { log.info("Application constructor: " + pn); } (5) @Value("${configuration.projectName}") void setProjectName(String projectName) { log.info("setProjectName: " + projectName); } (6) @Autowired void setEnvironment(Environment env) { log.info("setEnvironment: " + env.getProperty("configuration.projectName")); } (7) @Bean InitializingBean both(Environment env, @Value("${configuration.projectName}") String projectName) { return () -> { log.info("@Bean with both dependencies (projectName): " + projectName); log.info("@Bean with both dependencies (env): " + env.getProperty("configuration.projectName")); }; } @PostConstruct void afterPropertiesSet() throws Throwable { log.info("fieldValue: " + this.fieldValue); } }
(1)注释@PropertySource是类似于property-placeholder的简写,它从扩展名为.properties的文件中设置PropertySource。
(2)PropertySourcesPlaceholderConfigurer需要注册为静态bean,因为它是BeanFactoryPostProcessor的实现,并且必须在Spring bean的初始化生命周期的早期阶段调用。 在Spring XML配置中使用bean组件时,这种细微差别是不可见的。
(3)您可以用
Value注释修饰字段(但不要这样做,否则代码将无法通过测试!)...
(4)...或者
Value注释可以修饰构造函数参数...
(5)...或使用安装方法...
(6)...或嵌入Spring Environment对象并手动执行键解析。
(7)具有
Value批注的参数也可以在Spring Java配置的
Bean方法参数提供程序中使用。
在此示例中,值是从simple.properties文件加载的,然后具有值configuration.projectName,该值以各种方式提供。
个人资料
其中,环境抽象引入了
profile 。 这允许您分配标签(配置文件)以便对bean组件进行分组。 概要文件应用于描述因环境而异的bean组件和bean图。 可以同时激活多个配置文件。 没有为其分配概要文件的Bean总是被激活。 具有缺省概要文件的Bean仅在没有其他活动概要文件的情况下才被激活。 可以在XML的bean组件定义中或在标记类,配置类,单个bean组件中,或在使用
Profile的
Bean提供程序的方法中指定profile属性。
概要文件使您能够描述必须在一个环境中创建的bean组件集与在另一个环境中有所不同的集。 例如,在本地开发dev概要文件中,可以使用内置的H2数据源javax.sql.DataSource,然后在prod概要文件处于活动状态时,切换到使用JNDI搜索获得的javax.sql.DataSource数据源。通过从
Cloud Foundry中的环境变量读取属性。 在这两种情况下,您的代码都可以工作:您将获得javax.sql.DataSource,但是通过激活一个或多个概要文件(示例3.5)来决定使用哪个特定实例。
示例3.5 演示@Configuration类可以加载各种配置文件并根据以下内容提供不同的bean
活动资料
package profiles; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; @Configuration public class Application { private Log log = LogFactory.getLog(getClass()); @Bean static PropertySourcesPlaceholderConfigurer pspc() { return new PropertySourcesPlaceholderConfigurer(); } (1) @Configuration @Profile("prod") @PropertySource("some-prod.properties") public static class ProdConfiguration { @Bean InitializingBean init() { return () -> LogFactory.getLog(getClass()).info("prod InitializingBean"); } } @Configuration @Profile({ "default", "dev" }) (2) @PropertySource("some.properties") public static class DefaultConfiguration { @Bean InitializingBean init() { return () -> LogFactory.getLog(getClass()).info("default InitializingBean"); } } (3) @Bean InitializingBean which(Environment e, @Value("${configuration.projectName}") String projectName) { return () -> { log.info("activeProfiles: '" + StringUtils.arrayToCommaDelimitedString(e.getActiveProfiles()) + "'"); log.info("configuration.projectName: " + projectName); }; } public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); ac.getEnvironment().setActiveProfiles("dev"); (4) ac.register(Application.class); ac.refresh(); } }
(1)仅当prod配置文件处于活动状态时,才会计算此配置类及其中包含的所有
Bean定义。
(2)仅当dev配置文件处于活动状态或没有配置文件处于活动状态(包括dev)时,才会计算此配置类及其中包含的所有
Bean定义。
(3)此InitializingBean组件仅记录当前活动的概要文件,并输入最终输入到属性文件中的值。
(4)以编程方式激活一个或多个配置文件非常简单。
Spring使用spring_profiles_active或spring.profiles.active令牌响应其他几种配置文件激活方法。 可以使用环境变量(例如,SPRING_PROFILES_ACTIVE),JVM属性(-Dspring.profiles.active = ...),Servlet应用程序初始化参数或通过编程来设置概要文件。
引导配置
Spring Boot大大改善了这种情况。 该环境最初将自动从预定义位置的层次结构中加载属性。 命令行参数覆盖从JNDI派生的属性值,该属性值覆盖从System.getProperties()等获取的属性。
-命令行参数。
-来自Java的JNDI属性:comp / env。
-System.getProperties()的属性。
-操作系统环境变量。
-文件系统中的外部属性文件:(config /)?Application(Yml.properties)。
-存档(config /)?应用程序(Yml.properties)中的内部属性文件。
-配置类中的注释@PropertySource。
-来自SpringApplication.getDefaultProperties()的源属性。
如果
概要文件处于活动状态,那么将自动从基于概要文件名称的配置文件中读取数据,例如,从诸如src / main / resources / application-foo.properties之类的文件中读取,其中foo是当前概要文件。
如果在类路径中提到了
SnakeYAML库,则将遵循基本相同的约定自动加载YAML文件。
YAML规范页面指出:“ YAML是一种人类可读的标准,用于序列化所有编程语言的数据。” YAML是值的层次结构表示。 在扩展名为.properties的常规文件中,层次结构由点(“。”)表示;在YAML文件中,使用换行符和附加的缩进级别。 最好使用这些文件来避免在存在高度分支的配置树时指定公共根的需求。
例3.6中显示了扩展名为.yml的文件的内容。
示例3.6 Application.yml属性文件。 数据按层次结构顺序显示。
configuration: projectName : Spring Boot management: security: enabled: false
另外,在一般情况下,Spring Boot环境使获得正确结果变得容易得多。 它将-D参数转换为可用作属性的进程和java环境变量。 它甚至执行规范化,其中环境变量$ CONFIGURATION_PROJECTNAME(PROJECT_NAME CONFIGURATION)或-D参数形式为–Dconfiguration.projectName(configuration.project_name),可以像以前一样使用configuration.projectName键(configuration.project_name)使用。 spring_profiles_active令牌可用。
配置值是字符串,如果足够,则在尝试确保这些键本身不会成为代码中的魔术字符串时,它们可能变得不可读。 Spring Boot引入了组件类型@ConfigurationProperties。 当使用@ConfigurationProperties注释POJO(普通的Java对象)并指定前缀时,Spring会尝试将所有以此前缀开头的属性映射到POJO属性。 在下面的示例中,configuration.projectName的值将映射到POJO实例,然后所有代码都可以注入并取消引用以读取类型安全值。 如此一来,您将只从(String)键获得一个映射(示例3.7)。
示例3.7 自动从src / main / resources / application.yml中解析属性
软件包启动;
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.stereotype.Component; (1) @EnableConfigurationProperties @SpringBootApplication public class Application { private final Log log = LogFactory.getLog(getClass()); public static void main(String[] args) { SpringApplication.run(Application.class); } @Autowired public Application(ConfigurationProjectProperties cp) { log.info("configurationProjectProperties.projectName = " + cp.getProjectName()); } } (2) @Component @ConfigurationProperties("configuration") class ConfigurationProjectProperties { private String projectName; (3) public String getProjectName() { return projectName; } public void setProjectName(String projectName) { this.projectName = projectName; } }
(1)@EnableConfigurationProperties注释告诉Spring将属性映射到以@ConfigurationProperties注释的POJO。
(2)@ConfigurationProperties注释显示Spring该bean应该用作配置开始的所有属性的根。紧随其后的是映射到对象属性的标记。
(3)projectName字段最终将具有分配给configuration.projectName属性键的值。
Spring Boot主动使用@ConfigurationProperties机制使用户能够覆盖系统的基本组件。 您可能会注意到,属性键使您可以进行更改,例如,通过将org.springframework.boot:spring-boot-starter-actuator依赖项添加到Spring Boot Web应用程序,然后访问
127.0.0.1:8080 / configprops。
执行器端点将在第13章中更详细地讨论。它们被锁定,并且需要默认的用户名和密码。 可以通过在application.properties文件(或application.yml)中指定management.security.enabled = false来禁用安全措施(但仅考虑这些要点)。
您将在运行时基于类路径中显示的类型获取受支持的配置属性的列表。 随着Spring Boot类型数量的增加,将显示其他属性。 该端点还将显示由POJO导出的具有@ConfigurationProperties批注的属性。
使用Spring Cloud Configuration Server进行集中式注册配置
到目前为止,一切都很好,但是事情需要更加成功。 我们仍未回答有关常见用例的问题:
- 对应用程序配置进行更改后,需要重新启动;
- 无可追溯性:如何确定投入运行的更改,并在必要时将其回滚?
- 配置分散 目前尚不清楚应在何处进行更改以更改一个或另一个方面;
- 出于安全目的,没有安装支持编码和解码。
Spring Cloud配置服务器
通过将配置保存在一个目录中并将所有应用程序指向该目录,可以解决集中配置的问题。 您也可以使用Git或Subversion安装此目录的版本控制。 然后将收到验证和注册所需的支持。 但是仍然不能满足最后两个要求,因此需要更复杂的东西。 转到
Spring Cloud配置服务器。 Spring Cloud平台提供了配置服务器和该服务器的客户端。
Spring Cloud Config服务器是一个REST API,我们的客户端将连接到该REST API以检索其配置。 服务器还管理版本控制配置存储库。 他是我们的客户端和配置存储库之间的中介,因此在实施安全工具方面处于有利的位置,该安全工具用于连接客户端到服务的连接以及具有版本控制的服务到配置存储库的连接。 Spring Cloud Config客户端为客户端应用程序提供了一个新的范围,刷新,这使您无需重新启动应用程序即可再次配置Spring组件。
诸如Spring Cloud Config服务器之类的技术起着重要作用,但会带来额外的开销。 理想情况下,应将此责任转移到平台并自动执行。 使用Cloud Foundry时,您可以在服务目录中找到Config Server服务,其操作基于对Spring Cloud Config服务器的使用。
考虑一个简单的例子。 首先,配置Spring Cloud Config服务器。 一个这样的服务可以被多个Spring Boot应用程序一次访问。 您需要使其以某种方式工作。 然后,仅将所有配置服务通知到我们的服务即可。 它充当中介的一种中介,它可以通过网络或磁盘从Git存储中读取配置密钥和值。 将字符串org.springframework.cloud:spring-cloud-config-server添加到Spring Boot应用程序的程序集中,以输入Spring Cloud Config服务器(示例3.8)。
示例3.8 要将配置服务器嵌入到程序集中,请使用@EnableConfigServer批注
package demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; (1) @SpringBootApplication @EnableConfigServer public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
(1)使用@EnableConfigServer批注将导致安装Spring Cloud Config服务器。
例3.9显示了配置服务的配置。
示例3.9 src / main / resources / application.yml配置服务器配置
server.port = 8888
spring.cloud.config.server.git.uri = \
github.com/cloud-native-java/config-server-configuration-repository(1 )
(1)指示正常工作的Git存储库的指示,该存储库本质上是本地的,或者可以通过网络访问(例如,在GitHub(https://github.com/)上),并由Spring Cloud Config服务器使用。
在这里,指示Spring Cloud配置服务在GitHub上的Git存储库中搜索单个客户端的配置文件。 我们指向此存储库,但是指向任何有效Git URI的链接都可以。 当然,他甚至不必申请Git系统,您可以使用Subversion甚至是非托管目录(尽管我们强烈建议您不要这样做)。 在这种情况下,存储URI是硬编码的,但是没有什么阻止它从-D参数,参数或环境变量中获取的。
»这本书的更多信息可以
在出版商的网站上找到»
目录»
摘录Java发酵罐优惠券20%的折扣
-Java