SpringCloud之微服务实用篇2

news2025/7/18 17:48:12

在之前我们学习微服务中的两个组件,一个是注册中心,一个负载均衡器。今天,我们主要学习三个内容,分别是:Nacos配置管理、Feign远程调用、Gateway服务网关。

目录

一、Nacos配置管理

1.1、Nacos实现配置管理

1.2、微服务配置拉取

1.3、 配置热更新

1.4、多环境配置共享

1.5、nacos集群搭建

二、Feign远程调用

2.1、基于Feign远程调用

2.2、Feign自定义配置

​编辑2.3、Feign性能优化

 2.4、Feign最佳实践分析与实现

三、Gateway服务网关

3.1、网关的作用及快速入门

3.2、路由断言工厂

3.3、路由过滤器的配置

3.4、全局过滤器

3.5、过滤器链的执行顺序

3.6、网关的cors跨域配置


一、Nacos配置管理

1.1、Nacos实现配置管理

Nacos既可以作为注册中心,也可以用来作配置管理,微服务可以从nacos中进行注册发现和胚珠读取,具体如下所示:

在nacos的配置栏中点击➕添加配置,在弹出的列表中进行配置即可,并不是所有的都要配置,需要nacos统一管理的进行配置即可。

1.2、微服务配置拉取

因为现在需要读取nacos配置文件,故需要知道nacos的地址,所以需要在bootstrap文件中配置nacos地址信息,如下所示。

需要知道去哪里拉取配置信息,并且需要知道配置信息的名称,故需要先导入配置坐标,然后在bootstrap.yml文件中输入配置的名称。

 最后在表现层,拉去配置信息,并通过浏览器请求并显示配置信息,如下:


    //注入nacos中的配置属性
    @Value("${pattern.dateformat}")
    private String dateFormat ;

    @GetMapping("/now")
    public String now(){
        System.out.println(dateFormat);
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateFormat, Locale.CHINA)) ;
    }

从nacos拉取的配置信息,输出效果如下:

1.3、 配置热更新

Nacos配置更新后,微服务不需要重启就能自动感知,需要通过下面两种方式实现。

方式1:在@Value注解上注入变量所在的类上添加@RefreshScope注解。

import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;


@Slf4j
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {


    @Autowired
    private UserService userService;

    //注入nacos中的配置属性
    @Value("${pattern.dateformat}")
    private String dateFormat ;

    @GetMapping("/now")
    public String now(){
        System.out.println(dateFormat);
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateFormat, Locale.CHINA)) ;
    }


    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        return userService.queryById(id);
    }
}

方式2:使用@ConfigurationProperties注解,可以自动刷新。

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;


@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    private String dateformat;
  //  private String envSharedValue;
   // private String name;
}

在表现层将改配置作为bean注入进来,就可以使用了,如下:
 


import cn.itcast.user.config.PatternProperties;
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;


@Slf4j
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {


    @Autowired
    private UserService userService;

    //注入nacos中的配置属性
  //  @Value("${pattern.dateformat}")
  //  private String dateFormat ;
    @Autowired
    private PatternProperties patternProperties ;


    @GetMapping("/now")
    public String now(){
        System.out.println(patternProperties.getDateformat());
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat(), Locale.CHINA)) ;
    }


    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        return userService.queryById(id);
    }
}

1.4、多环境配置共享

微服务启动时会从nacos读取多个配置文件,无论怎么变都会读取多环境的共享配置文件,所以共享配置环境的公共配置。

 在nacos中创建两个配置,一个是dev环境下的,另外一个是多环境共享的。

那么便可以在程序中加载配置中的nacos共享配置以便使用。

那么需要考虑的是,如果本地配置贺远程配置中用相同的配置,系统会选择哪一个配置呢?这就需要考虑配置优先级的问题。

优先级:远程带环境的配置>远程不带环境的配置>本地配置

1.5、nacos集群搭建

我们假设有三台nacos节点,那么首先要实现的就是数据共享,我们实现Mysql集群,让nacos来访问mysql集群,进而实现数据共享。为了将多个服务按照负载均衡分发到不同的nacos节点,故使用Nginx实现负载均衡。

 搭建nacos集群的基本步骤如下:
1)搭建数据库,初始化数据库表结构;2)下载nacos安装包;3)配置nacos;4)启动nacos集群;5)ngnix反向代理

二、Feign远程调用

2.1、基于Feign远程调用

首先我们看一下之前学的基于RestTemplate方式实现的服务的远程调用,该方法的代码可读性较差,参数复杂URL难以维护。

 今天主要需要一个声明式的http客户端,以优雅的方式发送http请求。

首先需要在pom.xml加入坐标依赖;然后加入启动注解@EnableFeignClients;然后定义一个接口;最后使用接口中定义的方法替代RestTemplate实现远程调用。


        <!--添加feign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {

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


    @LoadBalanced
    @Bean //创建RestTemplate对象,并注入Spring容器
    public RestTemplate restTemplate(){
        return new RestTemplate() ;
    }



}

import cn.itcast.feign.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;


@FeignClient("userservice")
public interface UserClient {
    @GetMapping("/user/{id}")
    User getUserById(@PathVariable Long id) ;
}

最后使用接口的getUserById方法替代RestTeplate完成远程调用。


import cn.itcast.feign.pojo.User;
import cn.itcast.order.clients.UserClient;
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.pojo.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;


    @Autowired
    private UserClient userClient ;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        //用feign实现远程调用
        User user = userClient.getUserById(order.getUserId()) ;
        //封装到order中
        order.setUser(user);
        // 4.返回
        return order;
    }

    /*@Autowired
    private RestTemplate restTemplate;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2.利用RestTemplate发起http请求,查询用户
        // 2.1.url路径
        String url = "http://userservice/user/" + order.getUserId();
        // 2.2.发送http请求,实现远程调用
        User user = restTemplate.getForObject(url, User.class);
        // 3.封装user到Order
        order.setUser(user);
        // 4.返回
        return order;
    }*/
}

2.2、Feign自定义配置

     在Feign中一般会通过自定义的配置去覆盖默认的配置,通过可以进行修改的配置如下所示。

 自定义配置feign 的方式有两种,一种是配置文件方式进行配置,具体如下:

 第二种方式是使用java代码自定义feign配置文件,可以配置为全局配置,也可以为局部配置。

2.3、Feign性能优化

 Feign的性能优化主要包含两个方面,第一:使用连接池代替默认的URLConnection,日志级别最好为none。

 Feign性能优化:连接池优化,主要就是引入依赖,然后在连接池配置参数。

 2.4、Feign最佳实践分析与实现

我们先来看feign的最佳实践分析的第一种方式,如下:但是一般情况下,不推荐这种方法,会导致紧耦合问题。

 第二种最佳实践方式,是采用抽取的方式,不同服务直接从api中引入依赖即可,最后在表现层实现服务的远程调用。

下面我们演示一下上述的最佳实践的方式2,主要分为5步,首先需要创建一个名称为feign-api的module,然后引入feign的依赖,然后在将需要抽取的内容复制到feign-api中,最后直接在服务中引入feign-api依赖就可以,当然相应的包也需要换成feign-api中的包,最后重启服务,测试即可。

 这种方法在最后注入UserClient的时候发现不能注入,因为没有扫描到包,应该在@EnableFeignClients注解中加入要扫描的包或者直接指定要扫描的类,我直接扫描类,具体如下:

@EnableFeignClients(clients = UserClient.class)

三、Gateway服务网关

3.1、网关的作用及快速入门

网关的主要功能有三个,分别为:身份认证和权限校验;服务路由与负载均衡;请求限流等。

网关技术的两种实现方式如下,一般我们使用满足响应式编程的Gateway实现。

下面我们使用gateway进行网关搭建,具体步骤如下:
第一,创建一个module作为网关,在pom.xml文件中引入nacos服务发现依赖贺网关依赖。需要编写该服务的启动类,则网关的搭建就完成了。

第二步,需要编写路由以及配置nacos地址,需要定义路由的id,路由的目标地址以及路由的断言。其中lb为loadbalance表示负载均衡。

 

我们看一下上面通过网关进行路由的过程,首先是用户通过浏览器向网关发起请求,然后通过网关的配置进行路由规则判断,从nacos注册中心拉取相应的服务,然后根据负载均衡原理,选取相应的服务处理请求。

 

3.2、路由断言工厂

其实路由的配置主要包括以下四个部分,路由的唯一标识id,路由的目的地,路由断言,路由过滤器,这里主要学习路由断言部分的路由断言工厂。

 断言工厂就是处理断言的规则,具体的断言工厂有很多种。

我们看一下常见的断言工厂,一共11个断言规则,根据相应的断言规则进行配置即可。

 

3.3、路由过滤器的配置

路由过滤器是网关中提供的一种过滤器,主要用来都对请求的信息和微服务响应的信息进行处理。

一般通过名称就可以判断出过滤器的名称,根据自己的需求设置过滤器就可以了。

直接在网关中的.yaml文件中进行路由配置即可,我配置了一个 默认的过滤器,对于所有路由都进行过滤,如下:主要看最后一行的配置就可以 ,最后一行是
 

server:
  port: 10010
logging:
  #level:
   # cn.itcast: debug
  #pattern:
   # dateformat: MM-dd HH:mm:ss:SSS
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes:
        - id: user-service # 路由标示,必须唯一
          uri: lb://userservice # 路由的目标地址
          predicates: # 路由断言,判断请求是否符合规则
            - Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**
      default-filters:
        - AddRequestHeader=Truth,Itcast is freaking awesome!

3.4、全局过滤器

我们先了解一下什么是全局过滤器,全局过滤器和网关的过滤作用一样,都是对请求和响应进行处理的,但是全局过滤器可以自己写代码设置处理逻辑,即处理逻辑是不固定的。

 下面编写一个全局过滤器实现相应的接口,在重写的方法中定义处理逻辑。

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

// @Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String, String> params = request.getQueryParams();
        // 2.获取参数中的 authorization 参数
        String auth = params.getFirst("authorization");
        // 3.判断参数值是否等于 admin
        if ("admin".equals(auth)) {
            // 4.是,放行
            return chain.filter(exchange);
        }
        // 5.否,拦截
        // 5.1.设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        // 5.2.拦截请求
        return exchange.getResponse().setComplete();
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

最后在浏览器测试,必须要加上设置的参数才能通过网关访问服务。

3.5、过滤器链的执行顺序

我们之前学过三种过滤器,那么这三种过滤器的执行 顺序如何呢,怎么进行排序呢? 

过滤器的执行顺序的逻辑如下,对于order值来说,越小执行顺序越靠前,当order值一样时,会按照默认过滤器->路由过滤器->全局过滤器的顺序执行。

3.6、网关的cors跨域配置

我们先回顾一下跨域问题,跨域问题就是浏览器禁止发起者与服务端产生ajax请求,请求被浏览器拦截的问题,一般来说使用CORS跨域解决跨域问题。

网关处理跨域问题也是CORS方案,并且只需要简单的如下配置即可实现。一般要配置的参数如下所示。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/38082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis持久化策略AOF、RDB详解及源码分析

写在前面 以下内容是基于Redis 6.2.6 版本整理总结 一、Redis为什么要持久化 Redis 是一个内存数据库&#xff0c;就是将数据库中的内容保存在内存中&#xff0c;这与传统的MySQL&#xff0c;Oracle等关系型数据库直接将内容保存到硬盘中相比&#xff0c;内存数据库的读写效…

数论简单问题

数论基本问题约数个数问题约数之和问题1-n中所有1-n因子的数量n!分解后某个质因子的个数欧拉函数公式法求欧拉函数线性筛求欧拉函数欧拉函数在线性筛中的三种情况&#xff1a;欧拉定理逆元费马定理求逆元快速幂求逆元扩展欧几里得算法扩展欧几里得算法证明扩展欧几里得的应用中…

消息队列 - RabbitMQ

1. 名词解释 Producer&#xff1a;生产者 Broker&#xff1a;接收和分发消息的应用 Connection&#xff1a;生产者和消费者与 Broker 之间的 TCP 连接 Channel&#xff1a;信道&#xff1b;在 Connection 内部建立的逻辑连接&#xff0c;每个 Channel 之间是相互隔离的。相…

第十四届模拟赛第二期试题【Java解析】

目录 ✏️写在前面 ✨历史回顾 &#x1f388;第一题&#xff08;二进制API&#xff09; 代码&#xff1a; 思路&#xff1a; &#x1f388;第二题&#xff08;闰年问题/时间API&#xff09; 代码1&#xff1a; 思路1&#xff1a; 代码2&#xff1a; 思路2&#xff1a…

【计算机网络】数据链路层:使用点对点信道的数据链路层

数据链路层信道类型&#xff1a; &#xff08;1&#xff09;点对点信道&#xff1a;使用一对一的点对点通信方式 &#xff08;2&#xff09;广播信道&#xff1a;使用一对多的广播通信方式。 必须使用专用的共享信道协议来协调主机数据发送。 链路:从一个节点到相邻节点的一…

TCP的三次握手和四次挥手

目录:smile_cat:基础知识回顾1、运输层概述2、端口号3、复用与分用:smiley_cat:重点知识来袭1、TCP和UDP2、三次握手3、四次挥手4、TCP报文段首部格式文章参考来源&#xff1a; TCP的三次握手和挥手–飞天小牛肉20-1-tcp连接——初始化序列号(ISN)_网络安全-CSDN博客_初始序列…

掌握分布式环境缓存更新策略,提高缓存与数据库数据一致性

概述 随着时代的发展&#xff0c;服务系统架构也已经由最初的单体架构转变为分布式、微服务架构模式。 从数据体量上来看&#xff0c;各系统存储的数据量越来越大&#xff0c;数据的查询性能越来越低。 此时&#xff0c;就需要我们不断的进行优化&#xff0c;最常用的就是引入…

NVIDIA RTX3090上安装tensorflow-gpu 1.12.0

目录 项目场景&#xff1a; 问题描述1 CUDA版本不匹配&#xff0c;需要重新安装 解决方案1&#xff1a; 额外安装其他版本的CUDA&#xff0c;并实现版本自由切换。 问题描述2&#xff1a; 1. cuDNN包解压后的cudnn.h文件无法复制到目标文件夹中 2. 如何查看是否会到最初…

计算机系统基础期末复习

C语言代码如下&#xff1a; void fun(int n){ int x n*12;int y n/32; }请将其中计算的部分优化为位运算、移位运算和加法运算的结合。 x n8n4 (n<<3)(n<<2) x (n(n>>31) & 0x1F)>>5 设32位的位串为x(x类型为unsigned int)&#xff0c;现要…

python dingding --- 钉钉机器人API

dingding — 钉钉机器人 github 源码地址&#xff1a;https://github.com/zly717216/dingding 一、模块介绍 版本号 dingding: V1.0.0 功能 当前版本支持群机器人相关API调用&#xff0c;包括发送文本消息、文本链接、markdown、整体跳转 ActionCard、独立跳转 ActionCar…

【MindSpore】DCGAN生成漫画头像-----利用华为云modelarts云终端实现

前言 本人对于 mindspore 一点也不熟悉 但是 对于 学习新事物的心情和动力 一直都很澎湃 本次参加 mindSpore 的 DCGAN生成漫画头像 社区活动&#xff0c;希望能够增长见识 关注 证明图 使用工具 我直接使用的 mindSpore 提供的在线云环境 的终端来 体验 这一次的任务训练 …

【Autopsy数字取证篇】Autopsy数字取证软件的下载安装与优化配置

【Autopsy数字取证篇】Autopsy数字取证软件的下载安装与优化配置 Autopsy是一款免费开源的优秀数字取证&#xff08;Digital Forensics&#xff09;软件&#xff0c;提供与其他数字取证工具相同的核心功能&#xff0c;并提供其他商业工具不提供的其他基本功能&#xff0c;例如…

video元素与audio元素详解

1.video/audio属性 video元素和audio元素是HTML5中针对视频新增的两个标签&#xff0c;通过对这两个标签进行设置&#xff0c;可以控制页面的 上的音视频的播放。 1.src 属性 设置音/视频文件的URL地址。相关使用代码如下: <video src"movie.mp4"></vide…

【面试】揭秘面试背后的那点真实

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录前言/背景面试流程资料总结/刷题指南个人经验总结寄语&#x1f338;I could be bounded in a nutshell and count myself a king of infinite space. 特别鸣谢&#xff1a;木芯工作室 、Ivan from Russia 金…

【Windows编程】windows窗口创建过程详解

文章目录前言1 应用程序的分类2 应用程序分类的对比3 编译工具4 windows库文件和头文件5 WinMain函数和MessageBox函数初始6 窗口类7 窗口类的分类8 注册窗口类函数9 注册窗口类的结构体10 注册全局和局部窗口类11 创建窗口的函数12 创建一个windows的过程步骤13 创建一个子窗口…

C语言文件操作——打开 关闭 顺序读写 随机读写

1.文件的打开和关闭 1.1 文件指针 在打开一个文件的时候&#xff0c;会创建一个文件信息区&#xff0c;而文件指针指向的内容就是文件信息区。 文件信息区中存储的到底是什么内容的&#xff0c;我们可以在VS2013中查看一下文件信息区的内容(不同编译器下有所差异)。 struct …

shell脚本的条件判断2:文件属性的判断与比较

一 文件属性的判断与比较 Shell支持大量对文件属性的判断&#xff0c;常用的文件属性操作符很多&#xff0c;如下表所示。更多文件属性操作符可以参考命令帮助手册&#xff08;man test&#xff09;。 二 实例 实例&#xff1a;文件和目录判断 可以创建新的文件&#xff0c;…

属性值最大长度为30个字符(15个汉字)

上图是一位做成人用品店主反馈的问题&#xff0c;查看发过来的错误列表后&#xff0c;发现这份错误列表主要是有两个问题&#xff1a;一、属性值最大长度为30个字符(15个汉字)&#xff1b;二、手机端宝贝描述中每张图片的宽要在480到1500之间&#xff0c;最大高度为2500, 以下图…

深度学习之路=====11=====>>ShuffleNet(tensorflow2)

简介 来源&#xff1a;CVPR2017 作者&#xff1a;张祥雨&#xff0c;西安交通大学本硕博&#xff0c;原微软亚洲研究院研究员 特点 逐点分组卷积&#xff08;pointwise group conv)&#xff1a;使用了kernel_size1的分组卷积&#xff0c;大大降低模型参数量和计算量深度卷积…

阅读书《电子电路原理》截取的一些最核心的思想,找了个课程上海交通大学 郑益慧主讲做辅助(保证基本的理解是对的)。电路要以基本特性为基础从设计角度理解

一、戴维南 和 诺顿 物理量 过程戴维南等效诺顿等效步骤 l将负载电阻开路将负载电阻短路步骤 2计算或测量开路电 压&#xff0c; 即戴维南电压计算或测量短路电流&#xff0c;即诺顿电流步骤 3将电压源短路&#xff0c;电流源开路将电压源短路&#xff0c;电流源开路&#xff…