002-Spring Cloud 功能简介
一、主要功能
分布式/版本化配置、服务注册与发现、路由、服务间调用、负载均衡、断路器、分布式消息传递
1、云本地应用【Cloud Native Applications】
Spring Cloud Context 上下文和Spring Cloud Commons。Spring Cloud Context为Spring Cloud应用程序的ApplicationContext(引导上下文、加密、刷新范围和环境端点)提供实用程序和特殊服务。Spring Cloud Commons是不同的Spring Cloud实现的一套抽象和公共类集合(比如Spring Cloud Netflix和Spring Cloud Consul)。
注意:如果由于“非法密钥大小Illegal key size”而获得异常,并且使用Sun的JDK,则需要安装Java加密扩展(JCE)无限强度管辖权策略文件。:
无论JRE/JDK x64/x86版本,请放置在JDK/jre/lib/security
github地址:https://github.com/spring-cloud
1.1、Spring云上下文:应用上下文服务
1.1.1、The Bootstrap Application Context【引导上下文】
用于应用程序上下文的引导阶段。它通常用于“使用Spring Cloud Config Server时,应在bootstrap.yml中指定spring.application.name和spring.cloud.config.server.git.uri”以及一些加密/解密信息。技术上,bootstrap.yml由父Spring ApplicationContext加载。父ApplicationContext被加载到使用application.yml的之前。
例如,当使用Spring Cloud时,通常从服务器加载“real”配置数据。为了获取URL(和其他连接配置,如密码等),您需要一个较早的或“bootstrap”配置。因此,您将配置服务器属性放在bootstrap.yml中,该属性用于加载实际配置数据(通常覆盖application.yml [如果存在]中的内容)。
bootstrap.yml(bootstrap.properties)用来程序引导时执行,应用于更加早期配置信息读取,如可以使用来配置application.yml中使用到参数等
application.yml(application.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
bootstrap.yml 先于 application.yml 加载
spring: application: name: foo cloud: config: uri: ${SPRING_CONFIG_URI:http://localhost:8888}
您可以通过设置spring.cloud.bootstrap.enabled=false(例如在系统属性中)来完全禁用引导过程。
1.1.2、Application Context Hierarchies【应用上下文层次结构】
如果您从SpringApplication或SpringApplicationBuilder构建应用程序上下文,则将Bootstrap上下文添加为该上下文的父级。
这是一个Spring的功能,即子上下文从其父进程继承属性源和配置文件,因此与不使用Spring Cloud Config构建相同上下文相比,“主”应用程序上下文将包含其他属性源。额外的属性来源是:
“bootstrap”:如果在Bootstrap上下文中找到任何PropertySourceLocators,则可选CompositePropertySource显示为高优先级,并且具有非空属性。
一个例子是来自Spring Cloud Config服务器的属性。
“applicationConfig:[classpath:bootstrap.yml]”(如果Spring配置文件处于活动状态,则为朋友)。如果您有一个bootstrap.yml(或属性),那么这些属性用于配置引导上下文,然后在父进程设置时将它们添加到子上下文中。它们的优先级低于application.yml(或.properties)以及作为创建Spring Boot应用程序的过程的正常部分添加到子级的任何其他属性源。
由于属性源的排序规则,“bootstrap”条目优先,但请注意,这些条目不包含来自bootstrap.yml的任何数据,它具有非常低的优先级,但可用于设置默认值。
说明:
bootstrap.yml 和application.yml 都可以用来配置参数
bootstrap.yml可以理解成系统级别的一些参数配置,这些参数一般是不会变动的(Spring cloud)
application.yml 可以用来定义应用级别的,如果搭配spring-cloud-config使用 application.yml里面定义的文件可以实现动态替换
您可以通过简单地设置您创建的任何ApplicationContext的父上下文来扩展上下文层次结构,例如使用自己的界面,或使用SpringApplicationBuilder方便方法(parent(),child()和sibling())。
说明:
如果SpringApplication无法满足要求,你可以自己创建一个局部实例,然后对其进行设置:
public static void main(String[] args) { SpringApplication app = new SpringApplication(MySpringConfiguration.class); //关闭Banner打印 app.setBannerMode(Banner.Mode.OFF); //添加监听器 app.addListeners(new MyListener()); //... app.run(args); }
SpringApplication的相关配置将会被@Configuration注解的类,XML配置文件,以及Spring扫描的包引用。
你也可以通过SpringApplicationBuilder来对SpringApplication的属性进行配置,这样的结构更有层次感。SpringApplicationBuilder为构 建 SpringApplication 和 ApplicationContext 实例提供了一套便利的流式API:
new SpringApplicationBuilder() .sources(Parent.class) .child(Application.class) .bannerMode(Banner.Mode.OFF) .listeners(new MyListener()) ... .run(args);
SpringApplication将会根据需要创建一个ApplicationContext,默认情况下,如果是非web应用,则会创建一个AnnotationConfigApplicationContext上下文,如果是web应用,则会创建一个AnnotationConfigEmbeddedWebApplicationContext上下文。当然,你也可以通过setWebEnvironment(boolean webEnvironment)来覆盖默认的设置。
引导环境将是您创建自己的最高级祖先的父级。层次结构中的每个上下文都将有自己的“bootstrap”属性源(可能为空),以避免无意中将值从父级升级到其后代。层次结构中的每个上下文(原则上)也可以具有不同的spring.application.name,因此如果存在配置服务器,则不同的远程属性源。
普通的Spring应用程序上下文行为规则适用于属性解析:子环境中的属性通过名称和属性源名称覆盖父项中的属性(如果子级具有与父级名称相同的属性源,一个来自父母的孩子不包括在孩子中)。
请注意,SpringApplicationBuilder允许您在整个层次结构中共享Environment,但这不是默认值。因此,尤其不需要具有相同的资料或财产来源,尽管它们与父级共享共同点。
1.1.3、Changing the Location of Bootstrap Properties(改变引导位置Properties)
可以使用spring.cloud.bootstrap.name(默认“bootstrap”)或spring.cloud.bootstrap.location(默认为空)指定bootstrap.yml(或.properties)位置,例如在系统属性中。这些属性的行为类似于具有相同名称的spring.config.*变体,实际上它们用于通过在其Environment中设置这些属性来设置引导ApplicationContext。如果在正在构建的上下文中有活动的配置文件(来自spring.profiles.active或通过Environment API)),则该配置文件中的属性也将被加载,就像常规的Spring Boot应用程序,例如来自bootstrap-development.properties的“develop”配置,根据不同的环境配置不同的字段属性。
1.1.4、重写Remote Properties的值
通过引导上下文添加到应用程序中的属性源通常是“远程”的(例如来自SpringCloudConfig Server)。默认情况下,它们不能在本地被重写。如果您想让应用程序使用自己的系统属性或配置文件覆盖远程属性,则远程属性源必须通过设置Spring.Cloud.config.发给它权限(它不能在本地设置此属性)来授予它权限。设置该标志后,两个更细粒度的设置根据系统属性和应用程序的本地配置控制远程属性的位置:Spring.Cloud.config.overrideNone=true:spring.cloud.config.overrideSystemProperties=false:只覆盖系统属性、命令行参数和环境变量(而不是本地配置文件)。
1.1.5、Customizing the Bootstrap Configuration(自定义引导配置)
可以通过在org.springframework.cloud.bootstrap.BootstrapConfiguration键下添加条目/META-INF/spring.factories来训练引导上下文来执行任何您喜欢的操作。这是用于创建上下文的Spring @Configuration类的逗号分隔列表。您可以在此处创建要用于自动装配的主应用程序上下文的任何bean,并且还有ApplicationContextInitializer类型的@Beans的特殊合同。如果要控制启动顺序(默认顺序为“最后”),可以使用@Order标记类。
警告
添加自定义BootstrapConfiguration时,请注意,添加的类不在@ComponentScanned扫描您的“主”应用程序上下文中或@SpringBootApplication注释配置类尚未涵盖的启动配置类,请使用单独的包名称。
@SpringBootApplication(scanBasePackages = {"com.o2b","com.o2c"})
引导过程通过将初始化器注入主SpringApplication实例(即正常的Spring Boot启动顺序,无论是作为独立应用程序运行还是部署在应用程序服务器中)结束。首先,从spring.factories中找到的类创建引导上下文,然后在ApplicationContextInitializer类型的所有@Beans添加到主SpringApplication开始之前
1.1.6、Customizing the Bootstrap Property Sources(自定义引导属性源)
引导过程添加的外部配置的默认属性源是Config Server,但您可以通过将PropertySourceLocator类型的bean添加到引导上下文(通过spring.factories)添加其他源。您可以使用此方法从其他服务器或数据库中插入其他属性。
作为一个例子,请考虑以下自定义定位器:
@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")); } }
传入的Environment是要创建的ApplicationContext的Environment,即为我们提供额外的属性来源的。它将已经具有正常的Spring Boot提供的资源来源,因此您可以使用它们来定位特定于此Environment的属性源(例如通过将其绑定在spring.application.name上,如在默认情况下所做的那样Config Server属性源定位器)。
如果你在这个类中创建一个jar,然后添加一个META-INF/spring.factories包含:
org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator 那么“customProperty”PropertySource将显示在其类路径中包含该jar的任何应用程序中。
1.1.7、Logging Configuration【日志配置】
如果您打算使用SpringBoot来配置日志设置,则应该将此配置放在‘bootstrap.[yml\properties]中,如果您希望将其应用于所有事件。
[注意]如果SpringCloud要正确初始化日志配置,就不能使用自定义前缀。例如,当初始化日志系统时,使用custom.loggin.logpath将不会被SpringCloud识别。
1.1.8、环境变化
应用程序将监听EnvironmentChangeEvent,并以几种标准方式进行更改(用户可以正常方式以@bean的形式添加附加的ApplicationListener)。当观察到EnvironmentChangeEvent时,它将有一个已更改的键值列表,应用程序将使用以下内容:
重新绑定上下文中的任何@ConfigurationProperties bean
为logging.level.*中的任何属性设置记录器级别
请注意,配置客户端不会通过默认轮询查找Environment中的更改,通常我们不建议检测更改的方法(尽管可以使用@Scheduled注释进行设置)。如果您有一个扩展的客户端应用程序,那么最好将EnvironmentChangeEvent广播到所有实例,而不是让它们轮询更改(例如使用Spring Cloud总线)。
EnvironmentChangeEvent涵盖了大量的刷新用例,只要您真的可以更改Environment并发布事件(这些API是公开的,部分内核为Spring)。您可以通过访问/configprops端点(普通Spring Boot执行器功能)来验证更改是否绑定到@ConfigurationProperties bean。例如,DataSource可以在运行时更改其maxPoolSize(由Spring Boot创建的默认DataSource是一个@ConfigurationProperties bean),并且动态增加容量。重新绑定@ConfigurationProperties不会覆盖另一大类用例,您需要更多的控制刷新,并且您需要更改在整个ApplicationContext上是原子的。为了解决这些担忧,我们有@RefreshScope。
1.1.9、刷新作用域
当发生配置更改时,标记为@RefreshScope的Spring@Bean将得到特殊待遇。这个特性解决了有状态bean的问题,只有在初始化它们时才会注入它们的配置。例如,当通过环境更改数据库URL时,如果DataSource具有打开的连接,您可能希望这些连接的持有者能够完成他们正在做的事情。然后,当某物下一次从池中借用一个连接时,它会得到一个带有新URL的连接。
有时,在某些只能初始化一次的bean上应用@RefreshScope注释甚至是强制性的。如果一个bean是“不可变的”,那么您必须用@RefreshScope对bean进行注释,或者在属性键Spring.Cloud.刷新.额外刷新项下指定类名。
刷新作用域bean是在使用时(即调用方法时)初始化的惰性代理,该作用域充当初始化值的缓存。若要强制bean在下一个方法调用中重新初始化,您必须使其缓存条目失效。
RefreshScope是上下文中的bean,并具有一个通过清除目标缓存来刷新作用域中所有bean的公共REFERHAll()方法。/REFRESH端点公开此功能(通过HTTP或JMX)。要按名称刷新单个bean,还需要一个REFRESH(String)方法。
要展开 /refresh 节点需要增加配置
management:
endpoints:
web:
exposure:
include: refresh
注意:@RefreshScope(技术上)适用于@Configuration类,但它可能会导致令人惊讶的行为。例如,这并不意味着该类中定义的所有@bean都在@RefreshScope中。具体来说,任何依赖于这些bean的东西都不能依赖它们在启动刷新时被更新,除非它本身在@RefreshScope中。在这种情况下,它是在刷新时重建的,并且它的依赖项被重新注入。此时,它们将从刷新的@配置中重新初始化)。
1.1.10、加密与解密
Spring Cloud有一个用于本地解密属性值的环境预处理器。它遵循与配置服务器相同的规则,通过encrypt.*具有相同的外部配置。因此,您可以以{cipher}*的形式使用加密的值,只要有一个有效的密钥,它们就会在主应用程序上下文获得环境设置之前被解密。要在应用程序中使用加密特性,您需要在类路径中包含Spring Security RSA (Maven坐标:“org.springframework.security: Spring - Security - RSA”),并且您还需要在JVM中包含完整的JCE扩展。
1.1.11、管理点
对于Spring引导执行器应用程序,可以使用一些额外的管理端点。您可以使用:
POST
to/actuator/env
to update theEnvironment
and rebind@ConfigurationProperties
and log levels./actuator/refresh
to re-load the boot strap context and refresh the@RefreshScope
beans./actuator/restart
to close theApplicationContext
and restart it (disabled by default)./actuator/pause
and/actuator/resume
for calling theLifecycle
methods (stop()
andstart()
on theApplicationContext
).
If you disable the /actuator/restart
endpoint then the /actuator/pause
and /actuator/resume
endpoints will also be disabled since they are just a special case of /actuator/restart
.
1.2、Spring Cloud Commons: Common Abstractions
服务发现、负载平衡和断路器等模式将自己提供给一个公共的抽象层,该抽象层可以由所有Spring cloud clients使用,而不依赖于实现(例如,使用Eureka或Consul 服务发现)。
1.2.1、@EnableDiscoveryClient
Spring Cloud Commons提供了@EnableDiscoveryClient注解。这是使用META-INF/spring.factories查找DiscoveryClient接口的实现。添加一个实现org.springframework.cloud.client.discovery.EnableDiscoveryClien的配置类t到spring.factories下。DiscoveryClient实现的例子包括Spring Cloud Netflix Eureka、Spring Cloud Consul Discovery和Spring Cloud Zookeeper Discovery。
默认情况下,DiscoveryClient的实现会使用远程发现服务器自动注册本地Spring引导服务器。通过在@EnableDiscoveryClient中设置autoRegister=false,可以禁用此行为。
不再需要@EnableDiscoveryClient。您可以将DiscoveryClient实现放到classpath中,以使Spring引导应用程序注册到服务发现服务器。
1.2.2、服务注册
示例
@Configuration @EnableDiscoveryClient(autoRegister=false) public class MyConfiguration { private ServiceRegistry registry; public MyConfiguration(ServiceRegistry registry) { this.registry = registry; } // called through some external process, such as an event or a custom actuator endpoint public void register() { Registration registration = constructRegistration(); this.registry.register(registration); } }
注册接口:
ZookeeperRegistration
used withZookeeperServiceRegistry
EurekaRegistration
used withEurekaServiceRegistry
ConsulRegistration
used withConsulServiceRegistry
如果您正在使用ServiceRegistry接口,则需要为您正在使用的ServiceRegistry实现传递正确的注册表实现。
1.2.2.1、服务自动注册
默认情况下,ServiceRegistry实现自动注册正在运行的服务。要禁用该行为,可以设置:* @EnableDiscoveryClient(autoRegister=false)永久禁用自动注册。* :spring.cloud.service-registry.auto-registration.enabled=false通过配置禁用行为。
1.2.2.2、服务注册执行点
Spring Cloud Commons提供了一个/service-registry执行器端点。这个端点依赖于Spring应用程序上下文中的注册bean。带有GET的调用/service registry返回注册状态。使用POST到与JSON主体相同的端点会将当前注册的状态更改为新值。JSON主体必须包含具有首选值的状态字段。请参阅在更新状态和为状态返回值时为允许值使用的ServiceRegistry实现的文档。例如,Eureka支持的状态是UP、DOWN、OUT_OF_SERVICE和UNKNOWN。
1.2.3、Spring RestTemplate as a Load Balancer Client
RestTemplate可以自动配置为使用ribbon。要创建一个负载均衡的RestTemplate,请创建一个RestTemplate @Bean,并使用@LoadBalanced限定符,如下例所示:
@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 bean不再通过自动配置创建。单个应用程序必须创建它。
URI需要使用虚拟主机名(即服务名,而不是主机名)。Ribbon客户端用于创建完整的物理地址。
1.2.4、Spring WebClient as a Load Balancer Client
可以自动配置WebClient来使用loadbalancercerclient。要创建负载均衡的WebClient,请创建WebClient。构建器@Bean并使用@LoadBalanced限定符,如下例所示:
@Configuration public class MyConfiguration { @Bean @LoadBalanced public WebClient.Builder loadBalancedWebClientBuilder() { return WebClient.builder(); } } public class MyClass { @Autowired private WebClient.Builder webClientBuilder; public Mono<String> doOtherStuff() { return webClientBuilder.build().get().uri("http://stores/stores") .retrieve().bodyToMono(String.class); } }
URI需要使用虚拟主机名(即服务名,而不是主机名)。Ribbon客户端用于创建完整的物理地址。
1.2.4.1、重试失败请求
可以配置负载平衡的RestTemplate重试失败的请求。默认情况下,该逻辑是禁用的。您可以通过将Spring Retry添加到应用程序的类路径来启用它。负载平衡的RestTemplate尊重一些与重新尝试失败请求相关的Ribbon配置值。您可以使用client.ribbon.MaxAutoRetries
, client.ribbon.MaxAutoRetriesNextServer
, 和client.ribbon.OkToRetryOnAllOperations
属性。如果您想在类路径上禁用Spring重试的重试逻辑,您可以设置spring.cloud.loadbalancer.retry.enabled=false。有关这些属性的作用,请参阅Ribbon文档。
如果您想在重试中实现备份策略,您需要创建一个LoadBalancedBackOffPolicyFactory类型的bean,并返回您想为给定服务使用的备份策略,如下例所示:
@Configuration public class MyConfiguration { @Bean LoadBalancedBackOffPolicyFactory backOffPolciyFactory() { return new LoadBalancedBackOffPolicyFactory() { @Override public BackOffPolicy createBackOffPolicy(String service) { return new ExponentialBackOffPolicy(); } }; } }
客户端应该被替换为您的Ribbon客户端名称。
如果您想在重试功能中添加一个或多个RetryListener实现,您需要创建一个LoadBalancedRetryListenerFactory类型的bean,并返回您想为给定服务使用的RetryListener数组,如下例所示:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Configuration public class MyConfiguration { @Bean LoadBalancedRetryListenerFactory retryListenerFactory() { return new LoadBalancedRetryListenerFactory() { @Override public RetryListener[] createRetryListeners(String service) { return new RetryListener[]{new RetryListener() { @Override public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) { //TODO Do you business... return true; } @Override public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { //TODO Do you business... } @Override public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { //TODO Do you business... } }}; } }; } }
1.2.5、多RestTemplate 对象
如果您想要一个没有负载平衡的RestTemplate,那么创建一个RestTemplate bean并注入它。要访问负载平衡的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); } }
注意,在前面的示例中,在普通RestTemplate声明中使用@Primary注释来消除不合格的@Autowired注入的歧义。
出现如下错误 java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89
,可以注入 RestOperations
或设置 spring.aop.proxyTargetClass=true
.