微服务架构实战:Eureka服务注册发现与Ribbon负载均衡详解

news2025/5/25 6:28:18

微服务架构实战:Eureka服务注册发现与Ribbon负载均衡详解

  • 一 . 服务调用出现的问题
  • 二 . EureKa 的作用
  • 三 . 服务注册
    • 3.1 搭建 EureKaServer
      • ① 创建项目 , 引入 spring-cloud-starter-netflix-eureka-server 的依赖
      • ② 编写启动类 , 添加 @EnableEurekaServer 注解
      • ③ 添加 application.yml 文件 , 编写相关配置
    • 3.2 服务注册
      • ① 在 EureKa 的客户端项目中引入 spring-cloud-starter-netflix-eureka-client 的依赖
      • ② 在各自的 application.yml 中 , 编写相关配置
      • ③ 给各自的微服务起一个名称
      • ④ 启动多个 EureKa 客户端
  • 四 . 服务发现
  • 五 . Ribbon 负载均衡
    • 5.1 负载均衡流程
    • 5.2 负载均衡原理
    • 5.3 负载均衡策略
      • ① 代码方式
      • ② 配置文件方式
    • 5.4 懒加载
    • 5.5 小结

在微服务架构中,服务间的稳定调用是核心挑战之一。传统的RestTemplate直接调用存在单点故障、集群路由选择困难、服务健康状态难以感知等问题。如何实现服务的动态发现?如何优雅地管理多实例负载均衡?本文将深入剖析Spring Cloud中的Eureka服务注册中心与Ribbon负载均衡组件,通过实战演示如何解决服务治理的核心痛点,构建高可用的微服务通信体系。
在这里插入图片描述

本专栏的内容均来自于 B 站 UP 主黑马程序员的教学视频,感谢你们提供了优质的学习资料,让编程不再难懂。
专栏地址 : https://blog.csdn.net/m0_53117341/category_12835102.html

一 . 服务调用出现的问题

我们当前使用的是 RestTemplate 来让 order-service 调用 user-service , 那这里其实是存在问题的

我们目前的两个服务都是单节点的 , 如果 user-service 挂掉了 , order-service 就会调用失败 , 也会影响到 order-service .

那如果后续搭建 user-service 集群的话 , 我们到底访问哪一台 user-service 机器呢 ?

也就是服务消费者该如何获取服务提供者的地址信息 ?

那如果有多个服务提供者 , 消费者该如何选择呢 ? 是通过负载均衡策略还是其他策略呢 ?

消费者如何得知服务提供者的健康状态呢 ?

那综合这几点考虑 , 我们应该把节点信息都放到一个统一的位置进行管理 , 那这个统一的位置就是 EureKa .

二 . EureKa 的作用

那整体来看 , EureKa 的作用就是服务注册、服务发现、状态监控这三点

那我们重新来看上面的三个问题

服务消费者该如何获取服务提供者的地址信息 ?

  1. 服务的提供者在启动的时候 , 就需要向 EureKa 注册自己的信息
  2. EureKa 保存每个服务的信息
  3. 消费者根据服务名称向 EureKa 拉取提供者的信息

前提 : 必须是已经上传到 EureKa 的服务 , 才能拉取别人的信息

如果有多个服务提供者 , 消费者该如何选择呢 ?

服务消费者利用负载均衡算法 , 从服务列表中挑选一个

消费者如何得知服务提供者的健康状态呢 ?

  1. 服务提供者会每隔 30s 就向 EureKaServer 发送心跳请求 , 报告健康状态
  2. EureKa 会更新服务列表信息 , 心跳不正常的就会被剔除掉
  3. 消费者需要主动拉取最新的消息

小结 :

在 EureKa 架构中 , 微服务角色有两类 :

  1. EureKaServer : 服务端 , 注册中心
    1. 记录服务信息
    2. 进行心跳监控
  2. EureKaClient : 客户端
    1. Provider : 服务提供者 (user-service)
      1. 启动的时候主动注册自己的信息到 EureKaServer
      2. 每隔 30s 向 EureKaServer 发送心跳
    2. consumer : 服务消费者 (order-service)
      1. 启动的时候主动注册自己的信息到 EureKaServer
      2. 每隔 30s 向 EureKaServer 发送心跳
      3. 根据服务名称从 EureKaServer 拉取服务列表
      4. 基于拉取下来的服务列表做负载均衡策略 , 选择一个微服务进行远程调用

三 . 服务注册

基本流程如下 :

  1. 搭建 EureKaServer
  2. 将 user-service 和 order-service 都注册到 EureKa 中
  3. 在 order-service 中完成服务拉取 , 然后通过负载均衡挑选一个服务 , 来去实现远程调用

那我们分别来看

3.1 搭建 EureKaServer

① 创建项目 , 引入 spring-cloud-starter-netflix-eureka-server 的依赖

首先 , 我们创建一个新的模块

那接下来就可以在该模块的 pom.xml 中引入依赖了

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

那这里是不需要指定版本的 , 因为我们在父模块已经指定过了

那这个依赖 , 下载起来还是比较耗时的 , 稍加等待

② 编写启动类 , 添加 @EnableEurekaServer 注解

这个功能需要安装插件 :

[番外 1 : JBLSpringBootAppGen 的安装](https://www.yuque.com/jialebihaitao/study/wduur42qulhwgd48?singleDoc# 《番外 1 : JBLSpringBootAppGen 的安装》)

然后在启动类上添加 @EnableEurekaServer 注解

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
// 开启 EureKa 注册中心功能
@EnableEurekaServer
public class EurakeApp {
    public static void main(String[] args) {
        SpringApplication.run(EurakeApp.class, args);
    }
}

③ 添加 application.yml 文件 , 编写相关配置

server:
  port: 10086
spring:
  application:
    name: eurekaserver # 当前微服务的名称
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka # Eureka 向外暴漏的地址
    register-with-eureka: false # false 表示不向注册中心注册自己
    fetch-registry: false # false 表示自己就是注册中心, 我的职责就是维护服务实例, 并不需要去检索服务

那接下来 , 我们可以启动一下 , 看一下能否正常运行

访问 http://127.0.0.1:10086/

我们重点关注 Instances currently registered with Eureka 这个位置 , 他代表当前已经注册到 Eureka 注册中心的服务 , 那目前还没有任何实例注册到注册中心中

3.2 服务注册

将服务注册到 EureKaServer 的步骤如下 :

  1. 在 EureKa 的客户端项目中引入 spring-cloud-starter-netflix-eureka-client 的依赖
  2. 在各自的 application.yml 中 , 编写相关配置

① 在 EureKa 的客户端项目中引入 spring-cloud-starter-netflix-eureka-client 的依赖

将下面的依赖粘贴到 user-service 和 order-service 服务中的 pom.xml 中

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

② 在各自的 application.yml 中 , 编写相关配置

将这段配置粘贴到 user-service 和 order-service 的 application.yml 中

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka # Eureka 向外暴漏的地址

③ 给各自的微服务起一个名称

那我们需要给 user-service 和 order-service 的微服务起一个名称 , 不然到时候观察 EureKa 注册中心的时候 , 我们并不知道哪个是 user-service , 哪个是 order-service

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: userservice
mybatis:
  type-aliases-package: com.example.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    com.example: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka # Eureka 向外暴漏的地址

那这时候 , 我们重启 user-service 和 order-service , 就会自动将自身信息注册到 EureKa 中了

我们回到 EureKa 注册中心看一下 , 此时两个服务已经成功注册

那也有可能在页面 , 会有一个大大的红色警报

他其实并不是报错 , 只是 Eureka 认为 , 当你的实例只有一个节点的时候 , 这个服务就很危险了 .

也就是你对应的服务只启动了一份 .

④ 启动多个 EureKa 客户端

-Dserver.port=8082

那接下来 , 我们启动新的 user-service 服务

然后回到 EureKa 控制中心看一下

四 . 服务发现

虽然我们已经把 user-service 服务和 order-service 服务注册到 EureKa 中了 , 但是我们在访问这两个接口的时候 , 还需要访问固定的 IP

那这是因为我们在代码中已经将端口号写死了

那这样的话 , 即使 user-service 服务搭建了集群 , 我们也只能访问到固定的 8081 端口的服务 , 所以我们需要更换一下写法

package com.example.order.service;

import com.example.order.mapper.OrderMapper;
import com.example.order.pojo.Order;
import com.example.order.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RestTemplate restTemplate;

    public Order queryOrderById(Long orderId) {
        // 1. 查询订单
        Order order = orderMapper.findById(orderId);

        // 2. 查询用户 ID
        Long userId = order.getUserId();

        // 3. 拼接 URL
        // String url = "http://127.0.0.1:8081/user/" + userId;
        // 解析 URL 地址获取被调用的微服务的名称, 然后去注册中心根据名称获取服务列表, 最后负载均衡进行访问
        String url = "http://userservice/user/" + userId;

        // 4. 调用 RestTemplate 发起请求获取用户信息
        // 第一个参数: 要请求的 URL 地址
        // 第二个参数: 获取到的数据要转换成哪种对象
        User user = restTemplate.getForObject(url, User.class);

        // 5. 将获取到的用户信息添加到 user 字段中
        order.setUser(user);

        // 6. 返回
        return order;
    }
}

要注意这个位置需要跟要调用的服务的 application.yml 进行对齐

那为了演示负载均衡的效果 , 我们还需要修改一些内容

我们可以将配置文件中的端口号读取出来 , 然后设置到用户名部分 , 这样我们就能通过页面来看到端口号的变化

package com.example.user.service;

import com.example.user.mapper.UserMapper;
import com.example.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

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

    public User queryById(Long id) {
        // 1. 先获取到当前用户的信息
        User user = userMapper.findById(id);

        // 2. 在该用户的名称部分添加端口号信息
        user.setUsername(user.getUsername() + ",当前端口号为:" + port);
        return user;
    }
}

重启 order-service 与 user-service 服务

那这次我们再访问 order-service 服务 , 发现报错了

这是因为我们还需要在 order-service 项目的启动类 OrderApplication 中的 RestTemplate 添加负载均衡注解

package com.example.order;

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.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@MapperScan("com.example.order.mapper")
@SpringBootApplication
public class OrderApplication {

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

    @Bean
    @LoadBalanced // 开启负载均衡注解
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

这次我们重新运行

我们注意端口号的变化 , 这样就达到了负载均衡的效果 .

小结 :

  1. 搭建 EurekaServer
    1. 引入 eureka-server 依赖
    2. 在当前服务启动类中添加 @EnableEurekaServer 注解
    3. 在 application.yml 中配置 eureka 地址
  2. 服务注册
    1. 引入 eureka-client 依赖
    2. 在 application.yml 中配置 eureka 地址
  3. 服务发现
    1. 引入 eureka-client 依赖
    2. 在 application.yml 中配置 eureka 地址
    3. 给 RestTemplate 添加 @LoadBalanced 注解
    4. 用服务提供者的服务名称来去远程调用

五 . Ribbon 负载均衡

5.1 负载均衡流程

5.2 负载均衡原理

首先 , 我们全局搜索 LoadBalancerInterceptor 类

然后在下面的 intercept 方法打个断点

之后让 order-service 以 Debug 的方式运行

此时刷新页面 , 就会被 intercept 方法拦截

然后我们向下执行 , 发现成功获取到了我们指定的 URL

然后再往下执行

那接下来就是 execute 方法了 , 他的目的肯定是从注册中心获取服务列表 , 我们可以继续深入源码

然后我们要看这个接口具体的实现

然后在这个方法上添加一个端点 , 看能否执行到这里

我们发现 , 确实跳转过来了

那这个方法是一个重载的方法 , 他还需要继续向下调用 , 那我们就在他的重载方法的位置再打一个断点

将刚刚添加的这个 execute 断点取消

继续向下执行 , 我们看一下 ILoadBalancer 是什么内容

那这个 up 好像有点眼熟 , 这个 up 就代表可用节点的意思

那上面的 allServerList 指的就是所有节点

假如我们总共有三个节点 , 但是有一个节点挂了 . 那 allServerList 就是 3 , upServerList 就是 2

那下面的 getServer 方法就是按照某种策略来去获取某个节点

那我们还可以继续深入 getServer 方法

然后我们就找到了负责均衡的最顶层接口

5.3 负载均衡策略

那分析了源码之后 , 我们就可以来看一下整个负载均衡的框图

其中 , IRule 是最顶层的接口 , 这里面我们还比较眼熟的是 ZoneAvoidanceRule 这个规则 , 他是负载均衡策略默认的规则 .

那其他我们不认识的 , 其实也是负载均衡的策略 , 我们可以大概看一下

内置负载均衡规则类规则描述
RoundRobinRule简单轮询服务列表来选择服务器
AvailabilityFilteringRule对以下两种服务器进行忽略 :
(1)在默认情况下 , 这台服务器如果 3 次连接失败 , 那这台服务器就会被设置为“短路”状态 . 短路状态将持续 30 秒 , 如果 30s 之后再次连接失败 , 短路的持续时间就会几何级地增加 (30s -> 60s -> 90s …)
(2)如果一个服务器的并发连接数过高 , 就会忽略该节点 .
WeightedResponseTimeRule服务器响应时间越长 , 这个服务器的权重就越小 , 被选中的可能性就越低
ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择 , 如果当前节点在北京 , 那也会选择北京的节点进行连接而不是选择上海的节点 .
BestAvailableRule忽略那些短路的服务器 , 并选择并发数较低的服务器
RandomRule随机选择一个可用的服务器
RetryRule重试机制

那通过定义 IRule 可以实现修改负载均衡的规则 , 有两种方式

① 代码方式

在 order-service 中的启动类下 , 定义一个新的 IRule 覆盖掉本来的配置 (秉持谁用谁配置的原则 , order-service 需要调用 user-service , 就需要 order-service 进行配置)

package com.example.order;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
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.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@MapperScan("com.example.order.mapper")
@SpringBootApplication
public class OrderApplication {

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

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

    // 随机轮训
    @Bean
    public IRule randomRule() {
        return new RandomRule();
    }
}

接下来 , 我们重启 order-service , 看一下是否还按照轮训的方式访问

我们注意端口号的变化

并不是完全按照 81 -> 82 -> 81 这样轮训的方式获取的了 .

② 配置文件方式

在 order-service 的 application.yml 文件中 , 添加新的配置也可以去修改规则

userservice: # 给某个微服务配置负载均衡规则, 这里是 userservice 服务
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

那我们可以重新运行一下

将刚才代码的方式注释掉

这次访问的都是 8082 端口了

5.4 懒加载

那我们的 order-service 需要访问 user-service 的节点 , 那 order-service 就需要向 EureKa 的注册中心获取服务列表 , 那这个服务列表是什么时候获取的呢 ?

是调用的时候采取获取 , 还是服务刚启动的时候就获取服务列表呢 ?

那 Ribbon 默认是懒加载 , 只有第一次访问的时候才会去创建 LoadBalanceClient . 我们可以设置成饥饿加载 , 在项目启动的时候就创建 LoadBalanceClient , 这样就降低了第一次访问的耗时时长 .

我们可以通过配置文件开启饥饿加载 .

ribbon:
  eager-load:
    enabled: true # 开启饥饿加载
    clients: userservice # 指定对 userservice 这个微服务饥渴加载

如果对多个服务开启饥饿加载的话 , 可以使用列表的形式

ribbon:
  eager-load:
    enabled: true # 开启饥饿加载
    clients:
      - userservice # 指定对 userservice 这个微服务饥渴加载

那我们重新启动一下 , 就能够在控制台发现一些蛛丝马迹了

5.5 小结

  1. Ribbon 负载均衡规则
    1. 规则接口是 IRule
    2. 默认实现是 ZoneAvoidanceRule , 根据 zone (地区) 选择服务列表 , 然后轮询
  2. 负载均衡自定义方式
    1. 代码方式 : 配置灵活 , 但修改时需要重新打包发布
    2. 配置方式 : 直观、方便 , 无需重新打包发布 , 在配置中心统一配置即可 , 但是无法做全局配置
  3. 饥饿加载
    1. 开启饥饿加载 : 设置 ribbon.eager-load.enabled 为 true
    2. 指定饥饿加载的微服务名称 : 将需要饥饿加载的微服务添加到 ribbon.eager-load.clients 中

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

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

相关文章

采用多维计算策略(分子动力学模拟+机器学习),显著提升 α-半乳糖苷酶热稳定性

字数 978&#xff0c;阅读大约需 5 分钟 在工业应用领域&#xff0c;α-半乳糖苷酶在食品加工、动物营养及医疗等方面发挥着重要作用。然而&#xff0c;微生物来源的该酶往往存在热稳定性不足的问题&#xff0c;限制了其在工业场景中的高效应用。近日&#xff0c;来自江南大学的…

【java】小练习--零钱通

文章目录 前言一、项目开发流程说明二、功能实现2.1 菜单2.2 零钱通明细2.3 零钱通收益2.4 零钱通消费2.5 零钱通退出确认2.6 零钱通金额校验2.7 完整代码 三、零钱通OOP版 前言 本文是我跟着B站韩顺平老师的 Java 教程学习时动手实现“零钱通”项目的学习笔记&#xff0c;主要…

Docker-mongodb

拉取 MongoDB 镜像: docker pull mongo 创建容器并设置用户&#xff1a; 要挂载本地数据目录&#xff0c;请替换此路径: /Users/Allen/Env/AllenDocker/mongodb/data/db docker run -d --name local-mongodb \-e MONGO_INITDB_ROOT_USERNAMEadmin \-e MONGO_INITDB_ROOT_PA…

Gartner《Optimize GenAI Strategy for 4 Key ConsumerMindsets》学习心得

一、引言 在当今数字化营销浪潮中,生成式人工智能(GenAI)正以前所未有的速度重塑着市场格局。GenAI 既是一场充满机遇的变革,也是一场潜在风险的挑战。一方面,绝大多数 B2C 营销领导者对 GenAI 赋能营销抱有极高期待,他们看到了 GenAI 在提升时间与成本效率方面的巨大潜…

达梦数据库-学习-22-库级物理备份恢复(超详细版)

目录 一、环境信息 二、说点什么 三、概念 1、备份恢复 2、重做日志 3、归档日志 4、LSN 5、检查点 四、语法 1、BACKUP DATABASE 2、DMRMAN RESTORE DATABASE 3、DMRMAN RECOVER DATABASE 4、DMRMAN UPDATE DB_MAGIC 五、实验 1、开归档 &#xff08;1&#xf…

python网络爬虫的基本使用

各位帅哥美女点点关注&#xff0c;有关注才有动力啊 网络爬虫 引言 我们平时都说Python爬虫&#xff0c;其实这里可能有个误解&#xff0c;爬虫并不是Python独有的&#xff0c;可以做爬虫的语言有很多例如&#xff1a;PHP、JAVA、C#、C、Python。 为什么Python的爬虫技术会…

AI Agent开发第74课-解构AI伪需求的魔幻现实主义

开篇 🚀在之前的系列中我们狂炫了AI Agent的各种高端操作(向量数据库联动、多模态感知、动态工作流等…),仿佛每个程序员都能用LLM魔法点石成金✨。 但今天咱们要泼一盆透心凉的冷水——当企业把AI当成万能胶水强行粘合所有需求时,连电风扇都能被玩出量子纠缠的魔幻现实…

【卫星通信】通信卫星链路预算计算及其在3GPP NTN中的应用

引言 卫星通信是现代信息传播的重要手段&#xff0c;广泛应用于电信、广播、气象监测、导航等领域。卫星链路预算计算是设计和优化卫星通信系统的重要步骤&#xff0c;它帮助工程师评估信号在传输过程中的衰减和增益&#xff0c;从而确保系统在预定条件下可靠地工作。 1. 链路…

c++命名空间的作用及命名改编

c命名空间的作用及命名改编 命名空间 namespace的作用&#xff1a; std::命名空间&#xff0c;命名空间&#xff08;namespace&#xff09;是 C 中用于解决标识符命名冲突问题的机制。在大型程序开发中&#xff0c;不同模块可能会使用相同名称的变量、函数或类等标识符&…

echarts实现项目进度甘特图

描述 echarts并无甘特图配置项&#xff0c;我们可以使用柱状图模拟&#xff0c;具体配置项如下&#xff0c;可以在echarts直接运行 var option {backgroundColor: "#fff",legend: {data: ["计划时间","实际时间"],align: "right",…

2025深圳国际无人机展深度解析:看点、厂商与创新亮点

2025深圳国际无人机展深度解析&#xff1a;看点、厂商与创新亮点 1.背景2.核心看点&#xff1a;技术突破与场景创新2.1 eVTOL&#xff08;飞行汽车&#xff09;的规模化展示2.2 智能无人机与无人值守平台2.3 新材料与核心零部件革新2.4 动态演示与赛事活动 3.头部无人机厂商4.核…

人形机器人通过观看视频学习人类动作的技术可行性与前景展望

摘要 本文深入探讨人形机器人通过观看视频学习人类动作这一技术路线的正确性与深远潜力。首先阐述该技术路线在模仿人类学习过程方面的优势&#xff0c;包括对人类动作、表情、发音及情感模仿的可行性与实现路径。接着从技术原理、大数据训练基础、与人类学习速度对比等角度论证…

第三十四天打卡

DAY 34 GPU训练及类的call方法 知识点回归&#xff1a; CPU性能的查看&#xff1a;看架构代际、核心数、线程数 GPU性能的查看&#xff1a;看显存、看级别、看架构代际 GPU训练的方法&#xff1a;数据和模型移动到GPU device上 类的call方法&#xff1a;为什么定义前向传播时可…

配置tomcat时,无法部署工件该怎么办?

当我们第一次在IDEA中创建Java项目时&#xff0c;配置tomcat可能会出现无法部署工件的情况&#xff0c;如图&#xff1a; 而正常情况应该是&#xff1a; 那么该如何解决呢&#xff1f; 步骤一 点开右上角该图标&#xff0c;会弹出如图页面 步骤二 步骤三 步骤四

.NET外挂系列:8. harmony 的IL编织 Transpiler

一&#xff1a;背景 1. 讲故事 前面文章所介绍的一些注入技术都是以方法为原子单位&#xff0c;但在一些罕见的场合中&#xff0c;这种方法粒度又太大了&#xff0c;能不能以语句为单位&#xff0c;那这个就是我们这篇介绍的 Transpiler&#xff0c;它可以修改方法的 IL 代码…

基于netty实现视频流式传输和多线程传输

文章目录 业务描述业务难点流式传输客户端(以tcp为例)服务端测试类测试步骤多线程传输客户端服务端测试类测试步骤多线程流式传输总结业务描述 多台终端设备持续给数据服务器(外)发送视频数据,数据服务器(外)通过HTTP协议将数据经过某安全平台转到数据服务器(内),数据…

全面指南:使用Node.js和Python连接与操作MongoDB

在现代Web开发中&#xff0c;数据库是存储和管理数据的核心组件。MongoDB作为一款流行的NoSQL数据库&#xff0c;以其灵活的数据模型、高性能和易扩展性广受开发者欢迎。无论是使用Node.js还是Python&#xff0c;MongoDB都提供了强大的官方驱动和第三方库&#xff0c;使得数据库…

游戏引擎学习第308天:调试循环检测

回顾并为今天的内容做准备 我们正在进行游戏开发中的精灵&#xff08;sprite&#xff09;排序工作&#xff0c;虽然目前的实现已经有了一些改进&#xff0c;情况也在逐步好转&#xff0c;我们已经实现了一个图结构的排序算法&#xff0c;用来处理精灵渲染顺序的问题。然而&…

WPF性能优化之延迟加载(解决页面卡顿问题)

文章目录 前言一. 基础知识回顾二. 问题分析三. 解决方案1. 新建一个名为DeferredContentHost的控件。2. 在DeferredContentHost控件中定义一个名为Content的object类型的依赖属性&#xff0c;用于承载要加载的子控件。3. 在DeferredContentHost控件中定义一个名为Skeleton的ob…

移植 FART 到 Android 10 实现自动化脱壳

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ FART 源码 FART 是 ART 环境下基于主动调用的自动化脱壳方案。 关于 FART 详细介绍参考&#xff1a; FART 自动化脱壳框架简介与脱壳点的选择 FART 主动调用…