news 2026/4/16 9:23:28

微服务(1)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微服务(1)

最近主包的考试有点多,六级,期末,所以最近有点偷懒
废话不多说,回归正题

服务注册和发现

首先我们需要先去知道为什么要进行服务注册和发现,因为我们在使用微服务的时候每个项目都是独立的对不对,那么我要是比如去购买东西的话,是不是我的用户信息需要去共享,这样的话我创建订单就能知道是谁购买的对不对?

nacos


这里改成自己的虚拟机的ip地址,然后需要去映射nacos

docker run-d \--name nacos \--env-file./nacos/custom.env \-p 8848:8848 \-p 9848:9848 \-p 9849:9849 \--restart=always \ nacos/nacos-server:v2.1.0-slim

这样就能映射到8848端口了
但是要是想要去使用的话,我们还需要再nacos当中去注册一下

<!--nacos 服务注册发现--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>

这样的话我们在启动的时候就能扫描到了

spring: application: name: item-service# 服务名称cloud: nacos: server-addr:自己虚拟机的ip地址:8848# nacos地址

这里需要配置一下nacos的地址

最后配置出来是这个样子的,这样就能被nacos扫描到,但是话又说回来了,我只有服务注册的话还是不够啊,我光注册有啥用,我最终肯定是需要去调用的对不对,那我去调用的话就需要使用服务发现了

<!--nacos 服务注册发现--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>

可以发现,这里Nacos的依赖于服务注册时一致,这个依赖中同时包含了服务注册和发现的功能。因为任何一个微服务都可以调用别人,也可以被别人调用,即可以是调用者,也可以是提供者。

openfeign

现在我们需要去使用远程服务的话就需要使用openfeign来进行调用方法,
首先还是需要去引入依赖

<!--openFeign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!--负载均衡器--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>

这里使用的openfeign和负载均衡的依赖

在配置完成依赖之后还需要在启动类上面加上@enablefeignclients的注解里面的value指的是需要扫描到的包,在后面我们会重新解释一下的
接下来就需要去编写client的客户端来进行调用

这里需要先去声明一下关于feignclient的客户端扫描的模块是哪个,后面的配置注解也是在后面会讲到的
在这里大家需要注意到的是,这里使用的是代理的方式来进行唤醒方法,然后去转发请求,但是这里面的路径我们需要写全,注意是写全,就是locakhost:后面的都需要写上去,不然会出现找不到的异常,写完这个时候我们打底的就完成了,剩下的就是去调用这个方法


这里就是去调用的方法
接下来就是去开启连接池

<!--OK http 的依赖--> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-okhttp</artifactId> </dependency>
feign: okhttp: enabled: true# 开启OKHttp功能

这里需要先去引入okhttp的依赖,然后再去配置文件里面去开启okhttp的功能
最后就是去配置日志
OpenFeign只会在FeignClient所在包的日志级别为DEBUG时,才会输出日志。而且其日志级别有4级:

  • NONE:不记录任何日志信息,这是默认值。
  • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
  • HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
  • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
    Feign默认的日志级别就是NONE,所以默认我们看不到请求日志。
    首先

    这里面需要去配置一下日志,这里我们将日志等级设置成全部记录,这里还需要回顾一下前面的知识,我们在配置日志的时候默认
    这里配置的是全局变量,然后要是需要配置的是局部变量的话,需要在client上面去配置

    这里指定的就是我需要关联的是哪个模块,然后给这个模块配置一下

网关

首先大家需要知道我为什么需要去设置网关,网关就相当于是大门,我们去创建订单的时候还是需要去获取用户的id但是这个用户的id我是从哪里获取这是个问题,所以我需要网关来去拦截,要是没有人的话我就需要拦截请求
什么是网关?
顾明思议,网关就是网络的关口。数据在网络间传输,从一个网络传输到另一网络时就需要经过网关来做数据的路由和转发以及数据安全的校验。
更通俗的来讲,网关就像是以前园区传达室的大爷。

  • 外面的人要想进入园区,必须经过大爷的认可,如果你是不怀好意的人,肯定被直接拦截。
  • 外面的人要传话或送信,要找大爷。大爷帮你带给目标人。
    现在,微服务网关就起到同样的作用。前端请求不能直接访问微服务,而是要请求网关:
  • 网关可以做安全控制,也就是登录身份校验,校验通过才放行
  • 通过认证后,网关再根据请求判断应该访问哪个微服务,将请求转发过去
    这里我们去创建网关的模块
<?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>hmall</artifactId> <groupId>com.heima</groupId> <version>1.0.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>hm-gateway</artifactId> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <!--common--> <dependency> <groupId>com.heima</groupId> <artifactId>hm-common</artifactId> <version>1.0.0</version> </dependency> <!--网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--nacos discovery--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--负载均衡--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

然后去配置路由

server: port: 8080 spring: application: name: gateway cloud: nacos: server-addr: 192.168.150.101:8848 gateway: routes:-id: item# 路由规则id,自定义,唯一uri: lb://item-service# 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表predicates:# 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务-Path=/items/**,/search/**# 这里是以请求路径作为判断规则-id: cart uri: lb://cart-service predicates:-Path=/carts/**-id: user uri: lb://user-service predicates:-Path=/users/**,/addresses/**-id: trade uri: lb://trade-service predicates:-Path=/orders/**-id: pay uri: lb://pay-service predicates:-Path=/pay-orders/**

这里给大家透个底,后面会优化的

网关过滤器

这里定义网关过滤器就是为了去拦截请求,不然的话要网关的意义是就没有了

最后是nettyroutingFilter来发送的请求,所以我的网关要是需要过滤的话是不是就需要正在这个请求之前,所以这里取使用的是globalfilter来进行拦截

前端不是发送的请求吗,携带的请求头里面是不是我的jwt来进行加密的吗,所以这里我就需要使用jwt来进行解析出来用户的id,要是存在用户的id的话,我是不是就直接放行,要是不存在的话,我就直接返回给前端一个404的错误
但是这时候我的最初目的是什么,我是不是需要将用户的id传递下去,所以这里我是不是需要将id传递,这时候就需要使用

ServerWebExchange build = exchange.mutate().request(a-> a.header("user-info",userInfo)).build();

我调用mutate将请求写到里面去,这样的话用户id就会随着网关进行转发转发到每个子模块当中,但是这时候又存在问题了,我现在是给子模块了,但是子模块怎么进行获取呢,所以下载乃我需要去定义一个全局的拦截器去将用户id拿出来,然后存起来,所以这时候就需要使用common下面的模块了

package com.hmall.common.interceptor;import com.ctc.wstx.util.StringUtil;import com.hmall.common.utils.UserContext;import org.springframework.util.StringUtils;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;publicclassuserInfoInterceptor implements org.springframework.web.servlet.HandlerInterceptor{@Override public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throws Exception{String header = request.getHeader("user-info");if(!StringUtils.isEmpty(header)){Long userId = Long.valueOf(header);UserContext.setUser(userId);}returntrue;}@Override public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex)throws Exception{UserContext.removeUser();}

然后去添加拦截器

package com.hmall.common.config;import com.hmall.common.interceptor.userInfoInterceptor;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Conditional;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration @ConditionalOnClass(name ="org.springframework.web.servlet.DispatcherServlet")publicclassmvcConfig implements org.springframework.web.servlet.config.annotation.WebMvcConfigurer{@Override public void addInterceptors(InterceptorRegistry registry){registry.addInterceptor(new userInfoInterceptor()).excludePathPatterns("/users/login").excludePathPatterns("/search/**").excludePathPatterns("/items/**");}}

这里面需要去除我在网关里面的,因为,我在网关里面引用了common模块,common模块是mvc的,但是我的网关是webflux的,没有mvc的配置,所以你要是不想让这个拦截器在网关里面生效的话需要将这个排除在外,同时因为是定义在common模块下面的,没法被其他的微服务扫描到,所以这里需要去自动装配

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.hmall.common.config.MyBatisConfig,\ com.hmall.common.config.MvcConfig

我去解析请求头,这样的话我的用户id就能在每个子模块之间传递对不对?
现在我们的网关到微服务之间的用户的信息是不是已经完成了,但是问题又来了,我要是用户信息在微服务之间进行传递的话,我还是会报错,所以我们需要将用户的信息随着我去向另一个微服务发送请求的时候是不是就需要一块传递过去,所以这时候我们就用到了openfeign的拦截器

@Bean public RequestInterceptor userInfoRequestInterceptor(){returnnew RequestInterceptor(){@Override public void apply(RequestTemplate template){//获取登录用户 Long userId = UserContext.getUser();if(userId == null){//如果为空则直接跳过return;}//如果不为空则放入请求头中,传递给下游微服务 template.header("user-info",userId.toString());}};}

这里直接去创建一个拦截器,然后将用户的信息存放到请求头里面传递给下游微服务,这样的话又会被common拦截到,这样又能存到usercontext里面去,这样的话我的用户信息就能在微服务之间进行传递了

配置管理

这里我们要是需要在线上微调的话,我的配置还是需要变动,但是我又不想直接在服务里面写死,这样我每次调试都需要重启服务,所以我们来介绍一下配置
首先来讲一下配置共享,

就是去里面创建

这里面的配置项不要写的太死了,这里面就相当于是我又卸载resources下面的,直接把这个当成yaml文件就行
然后就是去拉去配置

<!--nacos配置管理--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--读取bootstrap文件--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>

还是需要先去引入依赖,然后去创建bootstrap的yaml文件

接下来就是热部署

package com.hmall.cart.config;import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;@Data@Component @ConfigurationProperties(prefix ="hm.cart")publicclassCartProperties{private Integer maxAmount;}

其实和yaml一样定义在nacos里面就行

这样我们在去修改的时候就能直接修改nacos里面的文件实现热部署,就不需要重新启动服务了
最后就是动态路由

<!--统一配置管理--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--加载bootstrap--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>

首先还是先去引入依赖

spring: application: name: gateway cloud: nacos: server-addr: 192.168.150.101 config: file-extension: yaml shared-configs:-dataId: shared-log.yaml# 共享日志配置

然后去引入共享配置,最后就是去动态更新路由

package com.heima.gateway;import ch.qos.logback.classic.spi.EventArgUtil;import cn.hutool.core.collection.CollectionUtil;import cn.hutool.json.JSONUtil;import com.alibaba.cloud.nacos.NacosConfigManager;import com.alibaba.nacos.api.config.listener.Listener;import com.alibaba.nacos.api.exception.NacosException;import com.heima.config.AuthProperties;import com.heima.config.gatewayConfig;import lombok.Data;import lombok.RequiredArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.springframework.cloud.gateway.route.RouteDefinition;import org.springframework.cloud.gateway.route.RouteDefinitionWriter;import org.springframework.stereotype.Component;import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;import java.util.ArrayList;import java.util.List;import java.util.concurrent.Executor;@Slf4j @Data@Component @RequiredArgsConstructor publicclassDynamicRoureLoader{private final NacosConfigManager nacosConfigManager;private final RouteDefinitionWriter routeDefinitionWriter;private final gatewayConfig GatewayConfig;private final List <String> routeIds = new ArrayList<>();@PostConstruct public void init()throws NacosException{//获取nacos中的配置 String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(GatewayConfig.getDataId(),GatewayConfig.getGroup(),5000,new Listener(){@Override public Executor getExecutor(){returnnull;}@Override public void receiveConfigInfo(String configInfo){updateRouteDefinition(configInfo);}});updateRouteDefinition(configInfo);}private void updateRouteDefinition(String configInfo){log.debug("监听到路由配置变更,{}",configInfo);//1.删除之前存在过的路由信息 routeIds.forEach(id-> routeDefinitionWriter.delete(Mono.just(id)).subscribe());routeIds.clear();//2.添加新的路由信息 List<RouteDefinition> list = JSONUtil.toList(configInfo,RouteDefinition.class);//3.判断是不是需要添加新的路由信息if(CollectionUtil.isEmpty(list)){return;}for(RouteDefinition routeDefinition : list){routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();routeIds.add(routeDefinition.getId());}}}

这里我们需要注入的是nacosconfig和routeDefinitionWriter至于gateway那是我自己定义的一个,大家不需要在意,然后就是在类加载完毕的时候去初始化路由,增加监听器,更新路由配置,恒心路由配置的时候需要注意的是我们要去订阅,因为mono是懒惰式的,需要调用才能执行

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 16:01:29

python基于Django的图书馆借阅论坛系统_158xjlt3可视化

文章目录 具体实现截图主要技术与实现手段关于我本系统开发思路java类核心代码部分展示结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01; 具体实现截图 同行可拿货,招校园代理 python基于Django的图书馆借阅论坛系统_158xjlt3可视化…

作者头像 李华
网站建设 2026/4/15 11:49:49

RabbitMQ 如何保证消息不丢失和不重复消费?掌握这 4 个关键点

在开发中&#xff0c;我们经常用RabbitMQ来做系统之间的传话筒。比如用户下单后&#xff0c;通知库存系统减库存、通知物流系统准备发货。但问题来了&#xff1a;万一消息丢了怎么办&#xff1f;或者同一条消息被处理了两次怎么办&#xff1f;别担心&#xff01;只要做好以下几…

作者头像 李华
网站建设 2026/3/27 18:04:10

开题报告卡壳?虎贲等考 AI 打破 “框架焦虑”,学术起点一步到位

作为毕业论文的 “敲门砖”&#xff0c;开题报告不仅是对研究方向的核心梳理&#xff0c;更是导师评估研究可行性的关键依据。但多数学生在撰写时陷入 “三重困境”&#xff1a;框架逻辑混乱、研究意义表述模糊、技术路线不清晰&#xff0c;反复修改仍难达学术规范。虎贲等考 A…

作者头像 李华
网站建设 2026/4/15 5:08:04

OpenAI或从亚马逊获得超100亿美元融资

据The Information周二晚间报道&#xff0c;OpenAI Group PBC正在洽谈从亚马逊公司获得至少100亿美元的融资。这家零售和云计算巨头在投资大语言模型初创公司方面并不陌生。它是OpenAI最大竞争对手Anthropic PBC的最大支持者。几周前&#xff0c;亚马逊云科技&#xff08;AWS&a…

作者头像 李华
网站建设 2026/4/15 7:13:53

基于java的SpringBoot/SSM+Vue+uniapp的供应链管理系统的详细设计和实现(源码+lw+部署文档+讲解等)

文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言 &#x1f31e;博主介绍&#xff1a;✌全网粉丝15W,CSDN特邀作者、211毕业、高级全…

作者头像 李华
网站建设 2026/4/7 20:28:53

【每日算法】LeetCode 39. 组合总和

对前端开发者而言&#xff0c;学习算法绝非为了“炫技”。它是你从“页面构建者”迈向“复杂系统设计者”的关键阶梯。它将你的编码能力从“实现功能”提升到“设计优雅、高效解决方案”的层面。从现在开始&#xff0c;每天投入一小段时间&#xff0c;结合前端场景去理解和练习…

作者头像 李华