原生应用:是一种程序开发风格,是连续交付(持续集成)和值驱动领域的最佳实践。html
与12-Factor (SaaS)应用,有着相似的目标: (12-Factor 为构建以下的 SaaS 应用提供了方法论):java
- 使用标准化流程自动配置,从而使新的开发者花费最少的学习成本加入这个项目。
- 和操做系统之间尽量的划清界限,在各个系统中提供最大的可移植性。
- 适合部署在现代的云计算平台,从而在服务器和系统管理方面节省资源。
- 将开发环境和生产环境的差别降至最低,并使用持续交付实施敏捷开发。
- 能够在工具、架构和开发流程不发生明显变化的前提下实现扩展。
这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序。正则表达式
12-factors 包含:spring
Spring Cloud 提供一种途径,使得可以方便快捷并按需的搭建一个可用的分布式应用。docker
在使用Spring Cloud 时不少特性是基于Spring Boot的, 另外还有两个库:Spring Cloud Context 和 Spring Cloud Commons。数据库
提供一些工具,以及Spring Cloud应用(ApplicationContext)的基础服务。如:引导上下文;加解密;做用域重建;环境()bootstrap
是一个不一样Spring Cloud实现的抽象层以及通用类集合。 如:Spring Cloud Netflix;Spring Cloud Consul后端
若是出现“Illegal key size”错误,那表示须要更新JCE策略文件,以得到更高的权限api
Spring Boot 提供了一套固定的套路来使用spring构建应用,用一种约定俗成的方式来进行配置,并提供一套通用的管理、监控方式。 Spring Cloud 在此基础之上,增长一些能够按需配置的功能。缓存
一个Spring Cloud应用,首先会建立一个引导上下文来做为主应用上下文的父级。 负责从外部加载配置源。两个上下文共享一个
Environment
来作为Spring应用的外部配置源。
默认的引导属性拥有更高的优先级,所以,不能被本地配置所覆盖。
引导上下文使用了一个和Spring Boot主应用不一样的约定方式来加载配置。引导上下文使用
bootstrap.yml
(或者properties)来配置,经过这样很好的与主应用配置分离开来。
bootstrap.yml
spring: application: name: foo cloud: config: uri: ${SPRING_CONFIG_URI:http://localhost:8888}
引导上下文也能够经过在系统属性中配置:
spring.cloud.bootstrap.enabled=false
来关闭。
若是使用
SpringApplication
或者SpringApplicationBuilder
来构建上下文时,那么会添加一个 引导上下文(BootstrapContext
)会做为父级上下文。
子级上下文会从父级上下文继承配置源以及配置文件,所以主应用会包含额外的配置来源。
额外的配置源包括:
- "bootstrap":若是有任何非空
PropertySourceLocators
被发现,那会生成一个优先级更高的CompositePropertySource
- "applicationConfig:[classpath:bootstrap.yml]":若是配置了
bootstrap.yml
或properties
,那么他们的配置项将被用于引导上下文(BootstrapContext
),这样也会被子级上下文引用到。他们比application.yml
的优先级低。
因为加载顺序使得
bootstrap
配置源会先被扫描,可是,注意:因为处于一个很是低的优先级,因此并无立刻加载bootstrap.yml
中的数据,也正是这个缘由,一般被用来看成默认配置实用。
能够设置父级上下文(
ApplicationContext
)来本身扩展上下文层级。 能够本身实现接口,也能够经过SpringApplicationBuilder
提供的几个方便的工具方法(parent()
,parent()
,parent()
)。 不论自定义了多少上下文层级,bootstrap
引导上下文都处于最高级。 在这个层级中的每个上下文都能访问到引导上下文的配置源,使用时须要注意避免无心的配置覆盖状况。 层级中的每个上下文原则上都应该有一个不一样的spring.application.name
,所以当有配置服务器时,就会有一个不一样的远程配置源。
普通的上下文,有一个区分配置的规则:子级上下文中的属性会覆盖父级上下文中的属性,覆盖条件包含属性名和配置源名。也就是说能够对整个配置源进行覆盖。
注意:
SpringApplicationBuilder
容许在整个上下文层级中共享Environment
,但此功能默认关闭。所以,当须要时,同级别的上下文不须要去包含同一个配置源,他们能够和父级上下文共享这些配置。
能够经过配置
spring.cloud.bootstrap.name
来改变默认的引导上下文配置文件名。(默认值bootstrap
)。
也能够经过配置
spring.cloud.bootstrap.location
来改变默认的引导上下文配置的扫描路径。(默认值空
)
经过系统属性来改变以上两个配置项
配置文件中
spring.config.*
等配置项是被用于引导上下文的配置,并被加载到Environment
中。
若是配置了
spring.profiles.active
或者经过Environment
的api来指定一个特定配置项,那么这个特定配置文件也会被加载,就如同一个Spring Boot应用同样。
被引导上下文加载的配置源一般都是一个远程的(例如:Config Server),默认状况下远程配置项不能被本地配置所覆盖。
若是应用想要覆盖远程配置项,则须要远程配置源经过配置
spring.cloud.config.allowOverride=true
来受权。一旦开启此功能,则能够在本地配置下面两个配置项来控制细节:
spring.cloud.config.overrideNone=true
覆盖本地全部配置源;spring.cloud.config.overrideSystemProperties=false
仅覆盖系统属性和环境变量,而不覆盖本地配置文件。
能够在
/META-INF/spring.factories
中添加org.springframework.cloud.bootstrap.BootstrapConfiguration
配置,来指定任何想要添加到引导上下文中的配置类(@Configuration
),若是有多个能够用逗号分隔。任何想要在主应用中自动装配的spring bean 均可以经过这些配置类来定义。 配置类也能够是一个包含@Beans
的ApplicationContextInitializer
对象。 当配置类有必定依赖顺序时,能够经过@Order
来指定顺序,默认:last。
注意: 当使用自定义
BootstrapConfiguration
时,在主应用时要当心使用@ComponentScanned
防止没必要要的加载。最好使用一个特定的包名来放置那些自定义配置类,来避免与@ComponentScan
,@SpringBootApplication
重叠。
当引导处理结束时会自动注入到主应用的
SpringApplication
实例中。 在启动以前,引导上下文会找到spring.factories
中的配置类以及全部被标记@Beans
的ApplicationContextInitializer
对象加入到主应用S上下文(SpringApplication
)
默认状况下外部配置源是一个Config Server,固然也能够在
spring.factories
中配置PropertySourceLocator
对象来手动添加外部配置源(其余Config Server;数据库等)
例如:
@Configuration public class CustomPropertySourceLocator implements PropertySourceLocator { @Override public PropertySource<?> locate(Environment environment) { return new MapPropertySource("customProperty", Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended")); } }
任何一个
ApplicationContext
都会创一个Environment
对象,它包含了外部配置源。它也相似一个普通Spring Boot配置源,所以你能够经过它来定制本地配置项。(例如:spring.application.name
)
若是jar中包含上面代码中的class,而且在
META-INF/spring.factories
包含:org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator那么,这个自定义配置源将会在classpath下全部的应用中被使用。
应用会监听
EnvironmentChangedEvent
事件,能够经过ApplicationListeners
来响应这个事件。
当配置项发生变更时,
EnvironmentChangedEvent
事件被抛出。 此时,应用会作出:
- 重建上下文中全部的
@ConfigurationProperties
对象- 对全部的日志属性
logging.level.*
进行设定
- 注意: Config Client默认不会主动去检测
Environment
的改变,不过能够经过一个定时任务(@Scheduled
)去轮询。可是,一般来讲并不建议用这样的方式。最好,经过广播EnvironmentChangedEvent
事件这种方式来处理。(例如使用:Spring Cloud Bus)
因为
EnvironmentChangedEvent
事件是经过Spring标准API来完成的,这就致使当Environment
发生改变时,会有大量的对象刷新。 例如:动态配置一个DataSource
的链接池的maxPoolSize
,当maxPoolSize
发生改变时,致使整个ApplicationContext
进入一个阻塞的重建@ConfigurationProperties
阶段。 为了解决这个问题,须要使用@RefreshScope
能够在
@Bean
上标记一个@Refresh Scope
来指定这个Bean须要在配置改变时刷新。
Refresh scope 对象都是延迟代理初始化的,调用方法获取值时都是从初始化值得缓存中获取的。从新初始化其实也就是初始化缓存。
RefreshScope
的refreshAll()
方法能够刷新所有目标缓存。refresh(String)
方法能够指定名字的缓存。这个功能会经过/refresh
暴露到外部(如:HTTP,JMX)
注意:
@RefreshScope
工做于@Configuration
类,这样就会致使一个特殊的状况:互相依赖的Bean也会被刷新重建,并从新注入,这样@Configuration
也就被从新初始化
Spring Cloud 为
Environment
提供了一个本地解密属性的预处理过程。 此过程,会使用几个扩展配置:encrypt.*
这样就能够经过{cipher}*
来使用加密数据了。
若是须要使用这个特性,那就须要引入Spring Security RSA 到classpath。
一样这也须要对JCE进行扩展。
对于一个基于Spring Boot Actuator应用,Spring Cloud原生应用扩展几个管理入口:
/env
(POST) : 用于 更新Environment
;重建@ConfigurationProperties
;日志级别/refresh
: 从新加载引导上下文;刷新@RefreshScope
对象。/restart
:重启ApplicationContext
,此功能默认不可用/pause
和/resume
: 调用Lifecycle
方法 (至关于ApplicationContext
的stop()
和start()
方法)
如服务发现,负载均衡,断路器等模式都是以一个共用抽象层提供给全部的Spring Cloud客户端独立使用。
RestTemplate
可使用@LoadBalanced
在对应的@Bean
进行连带的配置,就能够作成负载均衡。
注意:
RestTemplate
再也不自动建立了,须要时,须要本身建立特定的应用
@Configuration public class MyConfiguration { @LoadBalanced @Bean RestTemplate restTemplate() { return new RestTemplate(); } } public class MyClass { @Autowired private RestTemplate restTemplate; public String doOtherStuff() { String results = restTemplate.getForObject("http://stores/stores", String.class); return results; } }
若是
RestTemplate
不想要负载均衡,那就建立一个普通RestTemplate
正常注入就好了。 若是须要负载均衡,在建立@Bean
时加上@LoadBalanced
限定就行。
若是须要混用的话,能够参见下面的例子:
@Configuration public class MyConfiguration { @LoadBalanced @Bean RestTemplate loadBalanced() { return new RestTemplate(); } @Primary @Bean RestTemplate restTemplate() { return new RestTemplate(); } } public class MyClass { @Autowired private RestTemplate restTemplate; @Autowired @LoadBalanced private RestTemplate loadBalanced; public String doOtherStuff() { return loadBalanced.getForObject("http://stores/stores", String.class); } public String doStuff() { return restTemplate.getForObject("http://example.com", String.class); } }
使用
@Primary
限定,避免@Autowired
混淆。 若是上面的代码在进行RestOperations
操做时,出现java.lang.IllegalArgumentException
异常,能够设置spring.aop.proxyTargetClass=true
来解决。
有的时候须要忽略某个名字的网络接口,把他们排除在服务发现注册以外。(如:运行于Docker容器) 能够设置一组正则表达式来对接口名进行匹配,来进行忽略这些接口:
application.yml
spring: cloud: inetutils: ignoredInterfaces: - docker0 - veth.*