原生應用:是一種程序開發風格,是連續交付(持續集成)和值驅動領域的最佳實踐。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.*