当前位置: 首页 > article >正文

设计模式——桥接设计模式(结构型)

摘要

桥接设计模式是一种结构型设计模式,用于将抽象与实现解耦,使二者可以独立变化。它通过将一个类拆分为“抽象”和“实现”两部分,并通过桥接关系组合,避免了类继承层次结构过于庞大。桥接模式包含抽象类、扩充抽象类、实现类接口和具体实现类等角色。在实现方式上,结合了策略模式,适用于风控系统通知等场景。桥接模式适合维度较多的场景,与其他设计模式有明显区别,实战示例展示了其在项目中的应用和优势。

1. 桥接设计模式定义

桥接模式将抽象与其实现解耦,使二者可以独立地变化。

  • 将一个类拆分为“抽象 Abstraction”和“实现 Implementor”两部分,通过桥接关系(Bridge)进行组合。
  • 它主要用于避免类继承层次结构过于庞大,适合维度较多的场景。

1.1. 🔧 关键角色

角色

说明

Abstraction

抽象类,定义高层接口,包含 Implementor 引用

RefinedAbstraction

扩展 Abstraction,具体业务操作

Implementor

实现接口,定义底层实现的规范

ConcreteImplementor

具体实现类,实现底层逻辑

2. 桥接设计模式结构

桥接模式包含如下角色:

  • Abstraction:抽象类
  • RefinedAbstraction:扩充抽象类
  • Implementor:实现类接口
  • ConcreteImplementor:具体实现类

2.1. 桥接设计模式类图

2.2. 桥接设计模式时序图

3. 桥接设计模式实现方式

下面是一个完整的 Spring Boot 项目示例,结合了策略模式 + 桥接模式,实现一个可扩展的风控告警通知系统:根据不同通知类型(策略)选择不同消息类型(桥接抽象)和不同发送方式(桥接实现)。

3.1. 示例需求背景:风控系统通知

  • 风控系统会发送不同级别的通知(普通、加急、特急) → 使用策略模式选择。
  • 每种通知可以通过不同的渠道发送(短信、邮件、钉钉) → 使用桥接模式解耦抽象与实现。

3.2. 📦 项目结构

src
└── main└── java└── com.example.notification├── strategy│   ├── MessageStrategy.java│   ├── NormalMessageStrategy.java│   ├── UrgentMessageStrategy.java│   └── MessageStrategyContext.java├── bridge│   ├── Message.java│   ├── MessageSender.java│   ├── SmsSender.java│   ├── EmailSender.java│   └── DingTalkSender.java├── controller│   └── NotifyController.java└── NotificationApplication.java

3.3. 🧩 桥接设计模式部分(抽象 + 实现)

3.3.1. ✅ MessageSender.java(实现接口)

package com.example.notification.bridge;public interface MessageSender {void send(String content, String toUser);
}

3.3.2. ✅ SmsSender.java / EmailSender.java / DingTalkSender.java(桥接实现)

@Component("smsSender")
public class SmsSender implements MessageSender {public void send(String content, String toUser) {System.out.println("【短信】发送给 " + toUser + ": " + content);}
}@Component("emailSender")
public class EmailSender implements MessageSender {public void send(String content, String toUser) {System.out.println("【邮件】发送给 " + toUser + ": " + content);}
}@Component("dingSender")
public class DingTalkSender implements MessageSender {public void send(String content, String toUser) {System.out.println("【钉钉】发送给 " + toUser + ": " + content);}
}

3.3.3. ✅ Message.java(抽象类)

public abstract class Message {protected final MessageSender sender;public Message(MessageSender sender) {this.sender = sender;}public abstract void send(String content, String toUser);
}

3.4. 🎯 策略模式部分(选择通知类型)

3.4.1. ✅ MessageStrategy.java(策略接口)

public interface MessageStrategy {void send(String content, String toUser);
}

3.4.2. ✅ NormalMessageStrategy.java / UrgentMessageStrategy.java(具体策略)

@Component("normal")
public class NormalMessageStrategy implements MessageStrategy {private final MessageSender sender;public NormalMessageStrategy(@Qualifier("smsSender") MessageSender sender) {this.sender = sender;}@Overridepublic void send(String content, String toUser) {new Message(sender) {@Overridepublic void send(String content, String toUser) {sender.send(content, toUser);}}.send(content, toUser);}
}@Component("urgent")
public class UrgentMessageStrategy implements MessageStrategy {private final MessageSender sender;public UrgentMessageStrategy(@Qualifier("emailSender") MessageSender sender) {this.sender = sender;}@Overridepublic void send(String content, String toUser) {new Message(sender) {@Overridepublic void send(String content, String toUser) {sender.send("[加急] " + content, toUser);}}.send(content, toUser);}
}

3.4.3. ✅ MessageStrategyContext.java(策略上下文)

@Component
public class MessageStrategyContext {private final Map<String, MessageStrategy> strategyMap;public MessageStrategyContext(Map<String, MessageStrategy> strategyMap) {this.strategyMap = strategyMap;}public MessageStrategy getStrategy(String type) {return strategyMap.getOrDefault(type, strategyMap.get("normal"));}
}

3.5. 🎮 控制器 NotifyController.java

@RestController
@RequestMapping("/notify")
public class NotifyController {private final MessageStrategyContext strategyContext;public NotifyController(MessageStrategyContext strategyContext) {this.strategyContext = strategyContext;}@GetMappingpublic String notify(@RequestParam String level,@RequestParam String toUser,@RequestParam String content) {MessageStrategy strategy = strategyContext.getStrategy(level);strategy.send(content, toUser);return "通知发送成功";}
}

3.6. 🚀 启动类 NotificationApplication.java

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

3.7. ✅ 示例调用

  • GET /notify?level=normal&toUser=风控专员&content=用户触发高风险交易
【短信】发送给 风控专员: 用户触发高风险交易
  • GET /notify?level=urgent&toUser=主管&content=系统异常
【邮件】发送给 主管: [加急] 系统异常

3.8. ✅ 策略+桥接+Spring总结

优势

策略模式

动态选择消息类型(策略)

桥接模式

解耦消息类型与发送渠道

Spring 容器

自动注入,支持配置和扩展

易扩展

添加新策略或新渠道无需改动原有逻辑

控制灵活

运行时根据参数选择实现逻辑

4. 桥接设计模式适合场景

4.1. ✅ 适合使用桥接模式的场景

场景

说明

抽象和实现需要独立扩展

比如:消息系统中消息类型(普通、加急) 和 发送方式(短信、邮件)都可能单独增加。桥接模式通过组合解决“类爆炸”问题。

系统存在多维度变化

如设备类型 × 通信协议;风控规则类型 × 数据来源;UI控件 × 渲染方式等。桥接模式适用于“横向+纵向”组合扩展。

不希望抽象类绑定具体实现

抽象类只依赖实现接口,真正的实现类通过组合传入,提高灵活性和可测试性。

需要运行时动态切换实现

实现可以作为参数传入抽象类或在运行时替换,方便配置化和策略组合。

使用组合优于继承的场景

继承会导致层级复杂、类爆炸,桥接通过组合简化层次结构。

4.2. ❌ 不适合使用桥接模式的场景

场景

原因

抽象和实现之间不存在独立扩展需求

如固定只有一种实现方式,没有变化维度,引入桥接反而增加复杂度。

类结构稳定、扩展需求低

桥接增加了层次结构,若业务不会频繁扩展,实现过度设计。

仅仅是想复用实现类

用组合/继承/策略即可,不一定非用桥接模式。

没有多个维度变化(组合笛卡尔积)问题

如果只是单一维度扩展,例如“多种支付方式”,策略模式或工厂模式更合适。

对性能要求极高的底层系统

桥接带来额外抽象层(如接口调用)在某些场景下不如直接调用高效。

4.3. 📌 桥接模式 vs 其他设计模式

模式

区别

策略模式

聚焦在运行时选择行为,但不强调“抽象-实现分离”。

装饰器模式

动态增强功能,适用于功能叠加,不用于解耦抽象与实现。

抽象工厂

用于一组产品族的创建,而桥接强调结构分离和组合扩展。

组合模式

强调“整体-部分”关系,桥接是抽象-实现的解耦。

4.4. 🧠 桥接模式场景总结

项目

桥接模式适用

不适用

是否有多维度扩展需求

✅ 是

❌ 否

抽象与实现是否可独立变化

✅ 是

❌ 固定结构

是否需要运行时切换实现

✅ 是

❌ 编译时固定

是否容易产生类爆炸

✅ 是

❌ 单维度扩展

是否需要组合替代继承

✅ 是

❌ 简单结构即可

性能是否极端敏感

❌ 可能不是最佳方案

✅ 低层性能场景

5. 桥接设计模式实战示例

下面是一个完整的、基于 Spring 的风控系统桥接模式示例,增加了策略注册表 + 配置驱动的动态组合能力。适用于金融风控系统中,针对不同风控维度、选择不同的数据源策略执行风控校验。

5.1. 使用桥接模式的意图

  • 抽象部分:风控维度类型(维度逻辑)
  • 实现部分:数据源(策略实现来源)
  • 风控维度:identityCheckfraudCheck 等。
  • 数据源:localSourcethirdPartySource 等。
  • 维度 + 数据源 = 组合执行。
  • 动态组合来源于配置,例如:
risk:dimension-config:identityCheck: localSourcefraudCheck: thirdPartySource

5.2. ✅ 项目结构概览

risk/
├── dimension/          # 风控维度定义(Abstraction)
│   ├── RiskDimension.java
│   ├── IdentityCheck.java
│   └── FraudCheck.java
├── datasource/         # 数据源定义(Implementor)
│   ├── DataSourceStrategy.java
│   ├── LocalRuleSource.java
│   └── ThirdPartySource.java
├── registry/           # 策略注册表
│   ├── DimensionRegistry.java
│   └── RiskProperties.java
└── controller/         # Controller 调用入口└── RiskController.java

5.3. 🧱 数据源接口与实现(Implementor)


public interface DataSourceStrategy {Map<String, Object> fetchData(String userId);
}
@Component("localSource")
public class LocalRuleSource implements DataSourceStrategy {public Map<String, Object> fetchData(String userId) {return Map.of("identityScore", 90, "fraudRiskLevel", "LOW");}
}@Component("thirdPartySource")
public class ThirdPartySource implements DataSourceStrategy {public Map<String, Object> fetchData(String userId) {return Map.of("identityScore", 80, "fraudRiskLevel", "HIGH");}
}

5.4. 🧱 维度抽象(Abstraction)

public abstract class RiskDimension {protected final DataSourceStrategy dataSource;public RiskDimension(DataSourceStrategy dataSource) {this.dataSource = dataSource;}public abstract boolean check(String userId);
}
@Component("identityCheck")
public class IdentityCheck extends RiskDimension {public IdentityCheck(@Lazy DataSourceStrategy dataSource) {super(dataSource);}@Overridepublic boolean check(String userId) {int score = (int) dataSource.fetchData(userId).get("identityScore");return score >= 85;}
}
@Component("fraudCheck")
public class FraudCheck extends RiskDimension {public FraudCheck(@Lazy DataSourceStrategy dataSource) {super(dataSource);}@Overridepublic boolean check(String userId) {String risk = (String) dataSource.fetchData(userId).get("fraudRiskLevel");return !"HIGH".equalsIgnoreCase(risk);}
}

⚠️ 注意:这里 @Component + @Lazy 仅示意,最终我们会用工厂+注册表生成具体实例。

5.5. 🧱 配置类

5.5.1. application.yml

risk:dimension-config:identityCheck: localSourcefraudCheck: thirdPartySource

5.5.2. RiskProperties.java

@Configuration
@ConfigurationProperties(prefix = "risk")
public class RiskProperties {private Map<String, String> dimensionConfig = new HashMap<>();public Map<String, String> getDimensionConfig() {return dimensionConfig;}public void setDimensionConfig(Map<String, String> dimensionConfig) {this.dimensionConfig = dimensionConfig;}
}

5.6. 🧱 注册表 + 工厂

@Component
public class DimensionRegistry {private final Map<String, Function<DataSourceStrategy, RiskDimension>> dimensionFactories = new HashMap<>();private final Map<String, DataSourceStrategy> dataSources;private final RiskProperties properties;public DimensionRegistry(List<DataSourceStrategy> dataSourceList,RiskProperties properties) {this.dataSources = dataSourceList.stream().collect(Collectors.toMap(bean -> bean.getClass().getAnnotation(Component.class).value(), bean -> bean));this.properties = properties;// 注册维度逻辑工厂(风控维度 -> 构造函数)dimensionFactories.put("identityCheck", IdentityCheck::new);dimensionFactories.put("fraudCheck", FraudCheck::new);}public List<RiskDimension> buildRiskDimensions() {List<RiskDimension> dimensions = new ArrayList<>();for (Map.Entry<String, String> entry : properties.getDimensionConfig().entrySet()) {String dimensionKey = entry.getKey();String dataSourceKey = entry.getValue();Function<DataSourceStrategy, RiskDimension> factory = dimensionFactories.get(dimensionKey);DataSourceStrategy dataSource = dataSources.get(dataSourceKey);if (factory != null && dataSource != null) {dimensions.add(factory.apply(dataSource));}}return dimensions;}
}

5.7. 🧱 Controller 示例

@RestController
@RequestMapping("/risk")
public class RiskController {private final DimensionRegistry registry;public RiskController(DimensionRegistry registry) {this.registry = registry;}@GetMapping("/check")public String check(@RequestParam String userId) {List<RiskDimension> dimensions = registry.buildRiskDimensions();for (RiskDimension dimension : dimensions) {boolean pass = dimension.check(userId);if (!pass) {return "风控未通过: " + dimension.getClass().getSimpleName();}}return "全部风控校验通过 ✅";}
}

5.8. ✅ 示例访问

GET /risk/check?userId=10001

5.9. ✅ 总结亮点

特性

实现方式

桥接模式

RiskDimension 与 DataSourceStrategy 分离

动态组合

YAML + DimensionRegistry 注册表

便于扩展

新增维度 / 数据源只需注册工厂或添加配置

对象交给 Spring 管理

@Component 自动注入、收集策略

6. 桥接设计模式思考

6.1. spring多种注册方式理解

@Component("urgent")
public class UrgentMessageStrategy implements MessageStrategy {private final MessageSender sender;public UrgentMessageStrategy(@Qualifier("emailSender") MessageSender sender) {this.sender = sender;}@Overridepublic void send(String content, String toUser) {new Message(sender) {@Overridepublic void send(String content, String toUser) {sender.send("[加急] " + content, toUser);}}.send(content, toUser);}
}

你这个 UrgentMessageStrategy 完全可以使用 自动注入的方式,让 Spring 管理和注入所需的 MessageSender 实例,下面是你当前代码的简化版以及替代方案:

6.1.1. 当前写法(构造方法注入,使用 @Qualifier 指定具体实现)

这是推荐方式,优点是:

  • 构造注入更清晰,有利于单元测试。
  • @Qualifier 显式声明依赖于哪个 Bean,清楚、稳定

6.1.2. ✅ 替代方式 1:字段注入 + @Qualifier

@Component("urgent")
public class UrgentMessageStrategy implements MessageStrategy {@Autowired@Qualifier("emailSender")private MessageSender sender;@Overridepublic void send(String content, String toUser) {new Message(sender) {@Overridepublic void send(String content, String toUser) {sender.send("[加急] " + content, toUser);}}.send(content, toUser);}
}

字段注入也能用,但不推荐在实际项目中使用(测试不友好,易失控)。

6.1.3. ✅ 替代方式 2:@Resource(name = "emailSender")(使用 JSR-250 规范)

@Component("urgent")
public class UrgentMessageStrategy implements MessageStrategy {@Resource(name = "emailSender")private MessageSender sender;@Overridepublic void send(String content, String toUser) {new Message(sender) {@Overridepublic void send(String content, String toUser) {sender.send("[加急] " + content, toUser);}}.send(content, toUser);}
}

这也是一种替代方式,但语义上不如 @Qualifier 灵活。

6.1.4. 🚫 不建议的方式:使用 @Autowired 而不指定 @Qualifier

@Autowired
private MessageSender sender;

这种写法只有在系统中只有一个 MessageSender 实现时才不会报错。一旦有多个(如 smsSenderemailSenderdingSender),Spring 会抛出 NoUniqueBeanDefinitionException 异常。

6.1.5. ✅ spring对象注入总结

注入方式

是否可行

推荐度

说明

构造注入 + @Qualifier

⭐⭐⭐⭐⭐

推荐方式,稳定、测试友好

字段注入 + @Qualifier

⭐⭐

可用,但不推荐生产使用

@Resource(name = "...")

⭐⭐⭐

简洁但较老,语义较弱

@Autowired@Qualifier

❌ 多实现会报错

不推荐

博文参考

  • 桥接设计模式
  • 2. 桥接模式 — Graphic Design Patterns

相关文章:

设计模式——桥接设计模式(结构型)

摘要 桥接设计模式是一种结构型设计模式&#xff0c;用于将抽象与实现解耦&#xff0c;使二者可以独立变化。它通过将一个类拆分为“抽象”和“实现”两部分&#xff0c;并通过桥接关系组合&#xff0c;避免了类继承层次结构过于庞大。桥接模式包含抽象类、扩充抽象类、实现类…...

LLaDa——基于 Diffusion 的大语言模型 打平 LLama 3

这里分享一篇文章《Large Language Diffusion Models》&#xff0c;来自人民大学高领人工智能学院&#xff0c;一篇尝试改变传统自回归范&#xff08;预测下一个token&#xff09; LLM 架构&#xff0c;探索扩散模型在 LLM 上的作用&#xff0c;通过随机掩码-预测逆向思维&…...

Apache SeaTunnel部署技术详解:模式选择、技巧与最佳实践

Apache SeaTunnel&#xff08;原Waterdrop&#xff09;作为高性能、分布式数据集成平台&#xff0c;支持海量数据的离线与实时同步。其灵活多样的部署模式可适配不同规模的生产环境需求。本文将系统解析SeaTunnel的部署架构、技术要点及最佳实践&#xff0c;帮助用户高效构建稳…...

2. 数据结构基本概念 (2)

本文部分ppt、视频截图来自&#xff1a;[青岛大学-王卓老师的个人空间-王卓老师个人主页-哔哩哔哩视频] 1. 数据结构基本概念 1.1 数据类型和抽象数据类型 (1) 数据类型(Data Type) 概念 数据类型是一组性质相同的值的集合以及定义于这个值集合上的一组操作的总称。 在使用…...

鸿蒙5.0+ 多协议设备发现与分布式软总线技术实践

一、技术演进与架构升级 1.1 多协议发现机制演进 鸿蒙5.0重构设备发现层&#xff0c;支持​​三模异构发现​​&#xff1a; ​​经典蓝牙​​&#xff08;BLE 5.2&#xff09;&#xff1a;低功耗设备发现​​Wi-Fi Aware​​&#xff1a;高带宽设备预连接​​PLC&#xff0…...

STM32F407寄存器操作(多通道单ADC+DMA)

1.前言 又是半年没更新了&#xff0c;趁着端午放假有点时间&#xff0c;并且最近项目要用这块知识&#xff0c;我就顺带研究一下ADC吧。 一般来说ADC主要用法包含了1.单通道软件触发&#xff08;这是最简单和最常用的用法&#xff09;2.单通道多次采集&#xff08;需要快速采…...

基于React和TypeScript的金融市场模拟器开发与模式分析

基于React和TypeScript的金融市场模拟器开发与模式分析 项目概述 本项目开发了一个基于React和TypeScript的金融市场模拟器&#xff0c;通过模拟订单流和价格发现机制&#xff0c;重现了真实市场的动态特性。该模拟器不仅提供了实时价格图表、订单簿和交易功能&#xff0c;还…...

剑指offer13_剪绳子

剪绳子 给你一根长度为 n 绳子&#xff0c;请把绳子剪成 m 段&#xff08;m、n都是整数&#xff0c;2≤n≤58 并且 m≥2&#xff09;。 每段的绳子的长度记为 k[1]、k[2]、……、k[m]。 k[1]k[2]…k[m] 可能的最大乘积是多少&#xff1f; 例如当绳子的长度是 8 时&#xff0…...

reverse_ssh 建立反向 SSH 连接指南 混淆AV [好东西哟]

目录 &#x1f310; 工具简介 ⚙️ 前提条件 攻击主机 (Linux) 目标主机 (Windows) &#x1f4cb; 详细步骤 步骤 1&#xff1a;安装 Go 环境 步骤 2&#xff1a;安装必要依赖 步骤 3&#xff1a;下载并编译 reverse_ssh 步骤 4&#xff1a;配置密钥 步骤 5&#xff…...

vue+elementUi+axios实现分页(MyBatis、Servlet)

vueelementUiaxios实现分页 文章目录 vueelementUiaxios实现分页1.代码实现【HTML】**【Servlet层】****【Service层】****【Dao层】** 2.总结步骤3.实现要点4.注意事项4.注意事项 注&#xff1a;此项目 前端为 html、 后端采用 mybatis、servlet实现 1.代码实现 【HTML】…...

WebBuilder数据库:企业数据管理的能力引擎

在数据成为核心生产要素的时代&#xff0c;企业对数据库的需求早已超越“存储与查询”的基础功能&#xff0c;转而追求高性能、高安全、高兼容与高效开发的综合能力。WebBuilder作为企业级快速开发平台的佼佼者&#xff0c;其数据库能力正式破解数据管理难题的关键钥匙。本文将…...

QtWidgets,QtCore,QtGui

目录 三者的关系示例代码主要功能模块QtCore**一、核心功能与常用类****1. 信号与槽机制(Signals and Slots)****2. 事件处理(Event Handling)****3. 定时器(Timers)****4. 线程(Threading)****5. 文件与目录操作****6. 属性系统(Property System)****二、高级特性**…...

lvs-keepalived高可用群集

目录 1.Keepalived 概述及安装 1.1 Keepalived 的热备方式 1.2 keepalived的安装与服务控制 &#xff08;1&#xff09;安装keep alived (2)控制 Keepalived 服务DNF 安装 keepalived 后,执行以下命令将keepalived 服务设置为开机启动。 2.使用 Keepalived 实现双机热备 …...

【Elasticsearch】suggest

在Elasticsearch中&#xff0c;suggest 是一个非常强大的功能&#xff0c;用于实现自动补全、拼写纠错和模糊搜索等功能。它可以帮助用户更快地找到他们想要的内容&#xff0c;同时提升搜索体验。以下是关于 suggest 的详细使用方法和常见场景。 1\. Suggest 的基本概念 sugges…...

高速收发器

一、高速收发器 1.FPGA高速收发器&#xff1a;GTP,GTX,GTH,GTZ 2.每个Quad有4对高速收发器GT(4个TX和4个RX)和一个COmmon 3.走差分&#xff0c;提高抗干扰性 4.CPLL是每个lane私有的&#xff0c;QPLL是整个Quad的所有通道共享的 5.每个MGT的bank有两对差分参考时钟 6.CPLL的时钟…...

webpack的安装及其后序部分

npm install原理 这个其实就是npm从registry下载项目到本地&#xff0c;没有什么好说的 值得一提的是npm的缓存机制&#xff0c;如果多个项目都需要同一个版本的axios&#xff0c;每一次重新从registry中拉取的成本过大&#xff0c;所以会有缓存&#xff0c;如果缓存里有这个…...

如何利用自动生成文档工具打造出色的技术文档

文章目录 每日一句正能量前言一、自动生成文档工具的优势&#xff08;一&#xff09;提高效率&#xff08;二&#xff09;保持一致性&#xff08;三&#xff09;实时更新 二、常见的自动生成文档工具&#xff08;一&#xff09;Sphinx&#xff08;二&#xff09;Javadoc&#x…...

读《Go语言圣经记录》(二):深入理解Go语言的程序结构

读《Go语言圣经记录》&#xff08;二&#xff09;&#xff1a;深入理解Go语言的程序结构 在编程的世界里&#xff0c;Go语言以其简洁、高效和强大的并发能力而备受开发者青睐。今天&#xff0c;我将带大家深入探索Go语言的程序结构&#xff0c;通过详细解读《Go语言圣经》中的…...

实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.7 R语言解题

本文是实验设计与分析&#xff08;第6版&#xff0c;Montgomery著&#xff0c;傅珏生译) 第5章析因设计引导5.7节思考题5.7 R语言解题。主要涉及方差分析&#xff0c;正态假设检验&#xff0c;残差分析&#xff0c;交互作用图&#xff0c;等值线图。 dataframe <-data.frame…...

nacos Sentinel zipkin docker运行

服务注册发现 分布配置中⼼nacos dockerdocker pull nacos/nacos-server:1.3.2docker run -d --name nacos-server -p 8848:8848 -e MODEstandalone nacos/nacos-server:1.3.2访问 http://localhost:8848/nacos 服务限流降级&#xff1a;Sentinel docker docker pul…...

OpenCv高阶(二十)——dlib脸部轮廓绘制

文章目录 一、人脸面部轮廓绘制代码实现1、定义绘制直线段的函数2、定义绘制凸包轮廓的函数3、读取输入图像4、初始化dlib的人脸检测器5、使用检测器在图像中检测人脸&#xff08;参数0表示不进行图像缩放&#xff09;6、加载dlib的68点人脸关键点预测模型7、遍历检测到的每个人…...

pikachu靶场通关笔记08 XSS关卡04-DOM型XSS

目录 一、XSS原理 二、DOM型XSS 三、源码分析 1、进入靶场 2、XSS探测 3、源码分析 四、渗透实战 1、Payload1 2、Payload2 3、Payload3 本系列为通过《pikachu靶场通关笔记》的XSS关卡(共10关&#xff09;渗透集合&#xff0c;通过对XSS关卡源码的代码审计找到XSS风…...

python集成inotify-rsync实现跨服务器文件同步

1、实现功能 通过结合 Python 的 watchdog 库&#xff08;类似 Linux 的 inotify 机制&#xff09;和 rsync 命令&#xff0c;实现了文件系统变化的实时监控和增量同步。下面详细解释其工作原理和运行方式&#xff1a; 2、核心工作原理 2.1、文件监控 使用watchdog库监控源目…...

005 ElasticSearch 许可证过期问题

ElasticSearch 许可证过期问题 项目启动报错 org.elasticsearch.client.ResponseException: method [GET], host [http://127.0.0.1:9200], URI [/_cluster/health/], status line [HTTP/1.1 403 Forbidden] {"error":{"root_cause":[{"type":…...

Spring AI 系列之使用 Spring AI 开发模型上下文协议(MCP)

1. 概述 现代网页应用越来越多地集成大型语言模型&#xff08;LLMs&#xff09;来构建解决方案&#xff0c;这些解决方案不仅限于基于常识的问答。 为了增强 AI 模型的响应能力&#xff0c;使其更具上下文感知&#xff0c;我们可以将其连接到外部资源&#xff0c;比如搜索引擎…...

[Python] Python运维:系统性能信息模块psutil和系统批量运维管理器paramiko

初次学习&#xff0c;如有错误还请指正 目录 系统性能信息模块psutil 获取系统性能信息 CPU信息 内存信息 磁盘信息 网络信息 其他信息 进程信息 实用的IP地址处理模块IPy IP地址、网段的基本处理 多网络计算方法 系统批量运维管理器paramiko paramiko 的安装 Li…...

Linux 简单模拟实现C语言文件流

&#x1f307;前言 在 C语言 的文件流中&#xff0c;存在一个 FILE 结构体类型&#xff0c;其中包含了文件的诸多读写信息以及重要的文件描述符 fd&#xff0c;在此类型之上&#xff0c;诞生了 C语言 文件相关操作&#xff0c;如 fopen、fclose、fwrite 等&#xff0c;这些函数…...

ArcPy错误处理与调试技巧(3)

三、调试技巧 调试是编程过程中不可或缺的一部分&#xff0c;以下是一些常用的调试技巧&#xff1a; 1. 打印调试信息 在代码中添加print语句&#xff0c;可以帮助你了解程序的运行状态和变量的值。例如&#xff1a; # 打印提示信息&#xff0c;表示开始执行缓冲区分析 print(…...

小程序使用npm包的方法

有用的链接 npm init -y 这个命令很重要, 会初始化 package.json 再重新打开微信小程序开发工具 选择工具中npm构建 在程序中引用时在main.js中直接使用包名的方式引用即可 如安装的是generator包&#xff0c;npm构建后就会生成 const myPackage require(***-generato…...

Asp.Net Core SignalR的协议协商问题

文章目录 前言一、协议协商的原理二、常见的协商问题及解决办法1.跨域资源共享&#xff08;CORS&#xff09;问题2.身份验证和授权问题3.传输方式不兼容问题4.路由配置错误5.代理和负载均衡器问题6.自定义协商&#xff08;高级&#xff09; 总结 前言 在ASP.NET Core SignalR …...