Spring Cloud 笔记

1.Spring Cloud

1.微服务产⽣的背景

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xZ0OG79L-1662806970229)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220905131949026.png)]

单体应⽤存在的问题:

  • 随着业务的发展,开发变得越来越复杂。
  • 修改、新增某个功能,需要对整个系统进⾏测试,重写部署。
  • ⼀个模块出现问题,很可能导致整个系统崩溃。
  • 多团队同时对数据进⾏管理,容易产⽣安全漏洞。
  • 各个模块使⽤同⼀种技术框架,局限性太⼤,很难根据业务选择最适合的技术架构。
  • 模块内容太复杂,如果员⼯离职,可能需要很⻓时间才能完成任务交接。

为了解决上述问题,微服务架构应运⽽⽣,简单来说,微服务就是将⼀个单体应⽤拆分成若⼲个⼩型服务,协同完成系统功能的⼀种架构模式,在系统架构层⾯进⾏解耦合,将⼀个复杂问题拆分成若⼲个简单问题。

这样的好处是对于每⼀个简单问题,开发、维护、部署的难度就降低了很多,可以实现⾃治,可以⾃主选择最适合的技术框架,提⾼了项⽬开发的灵活性。

微服务架构不仅是简单的拆分,拆分之后的各个微服务之间还要进⾏通信,否则就⽆法协同完成需求。微服务之间只需要制定统⼀的协议即可,⾄于每个微服务使⽤什么技术框架来完成,统统不需要关⼼。

这种松耦合的⽅式使得开发、部署都变得更加灵活,同时系统更容易扩展,降低了开发、运维的难度。

2.微服务的优点

  • 各个服务之间实现了松耦合,彼此之间不需要关注对⽅是⽤什么语⾔开发,什么技术开发,只需要保证⾃⼰的接⼝可以正常访问即可,通过标准协议访问其他接⼝即可。
  • 各个微服务之间独⽴⾃治,只需要专注于做好⾃⼰的业务,开发和维护不会影响到其他的微服务。
  • 微服务是⼀种去中⼼化的架构⽅式,相当于⽤零件拼接⼀台机器,如果某个零件出现问题,可以随时进⾏替换从⽽保证机器的正常运⾏。

3.微服务的不⾜

  • 如果某个系统的远程调⽤出现问题,导致微服务不可⽤,就有可能产⽣级联反应,造成整个系统的崩溃。
  • 如果某个需求需要调⽤多个微服务,如何来保证数据的⼀致性。
  • 相⽐较于单体应⽤,微服务的学习难度会增加,对于新加⼊团队的员⼯来讲,如何快速掌握上⼿微服务架构,是⼀个问题。

4.微服务设计原则

从⼤到⼩,提炼出核⼼需求,搞清楚服务间的交互关系,先拆分成粒度较⼤的服务,然后再根据具体的业务需求逐步细化服务粒度,最终形成⼀套合理的微服务系统架构。

  • 服务粒度不能太⼩也不能太⼤,提炼核⼼需求,根据服务间的交互关系找到最合理的服务粒度。
  • 各个微服务的功能职责尽量单⼀,避免出现多个服务处理同⼀个需求。
  • 各个微服务之间要相互独⽴、⾃治,⾃主开发、⾃主测试、⾃主部署、⾃主维护。
  • 保证数据的独⽴性,各个微服务独⽴管理其业务模型下的数据。
  • 使⽤ RESTful 协议完成微服务之间的协作任务,数据交互采⽤ JSON 格式,⽅便调⽤和整合。

5.微服务架构的核⼼组件

  • 服务治理 : 服务注册 服务发现

提供服务的叫做服务提供者,调⽤服务的叫做服务消费者

  • 服务负载均衡
  • 服务⽹关
  • 微服务容错机制
  • 分布式配置
  • 服务监控

6.解决⽅案

Spring Cloud

微服务是⼀种分布式软件架构设计⽅式,具体的落地⽅案有很多,Dubbo、Spring Boot/SpringCloud、Motan 等等,Spring Cloud 基于 Spring Boot 使得整体的开发、配置、部署都⾮常⽅便,可以快速搭建基于微服务的分布式应⽤,Spring Cloud 相当于微服务各个组件的集⼤成者。

7.Spring Boot Spring Cloud 的关系

Spring Boot 快速搭建基础系统,Spring Cloud 在此基础上实现分布式系统中的公共组件,如服务注册、服务发现、配置管理、熔断器、控制总线等,服务调⽤⽅式是基于 REST API

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WH53uOVs-1662806970231)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220905234122522.png)]

8.搭建微服务系统的核⼼中枢

服务治理的核⼼组件:

  • 服务提供者
  • 服务消费者
  • 注册中⼼

分布式系统架构中,每个微服务在启动时,将⾃⼰的信息存储在注册中⼼,服务注册。

服务消费者从注册中⼼查询服务提供者的⽹络信息,并通过此信息调⽤服务提供者的接⼝,服务发现。

注册中⼼管理各个微服务:通过⼼跳机制,每隔⼀定的时间微服务会向注册中⼼进⾏汇报,如果注册中⼼⻓时间⽆法与某个微服务通信,就会⾃动销毁该服务。

当某个微服务的⽹络信息发⽣变化时,会重新注册。

服务提供者、服务消费者、注册中⼼的关联:

  • 启动注册中⼼
  • 服务提供者启动,在注册中⼼注册⼀个可以提供服务的实例。
  • 服务消费者启动,在注册中⼼订阅需要调⽤的服务。
  • 注册中⼼将服务提供者的信息推送给服务调⽤者。
  • 服务调⽤者通过相关信息(IP、端⼝)调⽤服务提供者的服务。

注册中⼼核⼼模块:

  • 服务注册表
  • 服务注册
  • 服务发现
  • 服务检查

Spring Cloud 的服务治理可以使⽤ Eureka 组件

9.什么是 Eureka

Spring Cloud Eureka,提供服务注册和服务发现功能。

参考大神的图

img

preview

如上图所示:库存服务,仓储服务,积分服务,都有一个Eureka Client组件组件,这个专门这个服务的信息注册到Eureka Server中,说白了就是告诉Eureka Server,自己在哪台机器上,监听那个端口,而Eureka 是一个注册中心,里面有一个注册表,保存了各个服务器的机器和端口,

订单服务里面有一个Eureka Client组件组件,Eureka Client组件会问一下:库存在那台服务器上,监听的端口号是哪个,仓储服务呢?积分服务呢?然后就可以把这些相关信息从Eureka Server的注册表中拉取到自己本地缓存起来。

这时候如果订单服务想要调用库存服务,不就可以找自己本地Eureka Client问题下库存服务在那台机器上,监听哪个端口吗?收到响应后,紧接着就可以发送一个请求过去,调用库存服务扣减库存的那个接口!同理,如果订单服务要调用仓储服务、积分服务,也是如法炮制。

所以总结下:

**Eureka service:**注册中心,里面有一个注册表,保存了各个服务所在的机器和端口号

**Eurake Client:**负责将这个服务的信息注册到Eureka Server中

2.代码实现

1.创建 Maven ⽗⼯程,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>
    <!-- JDK9 -->
    <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>

2.在⽗⼯程⽬录下创建 Module,实现 Eureka Server,pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>
  1. 在Eureka Server中配置application.yml
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/

4.创建启动类

package com.ag;

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-odsfjJPr-1662806970236)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220907200920185.png)]

5.启动,访问 http://localhost:8761,可以看到如下界⾯,启动成功。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HCgc01Te-1662806970239)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220907000655192.png)]

注册第⼀个微服务

服务提供者和服务消费者都是通过 Eureka Client 连接到 Eureka Server 完成注册

1.创建 Modelu,实现 Eureka Client。

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

2.application.yml

server:
  port: 8010
spring:
  application:
    name: provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

3.创建启动类

package com.ag;

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

4.实体类

package com.ag.entity;

import lombok.Data;

@Data
public class Student {
    private Integer id;
    private String name;

}

5.创建 Repository

package com.ag.repository;

import com.ag.entity.Student;

import java.util.Collection;

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

import com.ag.entity.Student;
import com.ag.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<Integer,Student> map;
    static {
        map = new HashMap<>();
        map.put(1,new Student(1,"张三"));
        map.put(2,new Student(2,"李四"));
        map.put(3,new Student(3,"王五"));
    }

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

    @Override
    public Student findById(Integer id) {
        return map.get(id);
    }

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

    @Override
    public void deleteById(Integer id) {
        map.remove(id);
    }
}

6.StudentHandler

package com.ag.controller;

import com.ag.entity.Student;
import com.ag.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") Integer 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") Integer id){
        studentRepository.deleteById(id);
    }
}

先启动server 在启动provider

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jZZ5Up48-1662806970240)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220908001828807.png)]

3.RestTemplate

通过 RestTemplate 可以实现不同微服务之间的调⽤。

RestTemplate 是 Spring 框架提供的⼀种基于 RESTful 的服务组件,底层对 HTTP 请求及响应进⾏了封装,提供了很多访问远程 REST 服务的⽅法,可以简化代码的开发。

1.创建 Maven ⼯程,pom.xml

<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<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>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

2.创建 User 类

package com.ag.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String name;
}

3.创建 UserRepository 接⼝及实现类

package com.ag.repository;

import com.ag.entity.User;

import java.util.Collection;

public interface UserRepository {
    public Collection<User> findAll();
    public User findById(Integer id);
    public void saveOrUpdate(User user);
    public void deleteById(Integer id);
}
package com.ag.repository.impl;

import com.ag.entity.User;
import com.ag.repository.UserRepository;
import org.springframework.stereotype.Repository;

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

@Repository
public class UserRepositoryImpl implements UserRepository {

    private static Map<Integer,User> map;
         static {
             map=new HashMap<>();
             map.put(1,new User(1,"tutu01"));
             map.put(2,new User(2,"tutu02"));
             map.put(3,new User(3,"tutu03"));
         }

    @Override
    public Collection<User> findAll() {
        return map.values();
    }

    @Override
    public User findById(Integer id) {
        return map.get(id);
    }

    @Override
    public void saveOrUpdate(User user) {
        map.put(user.getId(),user);
    }

    @Override
    public void deleteById(Integer id) {
             map.remove(id);

    }
}

4.创建 UserHandler

package com.ag.controller;

import com.ag.entity.User;
import com.ag.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@RestController
@RequestMapping("/user")
public class UserHandler {
    @Autowired
    private UserRepository userRepository;
    @GetMapping("/findAll")
    public Collection<User> findAll(){
        return userRepository.findAll();
    }
    @GetMapping("/findById/{id}")
    public User findById(@PathVariable("id") Integer id){
        return userRepository.findById(id);
    }
    @PostMapping("/save")
    public void save(@RequestBody User user){
        userRepository.saveOrUpdate(user);
    }
    @PutMapping("/update")
    public void update(@RequestBody User user){
        userRepository.saveOrUpdate(user);
    }
    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") Integer id){
        userRepository.deleteById(id);
    }
}

5.创建启动类

package com.ag;

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

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

1.使⽤ RestTemplate 访问 REST 服务

RestTemplate 底层对 HTTP 请求及响应进⾏了封装,提供了很多访问远程 REST 服务的⽅法,基于它的这个特性,我们可以实现不同微服务之间的调⽤。

什么是RestTemplate?

RestTemplate提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问restful服务模板类,是spring提供的用于访问Rest服务的客户端模板工具集

RestTemplate使用:

使用restTemplate访问restful接口非常的简单粗暴无脑。

(url,requestMap,ResponseBean.class)这是三个参数分别代表

REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。

1.将 RestTemplate 的实例化对象通过 @Bean 注⼊ IoC

package com.ag.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class MyConfig {

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

2.创建 RestHandler

package com.ag.controller;

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

import java.util.Collection;
import java.util.Collections;

@RestController
@RequestMapping("/rest")
public class RestHandler {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/findAll")
    public Collection<User> findAll(){
        return restTemplate.getForObject("http://localhost:8080/user/findAll",Collection.class);

    }

    @GetMapping("/findById/{id}")
    public User findById(@PathVariable("id") Integer id){
        return restTemplate.getForObject("http://localhost:8080/user/findById/{id}",User.class,id);
    }

    @PostMapping("/save")
    public void save(@RequestBody User user) {
        restTemplate.postForObject("http://localhost:8080/user/save", user, Collection.class);
    }
    @PutMapping("/update")
    public void update(@RequestBody User user){
        restTemplate.put("http://localhost:8080/user/update",user);
    }
    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") Integer id){
        restTemplate.delete("http://localhost:8080/user/deleteById/{id}",id);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GBIhnGoi-1662806970242)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220908140343081.png)]

4.服务消费者

1.创建 Module,pom.xml

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

2.application.yml

server:
  port: 8020
spring:
  application:
    name: consumer
eureka:
  instance:
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  

3.配置启动类和RestTemplate

package com.ag;

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 Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }

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

4.实体类

package com.ag.entity;

import lombok.Data;

@Data
public class Student {
    private Integer id;
    private String name;
}

5.StudentHandler

package com.ag.controller;

import com.ag.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 StudentHandler {

    @Autowired
    private RestTemplate restTemplate;

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

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

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        restTemplate.postForObject("http://localhost:8010/provider/save",student,Student.class);
    }
    @PutMapping("/update")
    public void update(@RequestBody Student student){
        restTemplate.put("http://localhost:8010/provider/update",student);
    }
    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") Integer id){
        restTemplate.delete("http://localhost:8010/provider/deleteById/{id}",id);
    }
}

在这里插入图片描述

5.服务⽹关

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0hEY3J4t-1662806970247)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220908192210212.png)]

API ⽹关可以对所有的 API 请求进⾏统⼀的管理维护,相当于为系统开放出⼀个统⼀的接⼝,所有的外部请求只需要统⼀访问这个外部⼊⼝即可,系统内部再通过 API ⽹关去映射不同的微服务。

对于开发者⽽⾔就不需要关注具体的微服务 URL,直接访问⽹关即可。

Spring Cloud Zuul

1.创建 Module,pom.xml

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

2.application.yml

server:
  port: 8030
spring:
  application:
    name: gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
zuul:
  routes:
    provider: /p/** 
#    给provider服务起别名,

3.创建启动类

package com.ag;

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

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

在这里插入图片描述

6.Ribbon 负载均衡

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wp2XVyu0-1662806970253)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220908204342815.png)]

Spring Cloud 提供的⼀种负载均衡解决⽅案,Ribbon 是 Netflflix 发布的负载均衡器,Spring Cloud Ribbon。

Ribbon 的使⽤同样需要结合 Eureka Server

负载均衡算法:轮询、随机、加权轮询、加权随机

1.创建 Module,pom.xml

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

2.application.yml

server:
  port: 8040
spring:
  application:
    name: ribbon
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

3.创建启动类 和restTemplate @LoadBalanced配置负载均衡

package com.ag;

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

4.创建handler

package com.ag.conteoller;

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;

@RestController
@RequestMapping("/ribbon")
public class RibbonHandler {

    @Autowired
    private RestTemplate restTemplate;

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

5.在consumer的controller中配置

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

@GetMapping("/index")
public String index(){
    return "consumer: "+port;
}

6.再建立一个启动类
在这里插入图片描述

启动一个启动类后,改端口为8021,然后启动另一个启动了

在这里插入图片描述

实现了负载均衡

7.Fiegn 声明式接⼝调⽤

1.什么是Feign

Netflflix,Feign 是⼀个提供模版的声明式 Web Service 客户端,使⽤ Feign 可以简化 Web Service 客户端的编写,开发者可以通过简单的接⼝和注解来调⽤ HTTP API。

Spring Cloud Feign:可插拔、基于注解、负载均衡、服务熔断

Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观

Feign 的特点:

  • Feign 是⼀个声明式 Web Service 客户端
  • ⽀持 Feign 注解、Spring MVC 注解
  • Feign 基于 Ribbon 实现
  • Feign 集成了 Hystrix

1.创建 Module,pom.xml

<dependencies>
    <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-openfeign</artifactId>
    </dependency>
</dependencies>

2.application.yml

server:
  port: 8050
spring:
  application:
    name: fiegn
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true    

3.启动类

package com.ag;

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

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

4.实体类

package com.ag.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private String name;

}

5.FeignProviderClient 接⼝

package com.ag.fiegn;

import com.ag.entity.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@FeignClient("provider") //写服务的名称(yml中配置的)
public interface FeignProviderClient {

    @GetMapping("/provider/findAll")
    public Collection<Student> findAll();

    @GetMapping("/provider/findById/{id}")
    public Student findById(@PathVariable("id") Integer id);
    @PostMapping("/provider/save")
    public void save(@RequestBody Student student);
    @PutMapping("/provider/update")
    public void update(@RequestBody Student student);
    @DeleteMapping("/provider/deleteById/{id}")
    public void deleteById(@PathVariable("id") Integer id);
}

6.handler

package com.ag.controller;

import com.ag.entity.Student;
import com.ag.fiegn.FeignProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@RestController
@RequestMapping("/fiegn")
public class fiegnHandler {

    @Autowired
    private FeignProviderClient feignProviderClient;

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

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        feignProviderClient.save(student);
    }
    @PutMapping("/update")
    public void update(@RequestBody Student student){
        feignProviderClient.update(student);
    }
    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") Integer id){
        feignProviderClient.deleteById(id);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0X18VoMP-1662806970259)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220909141503953.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IMbioMQW-1662806970260)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220909141512595.png)]

8.Hystrix 容错监控机制

什么是微服务的容错机制

提前预设解决⽅案,系统进⾏⾃主调节,遇到问题及时处理

什么是 Hystrix

Netflflix

设计原则

  • 服务隔离机制
  • 服务降级机制
  • 熔断机制
  • 提供实时的监控和报警功能
  • 提供实时的配置修改功能

1.创建 Module,pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SpringCloud</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hystrix</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
    <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-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>
</dependencies>

</project>

2.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'

3.创建启动类

package com.ag;

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

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker // 开启熔断器
public class hystrixApplication {
    public static void main(String[] args) {
        SpringApplication.run(hystrixApplication.class,args);
    }
}

4.实体类

package com.ag.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private String name;

}

5.FeignProviderClient 接⼝

package com.ag.fiegn;

import com.ag.entity.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@FeignClient("provider") //写服务的名称(yml中配置的)
public interface FeignProviderClient {

    @GetMapping("/provider/findAll")
    public Collection<Student> findAll();

    @GetMapping("/provider/findById/{id}")
    public Student findById(@PathVariable("id") Integer id);
    @PostMapping("/provider/save")
    public void save(@RequestBody Student student);
    @PutMapping("/provider/update")
    public void update(@RequestBody Student student);
    @DeleteMapping("/provider/deleteById/{id}")
    public void deleteById(@PathVariable("id") Integer id);
}

6.controller

package com.ag.controller;

import com.ag.entity.Student;
import com.ag.fiegn.FeignProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@RestController
@RequestMapping("/fiegn")
public class hystrixHandler {

    @Autowired
    private FeignProviderClient feignProviderClient;

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

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        feignProviderClient.save(student);
    }
    @PutMapping("/update")
    public void update(@RequestBody Student student){
        feignProviderClient.update(student);
    }
    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") Integer id){
        feignProviderClient.deleteById(id);
    }
}

数据监控 URL:http://localhost:8060/actuator/hystrix.stream

在这里插入图片描述

7.添加可视化界⾯组件

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

8.启动类添加相应注解

package com.ag;

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

可视化界⾯ URL:http://localhost:8060/hystrix

在这里插入图片描述
在这里插入图片描述

9.Spring Cloud Confifig 本地配置

我们可以将微服务的相关配置⽂件存储到本地⽂件中,然后让微服务来读取本地配置⽂件

就是把各个微服务的配置文件集中在一起,统一管理。

创建本地 Confifig Server

1.创建 Module nativeconfigserver,pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
</dependencies>

2.application.yml

server:
  port: 8762
spring:
  application:
    name: nativeconfigserver
#    设置类型为本地
  profiles:
    active: native
#    设置检索路径
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/shared

3.在 resources 路径下创建 shared ⽂件夹,并在此路径下创建本地配置⽂件 confifigclient-dev.yml

server:
  port: 8070
foo: foo version 1

4.创建启动类

package com.ag;

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

创建客户端读取配置中⼼的配置⽂件。

1.创建 Module nativeconfigclient,pom.xml

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

2.bootstrap.yml

#这个是在配置中心的文件名,寻找 configclient-dev名称的配置文件
spring:
  application:
   name: configclient
  profiles:
   active: dev
#   这个是配置中心的路径
  cloud:
   config:
    uri: http://localhost:8762
    fail-fast: true

3.创建启动类

package com.ag;

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

4.handler

package com.ag.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;
    }
}

客户端成功读取到了配置中心的数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OggyjFER-1662806970265)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220910153907595.png)]

10.Spring Cloud 服务跟踪

Zipkin 实现服务跟踪

什么是 Zipkin

  • Zipkin Server
  • Zipkin Client

Spring Cloud Sleuth 集成了 Zipkin

创建 Zipkin Server

1.创建 Module zipkinserver,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>

2.application.yml

server:
  port: 9091

3.启动类

package com.ag;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin.server.internal.EnableZipkinServer;

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

创建 Zipkin Client

1、创建 Module zipkinclient,pom.xml

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

2.application.yml

server:
  port: 8090
spring:
  application:
   name: zipkinclient
#   启用 服务跟踪的web客户端
  sleuth:
    web:
     client:
      enabled: true
#spring.sleuth.sampler.probability可以设置为小数,最大值为1.0,当设置为1.0时就是链路数据100%收集到zipkin-server,
#  当设置为0.1时,即10%概率收集链路数据
    sampler:
      probability: 1.0
#      关联server
  zipkin:
   base-url: http://localhost:9091/
eureka:
 client:
  service-url:
   defaultZone: http://localhost:8761/eureka/

3.创建启动类

package com.ag;

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

4.handler

package com.ag.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;
    }
}

依次启动注册中⼼、Zipkin Server、Zipkin Client

访问 http://localhost:9091/zipkin/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nt2XPeMS-1662806970266)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220910164651585.png)]

客户端发起 Zipkin Client 请求,点击 Find Traces,可以看到服务跟踪数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aU0ZM1gw-1662806970266)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220910165002260.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B40mDRU8-1662806970267)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220910164745435.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kATCvqaX-1662806970268)(C:\Users\AnGeng\AppData\Roaming\Typora\typora-user-images\image-20220910164807411.png)]

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值