springcloud筆記

單體應用存在的問題

  • 隨著業(yè)務的發(fā)展樟遣,開發(fā)變得越來越復雜。
  • 修改身笤、新增某個功能豹悬,需要對整個系統(tǒng)進行測試、重新部署液荸。
  • 一個模塊出現(xiàn)問題瞻佛,很可能導致整個系統(tǒng)崩潰。
  • 多個開發(fā)團隊同時對數(shù)據(jù)進行管理娇钱,容易產(chǎn)生安全漏洞伤柄。
  • 各個模塊使用同一種技術進行開發(fā),各個模塊很難根據(jù)實際情況選擇更合適的技術框架文搂,局限性很大响迂。
  • 模塊內容過于復雜,如果員工離職细疚,可能需要很長時間才能完成工作交接蔗彤。

分布式、集群

集群:一臺服務器無法負荷高并發(fā)的數(shù)據(jù)訪問量疯兼,那么就設置十臺服務器一起分擔壓力然遏,十臺不行就設置一百臺(物理層面)。很多人干同一件事情吧彪,來分攤壓力待侵。

分布式:將一個復雜問題拆分成若干個簡單的小問題,將一個大型的項目架構拆分成若干個微服務來協(xié)同完成姨裸。(軟件設計層面)秧倾。將一個龐大的工作拆分成若干個小步驟怨酝,分別由不同的人完成這些小步驟,最終將所有的結果進行整合實現(xiàn)大的需求那先。

服務治理的核心又三部分組成:服務提供者农猬、服務消費者、注冊中心售淡。

在分布式系統(tǒng)架構中斤葱,每個微服務在啟動時,將自己的信息存儲在注冊中心揖闸,叫做服務注冊揍堕。

服務消費者從注冊中心獲取服務提供者的網(wǎng)絡信息,通過該信息調用服務汤纸,叫做服務發(fā)現(xiàn)俘枫。

Spring Cloud 的服務治理使用 Eureka 來實現(xiàn)拳话,Eureka 是 Netflix 開源的基于 REST 的服務治理解決方案,Spring Cloud 集成了 Eureka,提供服務注冊和服務發(fā)現(xiàn)的功能妖谴,可以和基于 Spring Boot 搭建的微服務應用輕松完成整合狂魔,開箱即用起意,Spring Cloud Eureka诺凡。

Spring Cloud Eureka

  • Eureka Server,注冊中心
  • Eureka Client议惰,所有要進行注冊的微服務通過 Eureka Client 連接到 Eureka Server慎颗,完成注冊。

Eureka Server代碼實現(xiàn)

  • 創(chuàng)建父工程言询,pom.xml
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.7.RELEASE</version>
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <!-- 解決 JDK 9 以上沒有 JAXB API 的問題 -->
  <dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
  </dependency>

  <dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.3.0</version>
  </dependency>

  <dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.3.0</version>
  </dependency>

  <dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
  </dependency>
</dependencies>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>Finchley.SR2</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
  • 在父工程下創(chuàng)建 Module俯萎,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml,添加 Eureka Server 相關配置运杭。
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/

屬性說明

server.port:當前 Eureka Server 服務端口夫啊。

eureka.client.register-with-eureka:是否將當前的 Eureka Server 服務作為客戶端進行注冊。

eureka.client.fetch-fegistry:是否獲取其他 Eureka Server 服務的數(shù)據(jù)辆憔。

eureka.client.service-url.defaultZone:注冊中心的訪問地址撇眯。

  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class,args);
    }
}

注解說明:

@SpringBootApplication:聲明該類是 Spring Boot 服務的入口。

@EnableEurekaServer:聲明該類是一個 Eureka Server 微服務虱咧,提供服務注冊和服務發(fā)現(xiàn)功能熊榛,即注冊中心。

Eureka Client 代碼實現(xiàn)

  • 創(chuàng)建 Module 腕巡,pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml玄坦,添加 Eureka Client 相關配置
server:
  port: 8010
spring:
  application:
    name: provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

屬性說明:

spring.application.name:當前服務注冊在 Eureka Server 上的名稱。

eureka.client.service-url.defaultZone:注冊中心的訪問地址。

eureka.instance.prefer-ip-address:是否將當前服務的 IP 注冊到 Eureka Server煎楣。

  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}
  • 實體類
package com.southwind.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private long id;
    private String name;
    private int age;
}
  • Repository
package com.southwind.repository;

import com.southwind.entity.Student;

import java.util.Collection;

public interface StudentRepository {
    public Collection<Student> findAll();
    public Student findById(long id);
    public void saveOrUpdate(Student student);
    public void deleteById(long id);
}
  • RepositoryImpl
package com.southwind.repository.impl;

import com.southwind.entity.Student;
import com.southwind.repository.StudentRepository;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@Repository
public class StudentRepositoryImpl implements StudentRepository {

    private static Map<Long,Student> studentMap;

    static {
        studentMap = new HashMap<>();
        studentMap.put(1L,new Student(1L,"張三",22));
        studentMap.put(2L,new Student(2L,"李四",23));
        studentMap.put(3L,new Student(3L,"王五",24));
    }

    @Override
    public Collection<Student> findAll() {
        return studentMap.values();
    }

    @Override
    public Student findById(long id) {
        return studentMap.get(id);
    }

    @Override
    public void saveOrUpdate(Student student) {
        studentMap.put(student.getId(),student);
    }

    @Override
    public void deleteById(long id) {
        studentMap.remove(id);
    }
}
  • Handler
package com.southwind.controller;

import com.southwind.entity.Student;
import com.southwind.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@RestController
@RequestMapping("/student")
public class StudentHandler {
    @Autowired
    private StudentRepository studentRepository;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return studentRepository.findAll();
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return studentRepository.findById(id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        studentRepository.deleteById(id);
    }
}

RestTemplate 的使用

  • 什么是 RestTemplate豺总?

RestTemplate 是 Spring 框架提供的基于 REST 的服務組件,底層是對 HTTP 請求及響應進行了封裝择懂,提供了很多訪問 RETS 服務的方法喻喳,可以簡化代碼開發(fā)。

  • 如何使用 RestTemplate休蟹?

1沸枯、創(chuàng)建 Maven 工程日矫,pom.xml赂弓。

2、創(chuàng)建實體類

package com.southwind.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private long id;
    private String name;
    private int age;
}

3哪轿、Handler

package com.southwind.controller;

import com.southwind.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;

@RestController
@RequestMapping("/rest")
public class RestHandler {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return restTemplate.getForEntity("http://localhost:8010/student/findAll",Collection.class).getBody();
    }

    @GetMapping("/findAll2")
    public Collection<Student> findAll2(){
        return restTemplate.getForObject("http://localhost:8010/student/findAll",Collection.class);
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return restTemplate.getForEntity("http://localhost:8010/student/findById/{id}",Student.class,id).getBody();
    }

    @GetMapping("/findById2/{id}")
    public Student findById2(@PathVariable("id") long id){
        return restTemplate.getForObject("http://localhost:8010/student/findById/{id}",Student.class,id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        restTemplate.postForEntity("http://localhost:8010/student/save",student,null).getBody();
    }

    @PostMapping("/save2")
    public void save2(@RequestBody Student student){
        restTemplate.postForObject("http://localhost:8010/student/save",student,null);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        restTemplate.put("http://localhost:8010/student/update",student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        restTemplate.delete("http://localhost:8010/student/deleteById/{id}",id);
    }
}

4盈魁、啟動類

package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class RestTemplateApplication {
    public static void main(String[] args) {
        SpringApplication.run(RestTemplateApplication.class,args);
    }

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

服務消費者 consumer

  • 創(chuàng)建 Maven 工程,pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8020
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
  • Handler
package com.southwind.controller;

import com.southwind.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;

@RestController
@RequestMapping("/consumer")
public class ConsumerHandler {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return restTemplate.getForEntity("http://localhost:8010/student/findAll",Collection.class).getBody();
    }

    @GetMapping("/findAll2")
    public Collection<Student> findAll2(){
        return restTemplate.getForObject("http://localhost:8010/student/findAll",Collection.class);
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return restTemplate.getForEntity("http://localhost:8010/student/findById/{id}",Student.class,id).getBody();
    }

    @GetMapping("/findById2/{id}")
    public Student findById2(@PathVariable("id") long id){
        return restTemplate.getForObject("http://localhost:8010/student/findById/{id}",Student.class,id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        restTemplate.postForEntity("http://localhost:8010/student/save",student,null).getBody();
    }

    @PostMapping("/save2")
    public void save2(@RequestBody Student student){
        restTemplate.postForObject("http://localhost:8010/student/save",student,null);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        restTemplate.put("http://localhost:8010/student/update",student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        restTemplate.delete("http://localhost:8010/student/deleteById/{id}",id);
    }
}

服務網(wǎng)關

Spring Cloud 集成了 Zuul 組件窃诉,實現(xiàn)服務網(wǎng)關杨耙。

  • 什么是 Zuul?

Zuul 是 Netflix 提供的一個開源的 API 網(wǎng)關服務器飘痛,是客戶端和網(wǎng)站后端所有請求的中間層珊膜,對外開放一個 API,將所有請求導入統(tǒng)一的入口宣脉,屏蔽了服務端的具體實現(xiàn)邏輯车柠,Zuul 可以實現(xiàn)反向代理的功能,在網(wǎng)關內部實現(xiàn)動態(tài)路由塑猖、身份認證竹祷、IP 過濾、數(shù)據(jù)監(jiān)控等羊苟。

  • 創(chuàng)建 Maven 工程塑陵,pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8030
spring:
  application:
    name: gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
zuul:
  routes:
    provider: /p/**

屬性說明:

zuul.routes.provider:給服務提供者 provider 設置映射

  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@EnableZuulProxy
@EnableAutoConfiguration
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class,args);
    }
}

注解說明:

@EnableZuulProxy:包含了 @EnableZuulServer,設置該類是網(wǎng)關的啟動類蜡励。

@EnableAutoConfiguration:可以幫助 Spring Boot 應用將所有符合條件的 @Configuration 配置加載到當前 Spring Boot 創(chuàng)建并使用的 IoC 容器中令花。

  • Zuul 自帶了負載均衡功能,修改 provider 的代碼凉倚。
package com.southwind.controller;

import com.southwind.entity.Student;
import com.southwind.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@RestController
@RequestMapping("/student")
public class StudentHandler {
    @Autowired
    private StudentRepository studentRepository;

    @Value("${server.port}")
    private String port;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return studentRepository.findAll();
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return studentRepository.findById(id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        studentRepository.deleteById(id);
    }

    @GetMapping("/index")
    public String index(){
        return "當前端口:"+this.port;
    }
}

Ribbon 負載均衡

  • 什么是 Ribbon彭则?

Spring Cloud Ribbon 是一個負載均衡解決方案,Ribbon 是 Netflix 發(fā)布的負載均衡器占遥,Spring Cloud Ribbon 是基于 Netflix Ribbon 實現(xiàn)的俯抖,是一個用于對 HTTP 請求進行控制的負載均衡客戶端。

在注冊中心對 Ribbon 進行注冊之后瓦胎,Ribbon 就可以基于某種負載均衡算法芬萍,如輪詢尤揣、隨機、加權輪詢柬祠、加權隨機等自動幫助服務消費者調用接口北戏,開發(fā)者也可以根據(jù)具體需求自定義 Ribbon 負載均衡算法。實際開發(fā)中漫蛔,Spring Cloud Ribbon 需要結合 Spring Cloud Eureka 來使用嗜愈,Eureka Server 提供所有可以調用的服務提供者列表,Ribbon 基于特定的負載均衡算法從這些服務提供者中選擇要調用的具體實例莽龟。

  • 創(chuàng)建 Module蠕嫁,pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8040
spring:
  application:
    name: ribbon
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class RibbonApplication {
    public static void main(String[] args) {
        SpringApplication.run(RibbonApplication.class,args);
    }

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

@LoadBalanced:聲明一個基于 Ribbon 的負載均衡。

  • Handler
package com.southwind.controller;

import com.southwind.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;

@RestController
@RequestMapping("/ribbon")
public class RibbonHandler {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return restTemplate.getForObject("http://provider/student/findAll",Collection.class);
    }

    @GetMapping("/index")
    public String index(){
        return restTemplate.getForObject("http://provider/student/index",String.class);
    }
}

Feign

  • 什么是 Feign毯盈?

與 Ribbon 一樣剃毒,F(xiàn)eign 也是由 Netflix 提供的,F(xiàn)eign 是一個聲明式搂赋、模版化的 Web Service 客戶端赘阀,它簡化了開發(fā)者編寫 Web 服務客戶端的操作,開發(fā)者可以通過簡單的接口和注解來調用 HTTP API脑奠,Spring Cloud Feign基公,它整合了 Ribbon 和 Hystrix,具有可插拔宋欺、基于注解轰豆、負載均衡、服務熔斷等一系列便捷功能迄靠。

相比較于 Ribbon + RestTemplate 的方式秒咨,F(xiàn)eign 大大簡化了代碼的開發(fā),F(xiàn)eign 支持多種注解掌挚,包括 Feign 注解雨席、JAX-RS 注解、Spring MVC 注解等吠式,Spring Cloud 對 Feing 進行了優(yōu)化陡厘,整合了 Ribbon 和 Eureka,從而讓 Feign 的使用更加方便特占。

  • Ribbon 和 Feign 的區(qū)別

Ribbon 是一個通用的 HTTP 客戶端工具糙置,F(xiàn)eign 是基于 Ribbon 實現(xiàn)的。

  • Feign 的tedian

1是目、Feign 是一個聲明式的 Web Service 客戶端谤饭。

2、支持 Feign 注解、Spring MVC 注解揉抵、JAX-RS 注解亡容。

3、Feign 基于 Ribbon 實現(xiàn)冤今,使用起來更加簡單闺兢。

4、Feign 集成了 Hystrix戏罢,具備服務熔斷的功能屋谭。

  • 創(chuàng)建 Module,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8050
spring:
  application:
    name: feign
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class FeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignApplication.class,args);
    }
}
  • 創(chuàng)建聲明式接口
package com.southwind.feign;

import com.southwind.entity.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Collection;

@FeignClient(value = "provider")
public interface FeignProviderClient {
    @GetMapping("/student/findAll")
    public Collection<Student> findAll();

    @GetMapping("/student/index")
    public String index();
}
  • Handler
package com.southwind.controller;

import com.southwind.entity.Student;
import com.southwind.feign.FeignProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;

@RestController
@RequestMapping("/feign")
public class FeignHandler {

    @Autowired
    private FeignProviderClient feignProviderClient;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return feignProviderClient.findAll();
    }

    @GetMapping("/index")
    public String index(){
        return feignProviderClient.index();
    }
}
  • 服務熔斷龟糕,application.yml 添加熔斷機制桐磁。
server:
  port: 8050
spring:
  application:
    name: feign
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true

feign.hystrix.enabled:是否開啟熔斷器。

  • 創(chuàng)建 FeignProviderClient 接口的實現(xiàn)類 FeignError翩蘸,定義容錯處理邏輯所意,通過 @Component 注解將 FeignError 實例注入 IoC 容器中淮逊。
package com.southwind.feign.impl;

import com.southwind.entity.Student;
import com.southwind.feign.FeignProviderClient;
import org.springframework.stereotype.Component;

import java.util.Collection;

@Component
public class FeignError implements FeignProviderClient {
    @Override
    public Collection<Student> findAll() {
        return null;
    }

    @Override
    public String index() {
        return "服務器維護中......";
    }
}
  • 在 FeignProviderClient 定義處通過 @FeignClient 的 fallback 屬性設置映射催首。
package com.southwind.feign;

import com.southwind.entity.Student;
import com.southwind.feign.impl.FeignError;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Collection;

@FeignClient(value = "provider",fallback = FeignError.class)
public interface FeignProviderClient {
    @GetMapping("/student/findAll")
    public Collection<Student> findAll();

    @GetMapping("/student/index")
    public String index();
}

Hystrix 容錯機制

在不改變各個微服務調用關系的前提下,針對錯誤情況進行預先處理泄鹏。

  • 設計原則

1郎任、服務隔離機制

2、服務降級機制

3备籽、熔斷機制

4舶治、提供實時的監(jiān)控和報警功能

5、提供實時的配置修改功能

Hystrix 數(shù)據(jù)監(jiān)控需要結合 Spring Boot Actuator 來使用车猬,Actuator 提供了對服務的健康健康霉猛、數(shù)據(jù)統(tǒng)計,可以通過 hystrix.stream 節(jié)點獲取監(jiān)控的請求數(shù)據(jù)珠闰,提供了可視化的監(jiān)控界面惜浅。

  • 創(chuàng)建 Maven,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>

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

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.0.7.RELEASE</version>
  </dependency>

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

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8060
spring:
  application:
    name: hystrix
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true
management:
  endpoints:
    web:
      exposure:
        include: 'hystrix.stream'
  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrixDashboard
public class HystrixApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixApplication.class,args);
    }
}

注解說明:

@EnableCircuitBreaker:聲明啟用數(shù)據(jù)監(jiān)控

@EnableHystrixDashboard:聲明啟用可視化數(shù)據(jù)監(jiān)控

  • Handler
package com.southwind.controller;

import com.southwind.entity.Student;
import com.southwind.feign.FeignProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;

@RestController
@RequestMapping("/hystrix")
public class HystrixHandler {
    @Autowired
    private FeignProviderClient feignProviderClient;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return feignProviderClient.findAll();
    }

    @GetMapping("/index")
    public String index(){
        return feignProviderClient.index();
    }
}
  • 啟動成功之后伏嗜,訪問 http://localhost:8060/actuator/hystrix.stream 可以監(jiān)控到請求數(shù)據(jù)坛悉,
  • 訪問 http://localhost:8060/hystrix,可以看到可視化的監(jiān)控界面承绸,輸入要監(jiān)控的地址節(jié)點即可看到該節(jié)點的可視化數(shù)據(jù)監(jiān)控裸影。

Spring Cloud 配置中心

Spring Cloud Config,通過服務端可以為多個客戶端提供配置服務军熏。Spring Cloud Config 可以將配置文件存儲在本地轩猩,也可以將配置文件存儲在遠程 Git 倉庫,創(chuàng)建 Config Server,通過它管理所有的配置文件均践。

本地文件系統(tǒng)

  • 創(chuàng)建 Maven 工程画饥,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建 application.yml
server:
  port: 8762
spring:
  application:
    name: nativeconfigserver
  profiles:
    active: native
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/shared

注解說明

profiles.active:配置文件的獲取方式

cloud.config.server.native.search-locations:本地配置文件存放的路徑

  • resources 路徑下創(chuàng)建 shared 文件夾,并在此路徑下創(chuàng)建 configclient-dev.yml浊猾。
server:
  port: 8070
foo: foo version 1
  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class NativeConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(NativeConfigServerApplication.class,args);
    }
}

注解說明

@EnableConfigServer:聲明配置中心抖甘。

創(chuàng)建客戶端讀取本地配置中心的配置文件

  • 創(chuàng)建 Maven 工程,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建 bootstrap.yml葫慎,配置讀取本地配置中心的相關信息衔彻。
spring:
  application:
    name: configclient
  profiles:
    active: dev
  cloud:
    config:
      uri: http://localhost:8762
      fail-fast: true

注解說明

cloud.config.uri:本地 Config Server 的訪問路徑

cloud.config.fail-fase:設置客戶端優(yōu)先判斷 Config Server 獲取是否正常。

通過spring.application.name 結合spring.profiles.active拼接目標配置文件名偷办,configclient-dev.yml艰额,去 Config Server 中查找該文件。

  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class NativeConfigClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(NativeConfigClientApplication.class,args);
    }
}
  • Handler
package com.southwind.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/native")
public class NativeConfigHandler {

    @Value("${server.port}")
    private String port;

    @Value("${foo}")
    private String foo;

    @GetMapping("/index")
    public String index(){
        return this.port+"-"+this.foo;
    }
}

Spring Cloud Config 遠程配置

  • 創(chuàng)建配置文件椒涯,上傳至 GitHub
server:
  port: 8070
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: configclient
  • 創(chuàng)建 Config Server柄沮,新建 Maven 工程,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8888
spring:
  application:
    name: configserver
  cloud:
    config:
      server:
        git:
          uri: https://github.com/southwind9801/aispringcloud.git
          searchPaths: config
          username: root
          password: root
      label: master
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class,args);
    }
}

創(chuàng)建 Config Client

  • 創(chuàng)建 Maven 工程废岂,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建 bootstrap.yml
spring:
  cloud:
    config:
      name: configclient
      label: master
      discovery:
        enabled: true
        service-id: configserver
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

注解說明

spring.cloud.config.name:當前服務注冊在 Eureka Server 上的名稱祖搓,與遠程倉庫的配置文件名對應。

spring.cloud.config.label:Git Repository 的分支湖苞。

spring.cloud.config.discovery.enabled:是否開啟 Config 服務發(fā)現(xiàn)支持拯欧。

spring.cloud.config.discovery.service-id:配置中心在 Eureka Server 上注冊的名稱。

  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ConfigClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class,args);
    }
}
  • Handler
package com.southwind.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hello")
public class HelloHandler {

    @Value("${server.port}")
    private String port;

    @GetMapping("/index")
    public String index(){
        return this.port;
    }
}

服務跟蹤

Spring Cloud Zipkin

Zipkin 是一個可以采集并且跟蹤分布式系統(tǒng)中請求數(shù)據(jù)的組件财骨,讓開發(fā)者可以更加直觀的監(jiān)控到請求在各個微服務所耗費的時間等镐作,Zipkin:Zipkin Server、Zipkin Client隆箩。

創(chuàng)建 Zipkin Server

  • 創(chuàng)建 Maven 工程该贾,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-server</artifactId>
    <version>2.9.4</version>
  </dependency>
  <dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-autoconfigure-ui</artifactId>
    <version>2.9.4</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 9090
  • 創(chuàng)建啟動類
package com.southwind;

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);
    }
}

注解說明

@EnableZipkinServer:聲明啟動 Zipkin Server

創(chuàng)建 Zipkin Client

  • 創(chuàng)建 Maven 工程,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8090
spring:
  application:
    name: zipkinclient
  sleuth:
    web:
      client:
        enabled: true
    sampler:
      probability: 1.0
  zipkin:
    base-url: http://localhost:9090/
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

屬性說明

spring.sleuth.web.client.enabled:設置開啟請求跟蹤

spring.sleuth.sampler.probability:設置采樣比例捌臊,默認是 1.0

srping.zipkin.base-url:Zipkin Server 地址

  • 創(chuàng)建啟動類
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ZipkinClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZipkinClientApplication.class,args);
    }
}
  • Handler
package com.southwind.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/zipkin")
public class ZipkinHandler {

    @Value("${server.port}")
    private String port;

    @GetMapping("/index")
    public String index(){
        return this.port;
    }
}

更多詳情

設置為vip可見的都可訪問下面鏈接地址杨蛋,即可觀看原文
更多詳情請訪問: juntech

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市娃属,隨后出現(xiàn)的幾起案子六荒,更是在濱河造成了極大的恐慌,老刑警劉巖矾端,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掏击,死亡現(xiàn)場離奇詭異,居然都是意外死亡秩铆,警方通過查閱死者的電腦和手機砚亭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門灯变,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捅膘,你說我怎么就攤上這事添祸。” “怎么了寻仗?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵刃泌,是天一觀的道長。 經(jīng)常有香客問我署尤,道長耙替,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任曹体,我火速辦了婚禮俗扇,結果婚禮上,老公的妹妹穿的比我還像新娘箕别。我一直安慰自己铜幽,他們只是感情好,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布串稀。 她就那樣靜靜地躺著除抛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪厨诸。 梳的紋絲不亂的頭發(fā)上镶殷,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天禾酱,我揣著相機與錄音微酬,去河邊找鬼。 笑死颤陶,一個胖子當著我的面吹牛颗管,可吹牛的內容都是我干的。 我是一名探鬼主播滓走,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼垦江,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了搅方?” 一聲冷哼從身側響起比吭,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎姨涡,沒想到半個月后衩藤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡涛漂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年赏表,在試婚紗的時候發(fā)現(xiàn)自己被綠了检诗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡瓢剿,死狀恐怖逢慌,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情间狂,我是刑警寧澤攻泼,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站鉴象,受9級特大地震影響坠韩,放射性物質發(fā)生泄漏。R本人自食惡果不足惜炼列,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一只搁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧俭尖,春花似錦氢惋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至已亥,卻和暖如春熊赖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背虑椎。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工震鹉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捆姜。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓传趾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親泥技。 傳聞我的和親對象是個殘疾皇子浆兰,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內容

  • 基于上一篇SpringCloud筆記實現(xiàn)了Eureka服務的注冊和發(fā)現(xiàn)。在微服務架構中珊豹,業(yè)務都會被拆分成一個獨立的...
    二枚目閱讀 271評論 0 0
  • Spring Cloud是一個基于Spring Boot實現(xiàn)的云應用開發(fā)工具簸呈,它為基于JVM的云應用開發(fā)中涉及的配...
    二枚目閱讀 662評論 0 1
  • 微服務架構模式的核心在于如何識別服務的邊界,設計出合理的微服務店茶。但如果要將微服務架構運用到生產(chǎn)項目上蜕便,并且能夠發(fā)揮...
    java菜閱讀 2,952評論 0 6
  • 斷路器Hystrix 在微服務架構中,系統(tǒng)被拆分成了一個個小的服務單元忽妒,各自運行在自己的線程中玩裙,各單元之間通過注冊...
    二枚目閱讀 3,051評論 0 0
  • 一兼贸、簡介 Spring Cloud 為開發(fā)者提供了在分布式系統(tǒng)(配置管理,服務發(fā)現(xiàn)吃溅,熔斷溶诞,路由,微代理决侈,控制總線螺垢,...
    生活的探路者閱讀 1,055評論 0 6