springcloud筆記

單體應(yīng)用存在的問(wèn)題

  • 隨著業(yè)務(wù)的發(fā)展,開(kāi)發(fā)變得越來(lái)越復(fù)雜。
  • 修改、新增某個(gè)功能,需要對(duì)整個(gè)系統(tǒng)進(jìn)行測(cè)試、重新部署。
  • 一個(gè)模塊出現(xiàn)問(wèn)題,很可能導(dǎo)致整個(gè)系統(tǒng)崩潰。
  • 多個(gè)開(kāi)發(fā)團(tuán)隊(duì)同時(shí)對(duì)數(shù)據(jù)進(jìn)行管理,容易產(chǎn)生安全漏洞。
  • 各個(gè)模塊使用同一種技術(shù)進(jìn)行開(kāi)發(fā),各個(gè)模塊很難根據(jù)實(shí)際情況選擇更合適的技術(shù)框架,局限性很大。
  • 模塊內(nèi)容過(guò)于復(fù)雜,如果員工離職,可能需要很長(zhǎng)時(shí)間才能完成工作交接。

分布式、集群

集群:一臺(tái)服務(wù)器無(wú)法負(fù)荷高并發(fā)的數(shù)據(jù)訪問(wèn)量,那么就設(shè)置十臺(tái)服務(wù)器一起分擔(dān)壓力,十臺(tái)不行就設(shè)置一百臺(tái)(物理層面)。很多人干同一件事情,來(lái)分?jǐn)倝毫Α?/p>

分布式:將一個(gè)復(fù)雜問(wèn)題拆分成若干個(gè)簡(jiǎn)單的小問(wèn)題,將一個(gè)大型的項(xiàng)目架構(gòu)拆分成若干個(gè)微服務(wù)來(lái)協(xié)同完成。(軟件設(shè)計(jì)層面)。將一個(gè)龐大的工作拆分成若干個(gè)小步驟,分別由不同的人完成這些小步驟,最終將所有的結(jié)果進(jìn)行整合實(shí)現(xiàn)大的需求。

服務(wù)治理的核心又三部分組成:服務(wù)提供者、服務(wù)消費(fèi)者、注冊(cè)中心。

在分布式系統(tǒng)架構(gòu)中,每個(gè)微服務(wù)在啟動(dòng)時(shí),將自己的信息存儲(chǔ)在注冊(cè)中心,叫做服務(wù)注冊(cè)。

服務(wù)消費(fèi)者從注冊(cè)中心獲取服務(wù)提供者的網(wǎng)絡(luò)信息,通過(guò)該信息調(diào)用服務(wù),叫做服務(wù)發(fā)現(xiàn)。

Spring Cloud 的服務(wù)治理使用 Eureka 來(lái)實(shí)現(xiàn),Eureka 是 Netflix 開(kāi)源的基于 REST 的服務(wù)治理解決方案,Spring Cloud 集成了 Eureka,提供服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)的功能,可以和基于 Spring Boot 搭建的微服務(wù)應(yīng)用輕松完成整合,開(kāi)箱即用,Spring Cloud Eureka。

Spring Cloud Eureka

  • Eureka Server,注冊(cè)中心
  • Eureka Client,所有要進(jìn)行注冊(cè)的微服務(wù)通過(guò) Eureka Client 連接到 Eureka Server,完成注冊(cè)。

Eureka Server代碼實(shí)現(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 以上沒(méi)有 JAXB API 的問(wèn)題 -->
  <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 相關(guān)配置。
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/

屬性說(shuō)明

server.port:當(dāng)前 Eureka Server 服務(wù)端口。

eureka.client.register-with-eureka:是否將當(dāng)前的 Eureka Server 服務(wù)作為客戶端進(jìn)行注冊(cè)。

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

eureka.client.service-url.defaultZone:注冊(cè)中心的訪問(wèn)地址。

  • 創(chuàng)建啟動(dò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);
    }
}

注解說(shuō)明:

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

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

Eureka Client 代碼實(shí)現(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 相關(guān)配置
server:
  port: 8010
spring:
  application:
    name: provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

屬性說(shuō)明:

spring.application.name:當(dāng)前服務(wù)注冊(cè)在 Eureka Server 上的名稱。

eureka.client.service-url.defaultZone:注冊(cè)中心的訪問(wèn)地址。

eureka.instance.prefer-ip-address:是否將當(dāng)前服務(wù)的 IP 注冊(cè)到 Eureka Server。

  • 創(chuàng)建啟動(dò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);
    }
}
  • 實(shí)體類
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 的服務(wù)組件,底層是對(duì) HTTP 請(qǐng)求及響應(yīng)進(jìn)行了封裝,提供了很多訪問(wèn) RETS 服務(wù)的方法,可以簡(jiǎn)化代碼開(kāi)發(fā)。

  • 如何使用 RestTemplate?

1、創(chuàng)建 Maven 工程,pom.xml。

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

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、啟動(dò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 RestTemplateApplication {
    public static void main(String[] args) {
        SpringApplication.run(RestTemplateApplication.class,args);
    }

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

服務(wù)消費(fèi)者 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)建啟動(dò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ù)網(wǎng)關(guān)

Spring Cloud 集成了 Zuul 組件,實(shí)現(xiàn)服務(wù)網(wǎng)關(guān)。

  • 什么是 Zuul?

Zuul 是 Netflix 提供的一個(gè)開(kāi)源的 API 網(wǎng)關(guān)服務(wù)器,是客戶端和網(wǎng)站后端所有請(qǐng)求的中間層,對(duì)外開(kāi)放一個(gè) API,將所有請(qǐng)求導(dǎo)入統(tǒng)一的入口,屏蔽了服務(wù)端的具體實(shí)現(xiàn)邏輯,Zuul 可以實(shí)現(xiàn)反向代理的功能,在網(wǎng)關(guān)內(nèi)部實(shí)現(xiàn)動(dòng)態(tài)路由、身份認(rèn)證、IP 過(guò)濾、數(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/**

屬性說(shuō)明:

zuul.routes.provider:給服務(wù)提供者 provider 設(shè)置映射

  • 創(chuàng)建啟動(dò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);
    }
}

注解說(shuō)明:

@EnableZuulProxy:包含了 @EnableZuulServer,設(shè)置該類是網(wǎng)關(guān)的啟動(dòng)類。

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

  • Zuul 自帶了負(fù)載均衡功能,修改 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 "當(dāng)前端口:"+this.port;
    }
}

Ribbon 負(fù)載均衡

  • 什么是 Ribbon?

Spring Cloud Ribbon 是一個(gè)負(fù)載均衡解決方案,Ribbon 是 Netflix 發(fā)布的負(fù)載均衡器,Spring Cloud Ribbon 是基于 Netflix Ribbon 實(shí)現(xiàn)的,是一個(gè)用于對(duì) HTTP 請(qǐng)求進(jìn)行控制的負(fù)載均衡客戶端。

在注冊(cè)中心對(duì) Ribbon 進(jìn)行注冊(cè)之后,Ribbon 就可以基于某種負(fù)載均衡算法,如輪詢、隨機(jī)、加權(quán)輪詢、加權(quán)隨機(jī)等自動(dòng)幫助服務(wù)消費(fèi)者調(diào)用接口,開(kāi)發(fā)者也可以根據(jù)具體需求自定義 Ribbon 負(fù)載均衡算法。實(shí)際開(kāi)發(fā)中,Spring Cloud Ribbon 需要結(jié)合 Spring Cloud Eureka 來(lái)使用,Eureka Server 提供所有可以調(diào)用的服務(wù)提供者列表,Ribbon 基于特定的負(fù)載均衡算法從這些服務(wù)提供者中選擇要調(diào)用的具體實(shí)例。

  • 創(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)建啟動(dò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:聲明一個(gè)基于 Ribbon 的負(fù)載均衡。

  • 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 是一個(gè)聲明式、模版化的 Web Service 客戶端,它簡(jiǎn)化了開(kāi)發(fā)者編寫(xiě) Web 服務(wù)客戶端的操作,開(kāi)發(fā)者可以通過(guò)簡(jiǎn)單的接口和注解來(lái)調(diào)用 HTTP API,Spring Cloud Feign,它整合了 Ribbon 和 Hystrix,具有可插拔、基于注解、負(fù)載均衡、服務(wù)熔斷等一系列便捷功能。

相比較于 Ribbon + RestTemplate 的方式,F(xiàn)eign 大大簡(jiǎn)化了代碼的開(kāi)發(fā),F(xiàn)eign 支持多種注解,包括 Feign 注解、JAX-RS 注解、Spring MVC 注解等,Spring Cloud 對(duì) Feing 進(jìn)行了優(yōu)化,整合了 Ribbon 和 Eureka,從而讓 Feign 的使用更加方便。

  • Ribbon 和 Feign 的區(qū)別

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

  • Feign 的tedian

1、Feign 是一個(gè)聲明式的 Web Service 客戶端。

2、支持 Feign 注解、Spring MVC 注解、JAX-RS 注解。

3、Feign 基于 Ribbon 實(shí)現(xiàn),使用起來(lái)更加簡(jiǎn)單。

4、Feign 集成了 Hystrix,具備服務(wù)熔斷的功能。

  • 創(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)建啟動(dò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();
    }
}
  • 服務(wù)熔斷,application.yml 添加熔斷機(jī)制。
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:是否開(kāi)啟熔斷器。

  • 創(chuàng)建 FeignProviderClient 接口的實(shí)現(xiàn)類 FeignError,定義容錯(cuò)處理邏輯,通過(guò) @Component 注解將 FeignError 實(shí)例注入 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 "服務(wù)器維護(hù)中......";
    }
}
  • 在 FeignProviderClient 定義處通過(guò) @FeignClient 的 fallback 屬性設(shè)置映射。
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 容錯(cuò)機(jī)制

在不改變各個(gè)微服務(wù)調(diào)用關(guān)系的前提下,針對(duì)錯(cuò)誤情況進(jìn)行預(yù)先處理。

  • 設(shè)計(jì)原則

1、服務(wù)隔離機(jī)制

2、服務(wù)降級(jí)機(jī)制

3、熔斷機(jī)制

4、提供實(shí)時(shí)的監(jiān)控和報(bào)警功能

5、提供實(shí)時(shí)的配置修改功能

Hystrix 數(shù)據(jù)監(jiān)控需要結(jié)合 Spring Boot Actuator 來(lái)使用,Actuator 提供了對(duì)服務(wù)的健康健康、數(shù)據(jù)統(tǒng)計(jì),可以通過(guò) hystrix.stream 節(jié)點(diǎn)獲取監(jiān)控的請(qǐng)求數(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)建啟動(dò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);
    }
}

注解說(shuō)明:

@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();
    }
}
  • 啟動(dòng)成功之后,訪問(wèn) http://localhost:8060/actuator/hystrix.stream 可以監(jiān)控到請(qǐng)求數(shù)據(jù),
  • 訪問(wèn) http://localhost:8060/hystrix,可以看到可視化的監(jiān)控界面,輸入要監(jiān)控的地址節(jié)點(diǎn)即可看到該節(jié)點(diǎn)的可視化數(shù)據(jù)監(jiān)控。

Spring Cloud 配置中心

Spring Cloud Config,通過(guò)服務(wù)端可以為多個(gè)客戶端提供配置服務(wù)。Spring Cloud Config 可以將配置文件存儲(chǔ)在本地,也可以將配置文件存儲(chǔ)在遠(yuǎn)程 Git 倉(cāng)庫(kù),創(chuàng)建 Config Server,通過(guò)它管理所有的配置文件。

本地文件系統(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

注解說(shuō)明

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)建啟動(dò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);
    }
}

注解說(shuō)明

@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,配置讀取本地配置中心的相關(guān)信息。
spring:
  application:
    name: configclient
  profiles:
    active: dev
  cloud:
    config:
      uri: http://localhost:8762
      fail-fast: true

注解說(shuō)明

cloud.config.uri:本地 Config Server 的訪問(wèn)路徑

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

通過(guò)spring.application.name 結(jié)合spring.profiles.active拼接目標(biāo)配置文件名,configclient-dev.yml,去 Config Server 中查找該文件。

  • 創(chuàng)建啟動(dò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 遠(yuǎn)程配置

  • 創(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)建啟動(dò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/

注解說(shuō)明

spring.cloud.config.name:當(dāng)前服務(wù)注冊(cè)在 Eureka Server 上的名稱,與遠(yuǎn)程倉(cāng)庫(kù)的配置文件名對(duì)應(yīng)。

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

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

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

  • 創(chuàng)建啟動(dò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;
    }
}

服務(wù)跟蹤

Spring Cloud Zipkin

Zipkin 是一個(gè)可以采集并且跟蹤分布式系統(tǒng)中請(qǐng)求數(shù)據(jù)的組件,讓開(kāi)發(fā)者可以更加直觀的監(jiān)控到請(qǐng)求在各個(gè)微服務(wù)所耗費(fèi)的時(shí)間等,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)建啟動(dò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);
    }
}

注解說(shuō)明

@EnableZipkinServer:聲明啟動(dòng) 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/

屬性說(shuō)明

spring.sleuth.web.client.enabled:設(shè)置開(kāi)啟請(qǐng)求跟蹤

spring.sleuth.sampler.probability:設(shè)置采樣比例,默認(rèn)是 1.0

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

  • 創(chuàng)建啟動(dò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;
    }
}

更多詳情

設(shè)置為vip可見(jiàn)的都可訪問(wèn)下面鏈接地址,即可觀看原文
更多詳情請(qǐng)?jiān)L問(wèn): juntech

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 基于上一篇SpringCloud筆記實(shí)現(xiàn)了Eureka服務(wù)的注冊(cè)和發(fā)現(xiàn)。在微服務(wù)架構(gòu)中,業(yè)務(wù)都會(huì)被拆分成一個(gè)獨(dú)立的...
    二枚目閱讀 288評(píng)論 0 0
  • Spring Cloud是一個(gè)基于Spring Boot實(shí)現(xiàn)的云應(yīng)用開(kāi)發(fā)工具,它為基于JVM的云應(yīng)用開(kāi)發(fā)中涉及的配...
    二枚目閱讀 726評(píng)論 0 1
  • 微服務(wù)架構(gòu)模式的核心在于如何識(shí)別服務(wù)的邊界,設(shè)計(jì)出合理的微服務(wù)。但如果要將微服務(wù)架構(gòu)運(yùn)用到生產(chǎn)項(xiàng)目上,并且能夠發(fā)揮...
    java菜閱讀 3,047評(píng)論 0 6
  • 斷路器Hystrix 在微服務(wù)架構(gòu)中,系統(tǒng)被拆分成了一個(gè)個(gè)小的服務(wù)單元,各自運(yùn)行在自己的線程中,各單元之間通過(guò)注冊(cè)...
    二枚目閱讀 3,131評(píng)論 0 0
  • 一、簡(jiǎn)介 Spring Cloud 為開(kāi)發(fā)者提供了在分布式系統(tǒng)(配置管理,服務(wù)發(fā)現(xiàn),熔斷,路由,微代理,控制總線,...
    生活的探路者閱讀 1,089評(píng)論 0 6

友情鏈接更多精彩內(nèi)容