一、主要功能
分布式/版本化配置、服務注冊與發現、路由、服務間調用、負載均衡、斷路器、分布式消息傳遞
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引導執行器應用程序,可以使用一些額外的管理端點。您可以使用:
POSTto/actuator/envto update theEnvironmentand rebind@ConfigurationPropertiesand log levels./actuator/refreshto re-load the boot strap context and refresh the@RefreshScopebeans./actuator/restartto close theApplicationContextand restart it (disabled by default)./actuator/pauseand/actuator/resumefor calling theLifecyclemethods (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); } }
注冊接口:
ZookeeperRegistrationused withZookeeperServiceRegistryEurekaRegistrationused withEurekaServiceRegistryConsulRegistrationused 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數組,如下例所示:
@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.
