[toc]
SpringCloud父類
在pom.xml
中添加spring-cloud-dependencies
統(tǒng)一管理版本:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RC1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
服務(wù)注冊(cè)與發(fā)現(xiàn)中心Euerka
Spring Cloud Netflix 的 Eureka袍榆,Eureka 是一個(gè)服務(wù)注冊(cè)和發(fā)現(xiàn)模塊裕菠。
2.1. 引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
服務(wù)端配置
配置application.yml
在默認(rèn)情況下 Erureka Server 也是一個(gè) Eureka Client ,必須要指定一個(gè) Server拧略。
spring:
application:
name: hello-spring-cloud-eureka
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
通過 eureka.client.registerWithEureka:false
和 fetchRegistry:false
來表明自己是一個(gè) Eureka Server瓷翻。
服務(wù)端注解
啟動(dòng)一個(gè)服務(wù)注冊(cè)中心社证,只需要一個(gè)注解 @EnableEurekaServer
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
客戶端配置
配置application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
客戶端注解
通過注解 @EnableEurekaClient
表明自己是一個(gè) Eureka Client绿满。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ServiceAdminApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceAdminApplication.class, args);
}
}
負(fù)載均衡客戶端Ribbon
Ribbon 是一個(gè)負(fù)載均衡客戶端内地,可以很好的控制 http 和 tcp 的一些行為色罚。
3.1. 引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
發(fā)現(xiàn)服務(wù)配置
通過 @EnableDiscoveryClient 注解獲取注冊(cè)到服務(wù)中心的服務(wù)碰缔。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class WebAdminRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminRibbonApplication.class, args);
}
}
負(fù)載均衡客戶端Feign
Feign 是一個(gè)聲明式的偽 Http 客戶端, 支持可插拔的編碼器和解碼器戳护。Feign 默認(rèn)集成了 Ribbon金抡,并和 Eureka 結(jié)合,默認(rèn)實(shí)現(xiàn)了負(fù)載均衡的效果
- Feign 采用的是基于接口的注解
- Feign 整合了 ribbon
引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
開啟Feign注解
通過 @EnableFeignClients
注解開啟 Feign 功能腌且。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class WebAdminFeignApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminFeignApplication.class, args);
}
}
熔斷器Hystrix
Netflix 開源了 Hystrix 組件梗肝,實(shí)現(xiàn)了熔斷器模式,Spring Cloud 對(duì)這一組件進(jìn)行了整合铺董。
引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
開啟熔斷器配置
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
@SpringBootApplication
@EnableCircuitBreaker
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
使用注解@HystrixCommand
@HystrixCommand(fallbackMethod = "fallbackEcho")
@GetMapping(value = "/echo/app/name")
public String echo() {
TbUser tbUser = new TbUser();
tbUser.setUsername("adfad");
TbUser serviceOne = userService.findOne(tbUser);
return "test";
}
public String fallbackEcho(){
return "error";
}
Feign中使用熔斷器配置
Feign 是自帶熔斷器的巫击,但默認(rèn)是關(guān)閉的。需要在配置文件中配置打開它精续,在application.yml
配置文件增加以下代碼:
feign:
hystrix:
enabled: true
熔斷器Hystrix儀表盤監(jiān)控
引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
增加儀表盤注解
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
@EnableHystrixDashboard
public class WebAdminRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminRibbonApplication.class, args);
}
}
訪問路徑:http://ip:port/hystrix
創(chuàng)建 hystrix.stream 的 Servlet 配置
Spring Boot 2.x 版本開啟 Hystrix Dashboard 與 Spring Boot 1.x 的方式略有不同坝锰,需要增加一個(gè) HystrixMetricsStreamServlet
的配置,代碼如下:
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HystrixDashboardConfiguration {
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
路由網(wǎng)關(guān)Zuul
Zuul 的主要功能是路由轉(zhuǎn)發(fā)和過濾器重付。
添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
開啟路由網(wǎng)關(guān)
增加 @EnableZuulProxy 注解開啟 Zuul 功能顷级。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
配置application.yml
zuul:
routes:
api-a:
path: /api/a/**
serviceId: hello-spring-cloud-web-admin-ribbon
api-b:
path: /api/b/**
serviceId: hello-spring-cloud-web-admin-feign
- 以 /api/a 開頭的請(qǐng)求都轉(zhuǎn)發(fā)給 hello-spring-cloud-web-admin-ribbon 服務(wù)
- 以 /api/b 開頭的請(qǐng)求都轉(zhuǎn)發(fā)給 hello-spring-cloud-web-admin-feign 服務(wù)
配置中心Config
在分布式系統(tǒng)中,由于服務(wù)數(shù)量巨多确垫,為了方便服務(wù)配置文件統(tǒng)一管理弓颈,實(shí)時(shí)更新,所以需要分布式配置中心組件删掀。在 Spring Cloud 中翔冀,有分布式配置中心組件 Spring Cloud Config。
服務(wù)端配置
添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
開啟配置中心服務(wù)
通過 @EnableConfigServer
注解爬迟,開啟配置服務(wù)器功能橘蜜。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
}
配置application.yml
spring:
application:
name: hello-spring-cloud-config
cloud:
config:
label: master
server:
git:
uri: https://github.com/topsale/spring-cloud-config
search-paths: respo
username:
password:
server:
port: 8888
- spring.cloud.config.label:配置倉(cāng)庫(kù)的分支
- spring.cloud.config.server.git.uri:配置 Git 倉(cāng)庫(kù)地址(GitHub、GitLab、碼云 ...)
- spring.cloud.config.server.git.search-paths:配置倉(cāng)庫(kù)路徑(存放配置文件的目錄)
- spring.cloud.config.server.git.username:訪問 Git 倉(cāng)庫(kù)的賬號(hào)
- spring.cloud.config.server.git.password:訪問 Git 倉(cāng)庫(kù)的密碼
服務(wù)端配置
添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
配置application.yml
spring:
application:
name: hello-spring-cloud-config-client
cloud:
config:
uri: http://localhost:8888
name: config-client
label: master
profile: dev
相關(guān)配置說明计福,如下:
- spring.cloud.config.uri:配置服務(wù)中心的網(wǎng)址
- spring.cloud.config.name:配置文件名稱的前綴
- spring.cloud.config.label:配置倉(cāng)庫(kù)的分支
- spring.cloud.config.profile:配置文件的環(huán)境標(biāo)識(shí)
dev:表示開發(fā)環(huán)境
test:表示測(cè)試環(huán)境
prod:表示生產(chǎn)環(huán)境
注意事項(xiàng):
配置服務(wù)器的默認(rèn)端口為 8888跌捆,如果修改了默認(rèn)端口,則客戶端項(xiàng)目就不能在 application.yml 或 application.properties 中配置 spring.cloud.config.uri象颖,必須在 bootstrap.yml 或是 bootstrap.properties 中配置佩厚,原因是 bootstrap 開頭的配置文件會(huì)被優(yōu)先加載和配置。
鏈路追蹤ZipKin
ZipKin 是一個(gè)開放源代碼的分布式跟蹤系統(tǒng)说订,由 Twitter 公司開源抄瓦,它致力于收集服務(wù)的定時(shí)數(shù)據(jù),以解決微服務(wù)架構(gòu)中的延遲問題陶冷,包括數(shù)據(jù)的收集钙姊、存儲(chǔ)、查找和展現(xiàn)埂伦。
服務(wù)端配置
添加依賴
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>2.10.1</version>
</dependency>
開啟服務(wù)配置
通過 @EnableZipkinServer 注解開啟 Zipkin Server 功能煞额。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin.server.internal.EnableZipkinServer;
@SpringBootApplication
@EnableZipkinServer
public class ZipKinApplication {
public static void main(String[] args) {
SpringApplication.run(ZipKinApplication.class, args);
}
}
配置application.yml
設(shè)置端口號(hào)為:9411,該端口號(hào)為 Zipkin Server 的默認(rèn)端口號(hào)沾谜。
spring:
application:
name: hello-spring-cloud-zipkin
server:
port: 9411
management:
metrics:
web:
server:
auto-time-requests: false
客戶端端配置
添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
配置application.yml
spring:
zipkin:
base-url: http://localhost:9411
路由網(wǎng)關(guān)Gateway
Spring Cloud Gateway 是 Spring 官方基于 Spring 5.0膊毁,Spring Boot 2.0 和 Project Reactor 等技術(shù)開發(fā)的網(wǎng)關(guān),Spring Cloud Gateway 旨在為微服務(wù)架構(gòu)提供一種簡(jiǎn)單而有效的統(tǒng)一的 API 路由管理方式基跑。
添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
- Spring Cloud Gateway 不使用 Web 作為服務(wù)器婚温,而是 使用 WebFlux 作為服務(wù)器,Gateway 項(xiàng)目已經(jīng)依賴了 starter-webflux媳否,所以這里 千萬(wàn)不要依賴 starter-web
- 由于過濾器等功能依然需要 Servlet 支持栅螟,故這里還需要依賴 javax.servlet:javax.servlet-api
配置application.yml
spring:
application:
# 應(yīng)用名稱
name: spring-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.25.138:8848
# 路由網(wǎng)關(guān)配置
gateway:
# 設(shè)置與服務(wù)注冊(cè)發(fā)現(xiàn)組件結(jié)合,這樣可以采用服務(wù)名的路由策略
discovery:
locator:
enabled: true
# 配置路由規(guī)則
routes:
# 采用自定義路由 ID(有固定用法篱竭,不同的 id 有不同的功能嵌巷,詳見:https://cloud.spring.io/spring-cloud-gateway/2.0.x/single/spring-cloud-gateway.html#gateway-route-filters)
- id: NACOS-CONSUMER
# 采用 LoadBalanceClient 方式請(qǐng)求,以 lb:// 開頭室抽,后面的是注冊(cè)在 Nacos 上的服務(wù)名
uri: lb://nacos-consumer
# Predicate 翻譯過來是“謂詞”的意思,必須靡努,主要作用是匹配用戶的請(qǐng)求坪圾,有很多種用法
predicates:
# Method 方法謂詞,這里是匹配 GET 和 POST 請(qǐng)求
- Method=GET,POST
- Path=/api/consumer/**
filters:
# 前綴過濾惑朦,默認(rèn)配置下兽泄,我們的請(qǐng)求路徑是 http://localhost:9000/nacos-consumer/** 這時(shí)會(huì)路由到指定的服務(wù)
# 此處配置去掉 1 個(gè)路徑前綴,再配置上面的 Path=/api/**漾月,就能按照 http://localhost:9000/api/** 的方式訪問了
- StripPrefix=1
- id: NACOS-CONSUMER-FEIGN
uri: lb://nacos-consumer-feign
predicates:
- Method=GET,POST
- Path=/api/feign/**
filters:
- StripPrefix=1
server:
port: 9000
# 配置日志級(jí)別病梢,方別調(diào)試
logging:
level:
org.springframework.cloud.gateway: debug
解決跨域問題配置
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator;
import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.codec.support.DefaultServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
// ----------------------------- 解決跨域 Begin -----------------------------
private static final String ALL = "*";
private static final String MAX_AGE = "18000L";
@Bean
public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
}
@Bean
public ServerCodecConfigurer serverCodecConfigurer() {
return new DefaultServerCodecConfigurer();
}
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (!CorsUtils.isCorsRequest(request)) {
return chain.filter(ctx);
}
HttpHeaders requestHeaders = request.getHeaders();
ServerHttpResponse response = ctx.getResponse();
HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
HttpHeaders headers = response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
if (requestMethod != null) {
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
}
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL);
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
return chain.filter(ctx);
};
}
// ----------------------------- 解決跨域 End -----------------------------
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}