SpringCloud搭建保姆級教程

佛祖讓我來巡山發表於2023-09-20

一、搭建服務註冊與發現中⼼

使⽤Spring Cloud Netflix 中的 Eureka 搭建服務註冊與發現中⼼

1、建立SpringBoot應用新增依賴

1、spring web
2、eureka server

2、配置服務註冊與發現中⼼

## 設定服務註冊與發現中⼼的端⼝
server:
  port: 8761
## 在微服務架構中,服務註冊中⼼是透過服務應⽤的名稱來區分每個服務的
## 我們在建立每個服務之後,指定當前服務的 應⽤名/項⽬名
spring:
  application: null
  name: service-eureka
eureka:
  client:
    ## ip 就是服務註冊中⼼伺服器的ip,port 就是服務註冊與發現中⼼設定的port
    service-url:
      defaultZone: 'http://192.168.54.59:8761/eureka'
    ## 設定服務註冊與發現中⼼是否為為叢集搭建(如果為叢集模式,多個eureka節點之間需要相互註冊)
    register-with-eureka: false
     ## 設定服務註冊與發現中是否作為服務進⾏註冊
    fetch-registry: false

3、在啟動類新增@EnableEurekaServer註解

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

4、運⾏及訪問

二、服務註冊

建立儲存訂單的服務(order-add)註冊到服務註冊與發現中⼼

1、建立SpringBoot應⽤

建立spring boot應⽤,完成功能開發

2、註冊服務

將能夠完成特定業務的SpringBoot應⽤作為服務提供者,註冊到服務註冊與發現中⼼

2.1、新增依賴eureka-server

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

2.2、配置application.yml

server:
  port: 9001
## 當前應⽤名會作為服務唯⼀標識註冊到eureka
spring:
  application:
    name: order-add
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: 'jdbc:mysql://localhost:3306/db_2010_sc?characterEncoding=utf-8'
    username: root
    password: admin123
mybatis:
  mapper-locations: 'classpath:mappers/*'
  type-aliases-package: com.qfedu.order.beans
## 配置Eureka服務註冊與發現中⼼的地址
eureka:
  client: 
      service-url:
        defaultZone: 'http://localhost:8761/eureka'

2.3、在當前服務應⽤的啟動類新增 @EnableEurekaClient 註解

@SpringBootApplication
@MapperScan("com.qfedu.order.dao")
@EnableEurekaClient
public class OrderAddApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderAddApplication.class, args);
    }
}

三、服務發現-Ribbon

服務消費者(api-order-add)透過eureka查詢服務提供者(order-add),透過服務調⽤元件調⽤提供者
  • eureka server
  • ribbon

1、基礎配置

Ribbon客戶端已經停更進維啦

1.1、建立SpringBoot應⽤,新增依賴 

  • eureka server
  • ribbon

1.2、配置application.yml

server:
  port: 8001
spring:
  application: 
    name: api-order-add
eureka:
  client: 
    service-url: 
        defaultZone: 'http://localhost:8761/eureka'

1.3、在啟動類新增 @EnableDiscoveryClient註解 

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

2、服務調⽤

2.1、配置RestTemplate

@Configuration
public class AppConfig {
    @LoadBalanced //啟⽤Ribbon(負載均衡)
    @Bean
     public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

2.2、在Service中注⼊RestTemplate物件調⽤服務

@Service
public class OrderAddServiceImpl implements OrderAddService {
    @Autowired
    private RestTemplate restTemplate;
    @Override
    public ResultVO saveOrder(Order order) {
        //1. 調⽤ order-add服務進⾏儲存
        ResultVO vo = restTemplate.postForObject("http://order-add/order/add", order, ResultVO.class);
        //2. 調⽤ orderitem-add 儲存訂單快照
        //3. 調⽤ stock-update 修改商品庫存
        //4. 調⽤ shopcart-del 刪除購物⻋記錄
        return null;
    }
}

3、Ribbon服務調⽤說明

@LoadBalanced註解是Ribbon的⼊⼝,在RestTemplate物件上新增此註解之後,再使
⽤RestTemplate傳送REST請求的時候,就可以透過Ribbon根據服務名稱從Eureka中查
找服務對應的訪問地址列表,再根據負載均衡策略(預設輪詢)選擇其中的⼀個,然後
完成服務的調⽤
  • 獲取服務列表
  • 根據負載均衡策略選擇服務
  • 完成服務調⽤

四、基於Ribbon進⾏服務調⽤的引數傳遞

1、RestTemplate傳送調⽤請求的⽅法

SpringCloud的服務調⽤是基於REST的,因此當服務提供者規定了請求的⽅式,服務消
費者必須傳送對應⽅式的請求才能完成服務的調⽤,RestTemplate提供了多個⽅法⽤於
傳送不同形式的請求。
//post⽅式請求
restTemplate.postForObject();
//get⽅式請求
restTemplate.getForObject();
//delete⽅式請求
restTemplate.delete();
//put⽅式請求
restTemplate.put();

2、put/post請求傳參

1、服務消費者請求傳參
//引數1:訪問服務的url
//引數2:傳遞的物件引數
//引數3:指定服務提供者返回的資料型別
ResultVO vo = restTemplate.postForObject("http://order-add/order/add",order, ResultVO.class);

2、服務提供者接收引數

@PostMapping("/add")
public ResultVO addOrder(@RequestBody Order order){
   return orderService.saveOrder(order);
}

3、get請求傳參

1、服務消費者請求傳參 

String userId = order.getUserId();
ResultVO vo = restTemplate.getForObject("http://order-add/order/add?userId="+userId, ResultVO.class);

2、服務提供者接收引數 

@GetMapping("/add")
public ResultVO addOrder(Order order){
    return orderService.saveOrder(order);
}
@GetMapping("/add")
public ResultVO addOrder(String userId){
    //return orderService.saveOrder(order);
}

五、服務發現-Feign

1、基礎配置

1.1、建立SpringBoot應⽤,新增依賴

spring web
eureka server
OpenFeign

1.2、配置application.yml

server:
  port: 8002
spring:
  application:
    name: api-order-add-feign
eureka:
  client:
    service-url:
      defaultZone: 'http://localhost:8761/eureka'

1.3、在啟動類新增註解

@SpringBootApplication
@EnableDiscoveryClient //宣告為服務消費者
@EnableFeignClients //宣告啟⽤feign客戶端
public class ApiOrderAddFeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiOrderAddFeignApplication.class, args);
    }
}

2、服務調⽤

使⽤Feign進⾏服務調⽤的時候,需要⼿動建立⼀個服務訪問客戶端(接⼝)

2.1、建立Feign客戶端

@FeignClient("order-add")
public interface OrderAddClient {
    @PostMapping("order/add")
     public ResultVO addOrder(Order order);
}

2.2、使⽤Feign客戶端調⽤服務

@Service
public class OrderAddServiceImpl implements OrderAddService {
    @Autowired
    private OrderAddClient orderAddClient;
    @Override
    public ResultVO saveOrder(Order order) {
        //1. 調⽤ order-add服務進⾏儲存
        ResultVO vo = orderAddClient.addOrder(order);
        //2. 調⽤ orderitem-add 儲存訂單快照
        //3. 調⽤ stock-update 修改商品庫存
        //4. 調⽤ shopcart-del 刪除購物⻋記錄
        return vo;
    }
}

3、Feign傳參

3.1、POST請求

1、透過請求體傳遞物件

服務提供者
@PostMapping("/add")
public ResultVO addOrder(@RequestBody Order order){
    System.out.println("-------------------order-add");
    System.out.println(order);
    return orderService.saveOrder(order);
}
服務消費者(Feign客戶端)
@FeignClient("order-add")
public interface OrderAddClient {
    @PostMapping("order/add")
     public ResultVO addOrder(Order order);
}

2、透過請求⾏傳參

服務提供者
@PostMapping("/add")
public ResultVO addOrder(@RequestBody Order order,String str){
    System.out.println("-------------------order-add");
    System.out.println(order);
    System.out.println(str);
    return orderService.saveOrder(order);
}
服務消費者(Feign客戶端)
//1.對⽤POST請求調⽤服務,Feign客戶端的⽅法引數預設為body傳值(body只能有⼀個值)
//2.如果有多個引數,則需要透過@RequestParam宣告引數為請求⾏傳值
@PostMapping("order/add")
public ResultVO addOrder(Order order,@RequestParam("str") String str);

3、Get請求

Get請求調⽤服務,只能透過url傳參在Feign客戶端的⽅法中,如果不指定引數的傳值⽅式,則預設為body傳參,Get請求也不例外;
因此對於get請求傳遞引數,必須透過@RequestParam註解宣告

 

服務提供者
@GetMapping("/get")
public Order addOrder(String orderId){
    return new Order();
}
服務消費者(Feign客戶端)
@GetMapping("order/get")
public Order getOrder(@RequestParam("orderId") String orderId);

六、服務註冊與發現中⼼的可靠性和安全性

1、可靠性

在微服務架構系統中,服務消費者是透過服務註冊與發現中⼼發現服務、調⽤服務的,
服務註冊與發現中⼼伺服器⼀旦掛掉,將會導致整個微服務架構系統的崩潰,如何保證
Eureka的可靠性呢?
  • 使⽤eureka叢集
Eureka叢集搭建
相互註冊、相互發現
## 設定服務註冊與發現中⼼的端⼝
server:
  port: 8761
## 在微服務架構中,服務註冊中⼼是透過服務應⽤的名稱來區分每個服務的
## 我們在建立每個服務之後,指定當前服務的 應⽤名/項⽬名
spring:
  application:
    name: service-eureka
eureka:
  client:
    ## 設定服務註冊與發現中⼼是否為叢集搭建
    register-with-eureka: true
    ## 設定服務註冊與發現中是否作為服務進⾏註冊
    fetch-registry: true
    ## ip 就是服務註冊中⼼伺服器的ip
    ## port 就是服務註冊與發現中⼼設定的port
    service-url:
      defaultZone: 'http://192.168.54.10:8761/eureka'
    

2、安全性

當完成Eureka的搭建之後,只要知道ip和port就可以隨意的註冊服務、調⽤服務,這是
不安全的,我們可以透過設定帳號和密碼來限制服務的註冊及發現。
  • 在eureka中整合Spring Security安全框架實現帳號和密碼驗證

2.1、新增SpringSecurity的依賴

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2.2、設定訪問eureka的帳號和密碼

spring:
  security:
    user:
      name: zhangsan
      password: 123456

2.3、配置Spring Security

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
     protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        // 設定當前伺服器的所有請求都要使⽤spring security的認證
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }
}

2.4、服務提供者和服務消費者連線到註冊中⼼都要帳號和密碼

eureka:
  client:
    service-url:
      defaultZone: 'http://zhangsan:123456@localhost:8761/eureka'

七、熔斷器-Hystrix

服務故障的雪崩效應:當A服務調⽤B服務時,由於B服務的故障導致A服務處於阻塞狀態,當量的請求可能會導致A服務因資源耗盡⽽出現故障。
為了解決服務故障的雪崩效應,出現了熔斷器模型。

1、熔斷器介紹

熔斷器作⽤:
1、服務降級 :⽤戶請求A服務,A服務調⽤B服務,當B服務出現故障或者在特定的時間段內
不能給A服務響應,為了避免A服務因等待B服務⽽產⽣阻塞,A服務就不等B服務的結果
了,直接給⽤戶⼀個降級響應
2、服務熔斷 :⽤戶請求A服務,A服務調⽤B服務,當B服務出現故障的頻率過⾼達到特定閾
值(5s 20次)時,當⽤戶再請求A服務時,A服務將不再調⽤B服務,直接給⽤戶⼀個降
級響應

2、熔斷器的原理

3、基於Ribbon服務調⽤的熔斷器使⽤

3.1、服務消費者的服務降級

1、新增熔斷器依賴 hystrix

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

2、在啟動類新增 @EnableHystrix 註解

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

3、在調⽤服務提供者的業務處理⽅法中,進⾏降級配置

@Service
public class OrderAddServiceImpl implements OrderAddService {
   @Autowired
   private RestTemplate restTemplate;
   @HystrixCommand(fallbackMethod ="fallbackSaveOrder",commandProperties = {
        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
      }
   )
   public ResultVO saveOrder(Order order) {
      //1. 調⽤ order-add服務進⾏儲存
      //引數1:訪問服務的url
      //引數2:傳遞的物件引數
      //引數3:指定服務提供者返回的資料型別
      ResultVO vo = restTemplate.postForObject("http://order-add/order/add",order, ResultVO.class);
      System.out.println(vo);
      return vo;
  }
  /**
   * 降級⽅法:與業務⽅法擁有相同的引數和返回值
   * @return
   */
  public ResultVO fallbackSaveOrder(Order order){
      return ResultVO.fail("⽹絡異常,請重試!",null);
  }
}

3.2、服務提供者的服務降級

1、配置步驟⼀致
2、服務提供者接⼝降級
@RestController
@RequestMapping("/order")
public class OrderController {
   @Autowired
   private OrderService orderService;
   @HystrixCommand(fallbackMethod ="fallbackAddOrder",commandProperties = {
      @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
      }
   )
   @PostMapping("/add")
   public ResultVO addOrder(@RequestBody Order order){
      System.out.println("-------------------order-add");
      System.out.println(order);
      try {
          Thread.sleep(5000);
      }
      catch (InterruptedException e) {
          e.printStackTrace();
      }
      return orderService.saveOrder(order);
  }
  public ResultVO fallbackAddOrder(@RequestBody Order order){
      System.out.println("-------------------order-add--fallback");
      return ResultVO.fail("訂單儲存失敗!",null);
  }
}

1、服務熔斷配置

熔斷器狀態:閉合、開啟、半開
服務熔斷配置
  @HystrixCommand(fallbackMethod ="fallbackSaveOrder",commandProperties = {
    @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000"),
     @HystrixProperty(name="circuitBreaker.enabled",value="true"),//啟⽤服務熔斷
    @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value="10000"),//時間
    @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value="10"),//請求次數
    @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value="50"),//服務錯誤率
    }
  )
  public ResultVO saveOrder(Order order) {
    //1. 調⽤ order-add服務進⾏儲存
    ResultVO vo = restTemplate.postForObject("http://orderadd/order/add", order, ResultVO.class);
    System.out.println(vo);
    return vo;
  }
  /**
  * 降級⽅法:與業務⽅法擁有相同的引數和返回值
  * @return
  */
  public ResultVO fallbackSaveOrder(Order order){
    return ResultVO.fail("⽹絡異常,請重試!",null);
  }
服務熔斷:當⽤戶請求服務A,服務A調⽤服務B時,如果服務B的故障率達到特定的
閾值時,熔斷器就會被開啟⼀個時間週期(預設5s,可⾃定義),在這個時間週期
內如果⽤戶請求服務A,服務A將不再調⽤服務B,⽽是直接響應降級服務。

4、基於Feign服務調⽤的熔斷器使⽤

Feign是基於Ribbon和Hystrix的封裝

4.1、Feign中的熔斷器使⽤

1、新增依賴(SpringBoot 2.3.11 、Spring Cloud H)

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.3.11.RELEASE</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
   <java.version>1.8</java.version>
   <spring-cloud.version>Hoxton.SR11</spring-cloud.version>
</properties>
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2、在application.yml啟⽤熔斷器機制

feign:
  hystrix:
    enabled: true    

3、在啟動類新增 @EnableHystrix

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

4、建立服務降級處理類

5、FeignClient的服務降級類:

  5.1.必須實現Feign客戶端接⼝

  5.2.必須交給Spring容器管理

@Component
public class OrderAddClientFallback implements OrderAddClient {
    public ResultVO addOrder(Order order, String str) {
        System.out.println("-------addOrder的降級服務");
        return ResultVO.fail("fail",null);
    }
    public Order getOrder(String orderId) {
        System.out.println("-------getOrder的降級服務");
        return new Order();
    }
}

6、在Feign客戶端指定降級處理類

@FeignClient(value = "order-add", fallback =OrderAddClientFallback.class)
public interface OrderAddClient {
    //1.對⽤POST請求調⽤服務,Feign客戶端的⽅法引數預設為body傳值(body只能有⼀個值)
    //2.如果有多個引數,則需要透過@RequestParam宣告引數為請求⾏傳值
    @PostMapping("order/add")
    public ResultVO addOrder(Order order,@RequestParam("str") String str);
@GetMapping(
"order/get") public Order getOrder(@RequestParam("orderId") String orderId); }

7、Service類透過Feign客戶端調⽤服務

@Service
public class OrderAddServiceImpl implements OrderAddService {
    @Autowired
    private OrderAddClient orderAddClient;
    //當我們建立Feign客戶端的降級類並交給Spring管理後 在Spring容器中就會出現兩個OrderAddClient物件
    @Override
    public ResultVO saveOrder(Order order) {
        //1. 調⽤ order-add服務進⾏儲存
        ResultVO vo = orderAddClient.addOrder(order,"測試字串");
        Order order1 = orderAddClient.getOrder("訂單編號");
        System.out.println(order1);
        return vo;
    }
}

5、Ribbon 引數配置

ribbon:
  ## Ribbon建⽴連線最⼤等待時間
  ConnectTimeout: 1000
  ## 在當前服務提供者嘗試連線次數
  MaxAutoRetries: 2
  ## 與服務提供者通訊時間
  ReadTimeout: 5000

## 設定熔斷器服務降級時間 (預設 1000)
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 8000

6、熔斷器儀表盤監控

檢視各個服務的熔斷器狀態皮膚:
  • 熔斷器儀表盤

6.1、搭建熔斷器儀表盤

1、建立SpringBoot項⽬,新增依賴

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

2、配置儀表盤的port和appName

server:
  port: 9999
spring:
  application:
    name: hystrix-dashboard
hystrix:
  dashboard:
    proxy-stream-allow-list: localhost

3、啟動類新增 @EanbleHystrixDashboard 註解

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

4、訪問 http://localhost:9999/hystrix

6.2、配置使⽤了熔斷器的服務可被監控

1、新增依賴

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

2、配置(給每個需要監控熔斷器的專案配置)

@Configuration
public class DashBoardConfig {
     @Bean
     public ServletRegistrationBean getServletRegistrationBean(){
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setName("HystrixMetricsStreamServlet");
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        return registrationBean;
    }
}

3、檢視指定服務的熔斷器⼯作引數

 

 

相關文章