【Spring-Cloud】使用教程 基礎(chǔ)篇 Eureka Ribbon Feign Hystrix Zuul Dashboard Sleuth Zipkin Config Bus

==1. Eureka-Server==

1.1 新建eureka-server項(xiàng)目蹋订,添加pom依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

1.2 修改application.yml

1.2.1 單例

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

1.2.2 多例

---
spring:
  profiles: peer1
eureka:
  instance:
    hostname: peer1
  client:
    serviceUrl:
      defaultZone: http://peer2/eureka/

---
spring:
  profiles: peer2
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: http://peer1/eureka/

1.3 添加注解

@EnableEurekaServer

==2. Eureka-Client==

2.1 對應(yīng)的服務(wù)中七嫌,添加pom依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2.2 修改application.yml

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

2.3 添加注解

@EnableEurekaClient

==3. Ribbon==

3.1 對應(yīng)的服務(wù)中描沟,添加pom依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

3.2 修改application.yml

beebee-archives-thrift-consumer: # 服務(wù)提供者的名稱
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 負(fù)載均衡策略

3.3 啟動(dòng)類

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

3.4 添加工具類 EurekaUtil

@Configuration
public class EurekaUtil {
    @Autowired
    private  RestTemplate restTemplate;
    @Autowired
    private  LoadBalancerClient loadBalancerClient;
    /**
     * 遠(yuǎn)程調(diào)用
     * @param server 調(diào)用的服務(wù)器
     * @param method 調(diào)用的方法
     * @param p 方法的參數(shù)
     */
    public <P> String remoteInvoke(String server, String method, P p) {
        ServiceInstance serviceInstance = loadBalancerClient.choose(server);
        return restTemplate.postForObject("http://" + serviceInstance.getServiceId() + method, p, String.class);
    }
}

3.5 Controller調(diào)用

@PostMapping("/getList")
public String getList(ArchivesListParam param) {
    return eurekaUtil.remoteInvoke(Server.BEEBEE_ARCHIVES_THRIFT_PROVIDER_CLIENT, Method.ARCHIVES_GET_LIST, param);
}

==4. Feign==

4.1 對應(yīng)的服務(wù)中切心,添加pom依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

4.2 啟動(dòng)類添加注解

@EnableFeignClients

4.3 在service.impl下欺抗,添加 interface

@FeignClient(name = "product-service")
public interface ProductClient {
    @GetMapping("/api/v1/product/find")
    String findById(@RequestParam("id") int id);
}

4.4 在OrderServiceImpl下使用

@Autowired
private ProductClient productClient;

String resp = productClient.findById(productId);

==5. Hystrix==

5.1 對應(yīng)的服務(wù)中墓毒,添加pom依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

5.2 啟動(dòng)類添加注解

@EnableCircuitBreaker

5.3 OrderController使用

@Autowired
private StringRedisTemplate redisTemplate;

@RequestMapping("save")
@HystrixCommand(fallbackMethod = "saveOrderFail")
public Object save(int userId, int productId, HttpServletRequest request) {
    Map<String, Object> data = new HashMap<>();
    data.put("code", 0);
    data.put("data", orderService.save(userId, productId));
    return data;
}

private Object saveOrderFail(int userId, int productId, HttpServletRequest request) {
    String saveOrderKey = "save-order";
    String saveValue = redisTemplate.opsForValue().get(saveOrderKey);
    String ip = request.getRemoteAddr();

    new Thread(() -> {
        if (StringUtils.isBlank(saveValue)) {
            // TODO 調(diào)用短信接口 ip服務(wù)器宕機(jī),請盡快處理
            redisTemplate.opsForValue().set(saveOrderKey, "save-order-fail", 30, TimeUnit.SECONDS);
        } else {
            // TODO 30s內(nèi)不再重發(fā)
        }
    }).start();

    Map<String, Object> msg = new HashMap<>();
    msg.put("code", -1);
    msg.put("msg", "搶購人數(shù)太多包帚,您被寄出來了");
    return msg;
}

==6. Feign 結(jié)合 Hystrix==

6.1 開啟Feign支持Hystrix

feign:
  hystrix:
    enabled: true

6.2 在fallback包下創(chuàng)建ProductClientFallback

@Component
public class ProductClientFallback implements ProductClient {
    @Override
    public String findById(int id) {
        System.out.println("異常處理:記錄日志、發(fā)送短信或郵件");
        return null;
    }
}

6.3 在注解@FeignClient添加fallback類

@FeignClient(name = "product-service", fallback = ProductClientFallback.class)
public interface ProductClient {
    @GetMapping("/api/v1/product/find")
    String findById(@RequestParam("id") int id);
}

==7. 斷路器Dashboard監(jiān)控儀表盤==

7.1 對應(yīng)的服務(wù)中曹质,添加pom依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

7.2 啟動(dòng)類添加注解

@EnableHystrixDashboard

7.3 修改application.yml

management:
  endpoints:
    web:
      exposure:
        include: "*"

7.4 訪問入口

http://localhost:8781/hystrix
http://localhost:8781/actuator/hystrix.stream

7.5 斷路器圖示

斷路器close狀態(tài)

graph LR
consumer-->斷路器
斷路器-->provider

斷路器半開狀態(tài)

graph LR
consumer-.->斷路器
斷路器-->provider

斷路器open狀態(tài)

graph LR
consumer-.X.->斷路器
斷路器-->provider

==8. Zuul==

8.1 新建beebee-zuul項(xiàng)目婴噩,添加pom依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

8.2 啟動(dòng)類添加注解

@EnableZuulProxy

8.3 訪問

之前:http://localhost:8781/api/v1/order/save?userId=1&productId=1
現(xiàn)在:http://localhost:9000/order-service/api/v1/order/save?userId=1&productId=1
訪問規(guī)則:http://ip:port/service-id/*
注意:order-service 注意大小寫,需要和application.yml配置的一樣

8.4 自定義路由

server:
  port: 9000
spring:
  application:
    name: beebee-api
zuul:
  routes:
    order-service: /beebee-api/order/**  # 自定義服務(wù)名稱
    product-service: /beebee-api/product/**  # 此名稱不要與上面沖突羽德,否則會(huì)覆蓋上面的
  ignored-services: product-service  # 忽略一個(gè)几莽,忽略商品服務(wù),不能通過 http://localhost:9000/product-service/... 訪問
  ignored-patterns: /*-service/**  # 忽略多個(gè)宅静,只能通過 http://localhost:9000/beebee-api/... 訪問   
        
訪問方式:http://localhost:9000/beebee-api/api/v1/order/save?userId=1&productId=1

8.5 Http請求頭過濾問題

@ConfigurationProperties("zuul")
public class ZuulProperties {
    // 默認(rèn)以下三個(gè)敏感信息不傳遞到下游服務(wù)器
    private Set<String> sensitiveHeaders = new LinkedHashSet<>(Arrays.asList("Cookie", "Set-Cookie", "Authorization"));
}

# 將此屬性置為空
zuul:
  sensitive-headers:

8.6 zuul流程

過濾器order值越小章蚣,越優(yōu)先執(zhí)行

[圖片上傳失敗...(image-be497b-1551267407598)]

8.7 自定義zuul過濾器

在filter包下添加LoginFilter
@Component
public class LoginFilter extends ZuulFilter {

    /**
     * 過濾器類型,前置過濾器
     * @return
     */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    /**
     * 過濾器執(zhí)行順序姨夹,越小越先執(zhí)行
     * @return
     */
    @Override
    public int filterOrder() {
        return 4;
    }

    /**
     * 過濾器是否生效
     * @return
     */
    @Override
    public boolean shouldFilter() {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();

        // 或者ACL方式
        if ("/beebee-api/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())) {
            return true;
        }
        return false;
    }

    /**
     * 業(yè)務(wù)邏輯
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String token = request.getHeader("token");
        token = StringUtils.isEmpty(token) ? request.getParameter("token") : token;

        // 登錄校驗(yàn)纤垂,實(shí)際使用改為JWT
        if (StringUtils.isBlank(token)) {
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}

8.8 訂單服務(wù)限流

在filter包下創(chuàng)建OrderRateLimitFilter類
@Component
public class OrderRateLimitFilter extends ZuulFilter {

    // Guava:每秒產(chǎn)生1000個(gè)令牌,即每秒最多1000個(gè)請求
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return -4;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();

        // 只對訂單接口限流
        if ("/beebee-api/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())) {
            return true;
        }
        return false;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext context = RequestContext.getCurrentContext();
        if (!RATE_LIMITER.tryAcquire()) {
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
        }
        return null;
    }
}

==9. Sleuth==

9.1 對應(yīng)的項(xiàng)目中磷账,添加pom依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

9.2 XxxServiceImpl中使用

private final Logger logger = LoggerFactory.getLogger(getClass());
logger.info("order -- service");

2019-01-16 17:45:51.507  INFO [order-service,4fdff23615ab2226,d8818e5c8e6e5ba5,false] 8446 --- [derController-2] c.z.o.service.impl.OrderServiceImpl : order -- service

第一個(gè)值:order-service峭沦,spring.application.name的值
第二個(gè)值:4fdff23615ab2226,叫TraceID逃糟,用來標(biāo)識一條請求鏈路吼鱼,一條請求鏈路中包含一個(gè)TraceID,多個(gè)SpanID
第三個(gè)值:d8818e5c8e6e5ba5绰咽,叫SpanID菇肃,基本的工作單元,獲取元數(shù)據(jù)取募,如發(fā)送一個(gè)http
第四個(gè)值:false琐谤,是否要將該信息輸出到zipkin服務(wù)中來收集和展示。

==10. Zipkin==

10.1 web使用 Zipkin

docker run -d -p 9411:9411 openzipkin/zipkin 
訪問:http://localhost:9411/zipkin/    

10.2 對應(yīng)的服務(wù)中玩敏,添加pom依賴

這個(gè)依賴包含了 spring-cloud-starter-sleuth斗忌、spring-cloud-sleuth-zipkin
相應(yīng)的服務(wù)都要添加以下依賴
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

10.3 修改application.yml

spring:
  application:
    name: order-service
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      probability: 1 # 采樣百分比:開發(fā)環(huán)境=1即100%,生成環(huán)境用默認(rèn)的=0.1即10%

==11. Config==

11.1 新建config-server項(xiàng)目旺聚,添加pom依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

11.2 啟動(dòng)類添加注解

@EnableConfigServer

11.3 修改application.yml

spring:
  application:
    name: config-server
server:
  port: 9100
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/ 

11.4 碼云建立config-cloud項(xiàng)目

https://gitee.com/zhangyimai/config-cloud.git

11.5 修改application.yml

spring:
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/zhangyimai/config-cloud 
          username:
          password: 
          timeout: 5

11.6 在碼云config-cloud項(xiàng)目上飞蹂,新建product-service.yml文件

11.7 訪問方式

http://localhost:9100/product-service.yml
/{name}-{profiles}.properties
/{name}-{profiles}.yml
/{name}-{profiles}.json
/{label}/{name}-{profiles}.yml
name:服務(wù)器名稱
profile:環(huán)境名稱,開發(fā)翻屈、測試陈哑、生產(chǎn)
lable:倉庫分支、默認(rèn)master分支

11.8 config-client使用,product-service添加pom依賴

<!--配置中心客戶端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-client</artifactId>
</dependency>

11.9 修改application.yml為bootstrap.yml

# 服務(wù)名稱
spring:
  application:
    name: product-service
  # 指定從哪個(gè)配置中心讀取
  cloud:
    config:
      discovery:
        service-id: CONFIG-SERVER # 服務(wù)ID
        enabled: true
      label: dev # dev分支惊窖,建議用label區(qū)分配置文件的環(huán)境
      profile: dev # 配置文件后綴刽宪,不建議用profile區(qū)分配置文件的環(huán)境
# 注冊中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
      
此配置文件讀取的路徑:http://localhost:9100/dev/product-service-dev.yml

==12. Bus==

12.1 Docker安裝啟動(dòng)RabbitMQ

docker pull rabbitmq:management
docker run -d --name="myrabbitmq" -p 5671:5671 -p 15672:15672 rabbitmq:management
訪問:http://localhost:15672
用戶名密碼:guest

12.2 config-client添加pom依賴

<!--配置中心結(jié)合消息隊(duì)列-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

12.3 添加RabbitMQ等配置

在碼云config-cloud項(xiàng)目中,對應(yīng)的配置文件添加如下配置

# RabbitMQ連接信息
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
#暴露全部的監(jiān)控信息
management:
  endpoints:
    web:
      exposure:
        include: "*"

12.4 需要刷新配置的類上添加注解

如需動(dòng)態(tài)刷新界酒,需要配置以下注解
@RefreshScope

12.5 動(dòng)態(tài)刷新配置

post方式請求:http://localhost:8773/actuator/bus-refresh
8773是當(dāng)前項(xiàng)目的端口圣拄,如果是多個(gè)節(jié)點(diǎn),其他節(jié)點(diǎn)也會(huì)刷新
注意:動(dòng)態(tài)刷新配置毁欣,在開發(fā)和測試環(huán)境使用庇谆,盡量少在生產(chǎn)環(huán)境使用

==13. 微服務(wù)改造為配置中心總結(jié)==

13.1 碼云上創(chuàng)建cloud-config項(xiàng)目,并添加對應(yīng)配置文件

微服務(wù)添加以下配置

# RabbitMQ連接信息
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
#暴露全部的監(jiān)控信息
management:
  endpoints:
    web:
      exposure:
        include: "*"

13.2 微服務(wù)添加pom依賴

<!--配置中心客戶端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-client</artifactId>
</dependency>
<!--配置中心結(jié)合消息隊(duì)列-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

13.3 application.yml --> bootstrap.yml

# 服務(wù)名稱
spring:
  application:
    name: product-service
  # 指定從哪個(gè)配置中心讀取
  cloud:
    config:
      discovery:
        service-id: CONFIG-SERVER # 服務(wù)ID
        enabled: true
      label: dev # dev分支
      profile: dev # 配置文件后綴
# 注冊中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

13.4 各個(gè)項(xiàng)目啟動(dòng)順序

1. 注冊中心
2. 配置中心
3. 各個(gè)服務(wù):商品服務(wù)凭疮、訂單服務(wù)...
4. 啟動(dòng)網(wǎng)關(guān)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饭耳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子执解,更是在濱河造成了極大的恐慌寞肖,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衰腌,死亡現(xiàn)場離奇詭異新蟆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)右蕊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門琼稻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人饶囚,你說我怎么就攤上這事帕翻。” “怎么了坯约?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長莫鸭。 經(jīng)常有香客問我闹丐,道長,這世上最難降的妖魔是什么被因? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任卿拴,我火速辦了婚禮,結(jié)果婚禮上梨与,老公的妹妹穿的比我還像新娘堕花。我一直安慰自己,他們只是感情好粥鞋,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布缘挽。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪壕曼。 梳的紋絲不亂的頭發(fā)上苏研,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天,我揣著相機(jī)與錄音腮郊,去河邊找鬼摹蘑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛轧飞,可吹牛的內(nèi)容都是我干的衅鹿。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼过咬,長吁一口氣:“原來是場噩夢啊……” “哼大渤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起援奢,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤兼犯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后集漾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體切黔,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年具篇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纬霞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驱显,死狀恐怖诗芜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情埃疫,我是刑警寧澤伏恐,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站栓霜,受9級特大地震影響翠桦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胳蛮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一销凑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧仅炊,春花似錦斗幼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谋逻。三九已至,卻和暖如春渠羞,著一層夾襖步出監(jiān)牢的瞬間斤贰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工次询, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荧恍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓屯吊,卻偏偏與公主長得像送巡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子盒卸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容