代理模式深度解析:從靜態代理到 Spring AOP 實現

代理模式是軟件開發中一種經典的設計模式,它通過引入 "代理對象" 間接訪問目標對象,從而在不修改目標對象代碼的前提下,實現功能增強(如日志記錄、事務管理)、權限控制等橫切需求。從簡單的靜態代理到靈活的動態代理,再到 Spring AOP 的工業化實現,代理模式的演進極大地提升了代碼的可擴展性和可維護性。本文將從原理到實踐,全面解析代理模式的各種實現方式及其在 Spring AOP 中的應用。

一、代理模式的核心思想

代理模式的本質是 "控制訪問":通過代理對象作為目標對象的 "中間人",所有對目標對象的訪問都必須經過代理,從而在代理中嵌入額外邏輯(如前置檢查、后置處理)。其核心價值在于:

  • 解耦:將核心業務邏輯與橫切關注點(如日志、事務)分離,符合 "單一職責原則";
  • 增強:在不修改目標對象代碼的前提下,動態擴展功能;
  • 隔離:通過代理隔離客戶端與目標對象,保護目標對象的直接訪問(如遠程代理中隱藏網絡通信細節)。

代理模式的通用結構包含三個角色:

  • 抽象接口(Subject):定義目標對象和代理對象的共同行為,是代理模式的 "契約";
  • 目標對象(Target):實現抽象接口,包含核心業務邏輯,是被代理的對象;
  • 代理對象(Proxy):實現抽象接口,持有目標對象的引用,在調用目標方法前后嵌入增強邏輯。

二、靜態代理:編譯時確定的代理關系

靜態代理是代理模式最基礎的實現方式,其代理類在編譯期就已確定,與目標對象的關系是 "硬編碼" 的。

1. 靜態代理的實現原理

靜態代理要求代理類與目標對象實現相同的抽象接口,代理類內部持有目標對象的實例,在重寫的接口方法中調用目標對象的對應方法,并在調用前后添加增強邏輯。

實現步驟:
  1. 定義抽象接口(Subject):規范目標對象和代理對象的行為;
  2. 實現目標對象(Target):完成核心業務邏輯;
  3. 實現代理對象(Proxy):持有目標對象引用,在方法中嵌入增強邏輯;
  4. 客戶端通過代理對象訪問目標功能。

2. 靜態代理實戰案例:日志增強

以 "給用戶服務添加操作日志" 為例,演示靜態代理的實現。

(1)抽象接口:定義用戶服務行為
// 抽象接口(Subject)
public interface UserService {void login(String username); // 登錄方法void logout(); // 登出方法
}
(2)目標對象:實現核心業務邏輯
// 目標對象(Target)
public class UserServiceImpl implements UserService {@Overridepublic void login(String username) {System.out.println("用戶[" + username + "]登錄成功");}@Overridepublic void logout() {System.out.println("用戶登出成功");}
}
(3)代理對象:嵌入日志增強邏輯
// 代理對象(Proxy)
public class UserServiceProxy implements UserService {// 持有目標對象引用private UserService target;// 通過構造器注入目標對象public UserServiceProxy(UserService target) {this.target = target;}@Overridepublic void login(String username) {// 前置增強:記錄開始時間long start = System.currentTimeMillis();System.out.println("【日志】登錄方法開始執行,參數:" + username);// 調用目標方法target.login(username);// 后置增強:記錄結束時間和耗時long end = System.currentTimeMillis();System.out.println("【日志】登錄方法執行結束,耗時:" + (end - start) + "ms");}@Overridepublic void logout() {// 前置增強System.out.println("【日志】登出方法開始執行");// 調用目標方法target.logout();// 后置增強System.out.println("【日志】登出方法執行結束");}
}
(4)客戶端調用
public class Client {public static void main(String[] args) {// 創建目標對象UserService target = new UserServiceImpl();// 創建代理對象(傳入目標對象)UserService proxy = new UserServiceProxy(target);// 通過代理對象調用方法proxy.login("zhangsan");System.out.println("-----");proxy.logout();}
}
執行結果:
【日志】登錄方法開始執行,參數:zhangsan
用戶[zhangsan]登錄成功
【日志】登錄方法執行結束,耗時:1ms
-----
【日志】登出方法開始執行
用戶登出成功
【日志】登出方法執行結束

3. 靜態代理的優缺點

優點

  • 實現簡單:邏輯直觀,易于理解和調試;
  • 性能較好:編譯期確定代理關系,運行時無額外開銷。

缺點

  • 代碼冗余:每一個目標類都需要對應一個代理類,類數量爆炸;
  • 維護成本高:目標類新增 / 修改方法時,代理類必須同步修改,違反 "開閉原則";
  • 靈活性差:代理邏輯固定,無法動態切換(如不同場景需要不同增強邏輯時,需創建多個代理類)。

靜態代理僅適用于目標類少、方法固定的簡單場景(如固定第三方接口的適配),在復雜系統中難以應用。

三、動態代理:運行時生成的靈活代理

動態代理解決了靜態代理的局限性,其核心是在運行時動態生成代理類,代理關系在程序運行時才確定,無需手動編寫代理類代碼。Java 中動態代理的主流實現有兩種:JDK Proxy(基于接口)和 CGLib(基于繼承)。

1. JDK Proxy:基于接口的動態代理

JDK Proxy 是 Java 原生支持的動態代理方式,通過java.lang.reflect.Proxy類和InvocationHandler接口實現,僅能代理實現了接口的目標類

(1)JDK Proxy 的核心原理

JDK Proxy 的工作流程可概括為:

  1. 客戶端通過Proxy.newProxyInstance()方法請求生成代理對象;
  2. JVM 在運行時動態生成一個代理類的字節碼(繼承Proxy類,實現目標接口);
  3. 代理類的所有方法都會委托給InvocationHandlerinvoke()方法;
  4. invoke()方法中,開發者可嵌入增強邏輯,再通過反射調用目標對象的方法。

關鍵機制

  • 動態生成的代理類名稱格式為$ProxyN(N 為數字),由sun.misc.ProxyGenerator生成字節碼;
  • 代理類持有InvocationHandler實例,通過它轉發所有方法調用;
  • 利用反射(Method.invoke())調用目標方法,這是 JDK Proxy 性能開銷的主要來源。
(2)JDK Proxy 實戰:通用日志代理

基于 JDK Proxy 實現一個通用的日志代理,可對任意接口的目標對象添加日志增強。

步驟 1:定義接口和目標類(復用靜態代理中的UserServiceUserServiceImpl
步驟 2:實現InvocationHandler:封裝增強邏輯
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;// 日志增強處理器
public class LogInvocationHandler implements InvocationHandler {// 目標對象(被代理的對象)private Object target;public LogInvocationHandler(Object target) {this.target = target;}/*** 代理對象的所有方法調用都會轉發到這里* @param proxy 代理對象本身* @param method 目標方法* @param args 目標方法參數* @return 目標方法返回值*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 前置增強:記錄方法開始日志System.out.println("【JDK Proxy日志】方法[" + method.getName() + "]開始執行,參數:" + Arrays.toString(args));// 反射調用目標方法Object result = method.invoke(target, args);// 后置增強:記錄方法結束日志System.out.println("【JDK Proxy日志】方法[" + method.getName() + "]執行結束,返回值:" + result);return result;}
}
步驟 3:生成代理對象并調用
import java.lang.reflect.Proxy;public class JdkProxyClient {public static void main(String[] args) {// 1. 創建目標對象UserService target = new UserServiceImpl();// 2. 創建InvocationHandler(傳入目標對象)LogInvocationHandler handler = new LogInvocationHandler(target);// 3. 動態生成代理對象// 參數:類加載器、目標接口數組、InvocationHandlerUserService proxy = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);// 4. 通過代理對象調用方法proxy.login("lisi");System.out.println("-----");proxy.logout();}
}
執行結果:
【JDK Proxy日志】方法[login]開始執行,參數:[lisi]
用戶[lisi]登錄成功
【JDK Proxy日志】方法[login]執行結束,返回值:null
-----
【JDK Proxy日志】方法[logout]開始執行,參數:null
用戶登出成功
【JDK Proxy日志】方法[logout]執行結束,返回值:null
(3)JDK Proxy 的特點
  • 接口依賴:必須代理實現了接口的類,無法代理純類(無接口);
  • 動態生成:代理類在運行時生成,無需手動編寫;
  • 反射調用:通過Method.invoke()調用目標方法,性能略低于直接調用;
  • 原生支持:無需額外依賴,Java 核心庫自帶。

2. CGLib:基于繼承的動態代理

CGLib(Code Generation Library)是一個第三方字節碼操作庫,通過生成目標類的子類實現代理,無需目標類實現接口,彌補了 JDK Proxy 的局限性。

(1)CGLib 的核心原理

CGLib 的工作流程:

  1. 通過Enhancer類指定目標類作為父類;
  2. 實現MethodInterceptor接口,定義方法攔截邏輯;
  3. CGLib 使用 ASM 框架動態生成目標類的子類(代理類),重寫父類的非 final 方法;
  4. 代理類的方法被調用時,會觸發MethodInterceptorintercept()方法,在此嵌入增強邏輯。

關鍵機制

  • FastClass 機制:為目標類和代理類生成一個 "FastClass",通過方法索引直接調用目標方法,避免反射開銷,性能優于 JDK Proxy;
  • 字節碼操作:通過 ASM 框架直接操作字節碼生成代理類,無需源碼;
  • 繼承限制:無法代理 final 類(無法繼承)和 final 方法(無法重寫)。
(2)CGLib 實戰:代理無接口的類

以一個無接口的OrderService為例,演示 CGLib 代理。

步驟 1:引入 CGLib 依賴(Maven)
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
步驟 2:定義無接口的目標類
// 無接口的目標類
public class OrderService {public void createOrder(String goods) {System.out.println("訂單創建成功,商品:" + goods);}public void cancelOrder(Long orderId) {System.out.println("訂單[" + orderId + "]取消成功");}
}
步驟 3:實現MethodInterceptor:定義攔截邏輯
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;// 訂單服務攔截器(增強邏輯)
public class OrderServiceInterceptor implements MethodInterceptor {/*** 代理類方法被調用時觸發* @param obj 代理對象(子類實例)* @param method 目標方法(父類方法)* @param args 方法參數* @param proxy 方法代理對象(用于調用父類方法)* @return 目標方法返回值*/@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 前置增強:記錄開始日志System.out.println("【CGLib日志】方法[" + method.getName() + "]開始執行,參數:" + Arrays.toString(args));// 調用目標方法(通過MethodProxy調用父類方法,比反射高效)Object result = proxy.invokeSuper(obj, args);// Object invoke = method.invoke(t, args);// 作用等同與上面。// 后置增強:記錄結束日志System.out.println("【CGLib日志】方法[" + method.getName() + "]執行結束");return result;}
}
步驟 4:生成代理對象并調用
import net.sf.cglib.proxy.Enhancer;public class CglibProxyClient {public static void main(String[] args) {// 1. 創建增強器(用于生成代理類)Enhancer enhancer = new Enhancer();// 2. 設置父類(目標類)enhancer.setSuperclass(OrderService.class);// 3. 設置攔截器(增強邏輯)enhancer.setCallback(new OrderServiceInterceptor());// 4. 生成代理對象(目標類的子類)OrderService proxy = (OrderService) enhancer.create();// 5. 調用代理對象方法proxy.createOrder("手機");System.out.println("-----");proxy.cancelOrder(1001L);}
}
執行結果:
【CGLib日志】方法[createOrder]開始執行,參數:[手機]
訂單創建成功,商品:手機
【CGLib日志】方法[createOrder]執行結束
-----
【CGLib日志】方法[cancelOrder]開始執行,參數:[1001]
訂單[1001]取消成功
【CGLib日志】方法[cancelOrder]執行結束
(3)CGLib 的特點
  • 無接口依賴:可代理任意非 final 類,無需實現接口;
  • 性能優勢:通過 FastClass 機制避免反射,調用效率高于 JDK Proxy;
  • 字節碼操作:依賴 ASM 框架生成字節碼,實現復雜;
  • 繼承限制:無法代理 final 類或方法(因無法生成子類或重寫方法)。

3. JDK Proxy vs CGLib:核心差異對比

維度JDK ProxyCGLib
底層原理實現目標接口(接口代理)繼承目標類(子類代理)
目標類要求必須實現接口不能是 final 類,方法不能是 final
性能反射調用,性能中等FastClass 機制,性能更高(尤其是多次調用)
依賴Java 原生支持,無額外依賴需引入 CGLib 和 ASM 依賴
生成代理類時間較快(僅生成接口實現類)較慢(需生成子類字節碼)
適用場景目標類已實現接口目標類無接口或為純類

四、靜態代理與動態代理:如何選擇?

靜態代理和動態代理的核心差異在于代理類的生成時機(編譯期 vs 運行時),選擇時需結合場景:

1. 靜態代理的適用場景

  • 目標類數量少且固定(如固定的第三方接口適配);
  • 增強邏輯簡單且不常變更(如簡單的參數校驗);
  • 對性能要求極高(無運行時生成代理類的開銷)。

2. 動態代理的適用場景

  • 目標類數量多或不確定(如框架中通用增強,如 Spring 事務);
  • 增強邏輯需要動態切換(如不同環境下的日志級別切換);
  • 需代理無接口的類(如遺留系統中的純類)。

總結:日常開發中,動態代理(尤其是結合框架的實現)應用更廣泛,靜態代理僅在簡單場景下使用。

五、Spring AOP:動態代理的工業化實現

Spring AOP(面向切面編程)是代理模式的工業化應用,它基于動態代理(JDK Proxy 或 CGLib)實現橫切關注點的模塊化,是 Spring 框架的核心特性之一。

1. AOP 核心概念

AOP 通過以下概念描述橫切邏輯的設計與織入:

  • 切面(Aspect):封裝橫切關注點的模塊(如日志切面、事務切面),由切點和通知組成;
  • 連接點(Join Point):程序執行過程中的可插入點(如方法調用、異常拋出),Spring AOP 僅支持方法級連接點;
  • 切點(Pointcut):篩選連接點的條件(如 "所有被 @Transactional 注解的方法");
  • 通知(Advice):切面在連接點執行的邏輯,包括前置通知(@Before)、后置通知(@After)、環繞通知(@Around)等;
  • 織入(Weaving):將切面邏輯嵌入目標對象的過程(Spring AOP 在運行時織入)。

2. Spring AOP 的代理選擇策略

Spring AOP 默認根據目標類是否實現接口選擇代理方式:

  • 若目標類實現了接口:使用 JDK Proxy 生成代理;
  • 若目標類未實現接口:使用 CGLib 生成代理;
  • 可通過proxy-target-class="true"強制使用 CGLib(如@EnableAspectJAutoProxy(proxyTargetClass = true))。

3. Spring AOP 實戰:基于注解的切面

以 "用戶服務的操作日志記錄" 為例,演示 Spring AOP 的實現。

步驟 1:引入 Spring AOP 依賴(Maven)
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.20</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.20</version>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.9.1</version>
</dependency>
步驟 2:定義目標服務(UserService)
import org.springframework.stereotype.Service;@Service // 交由Spring管理
public class UserService {public void login(String username) {System.out.println("用戶[" + username + "]登錄成功");}public void logout() {System.out.println("用戶登出成功");}
}
步驟 3:定義切面類(日志切面)
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;@Aspect // 標識為切面類
@Component // 交由Spring管理
public class LogAspect {// 定義切點:匹配UserService中的所有方法@Pointcut("execution(* com.example.aop.UserService.*(..))")public void userServicePointcut() {}// 前置通知:方法執行前觸發@Before("userServicePointcut()")public void beforeAdvice(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("【AOP前置通知】方法[" + methodName + "]參數:" + Arrays.toString(args));}// 后置通知:方法執行后觸發(無論是否異常)@After("userServicePointcut()")public void afterAdvice(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();System.out.println("【AOP后置通知】方法[" + methodName + "]執行結束");}// 環繞通知:包圍方法執行,可控制是否執行目標方法@Around("userServicePointcut()")public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {String methodName = joinPoint.getSignature().getName();long start = System.currentTimeMillis();// 執行目標方法(必須調用,否則目標方法不執行)Object result = joinPoint.proceed();long end = System.currentTimeMillis();System.out.println("【AOP環繞通知】方法[" + methodName + "]耗時:" + (end - start) + "ms");return result;}
}
步驟 4:配置 Spring 并測試
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@EnableAspectJAutoProxy // 開啟AOP注解支持
@ComponentScan("com.example.aop") // 掃描組件
public class SpringAopClient {public static void main(String[] args) {// 初始化Spring容器AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringAopClient.class);// 獲取代理對象(注意:此時獲取的是代理對象,而非原始UserService)UserService userService = context.getBean(UserService.class);// 調用方法userService.login("wangwu");System.out.println("-----");userService.logout();}
}
執行結果:
【AOP前置通知】方法[login]參數:[wangwu]
【AOP環繞通知】方法[login]開始執行
用戶[wangwu]登錄成功
【AOP環繞通知】方法[login]耗時:2ms
【AOP后置通知】方法[login]執行結束
-----
【AOP前置通知】方法[logout]參數:[]
【AOP環繞通知】方法[logout]開始執行
用戶登出成功
【AOP環繞通知】方法[logout]耗時:1ms
【AOP后置通知】方法[logout]執行結束

4. Spring AOP 的底層實現

Spring AOP 的織入過程本質是動態代理的生成過程:

  1. 容器啟動時,掃描所有@Aspect注解的切面類;
  2. 解析切點表達式,匹配需要被增強的目標類方法;
  3. 對匹配的目標類,根據是否實現接口選擇 JDK Proxy 或 CGLib 生成代理對象;
  4. 將切面中的通知邏輯(Advice)嵌入代理對象的方法中;
  5. 客戶端從容器中獲取的是代理對象,所有方法調用均通過代理執行。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/96270.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/96270.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/96270.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

算法 ----- 鏈式

目錄 一 、鏈式 二 、題目 1、兩兩相加 &#xff08;1&#xff09;題目 (3) 代碼書寫 2、兩兩交換鏈表中的節點 &#xff08;1&#xff09;題目 &#xff08;2&#xff09; 解題思路 &#xff08;3&#xff09;代碼書寫 3、重排鏈表 &#xff08;1&#xff09;題目 …

運維監控prometheus+grafana

目錄 一、環境 二、Node_exporter部署 三、Prometheus部署 四、Grafana部署 五、驗證、使用 一、環境 系統使用CentOS7虛擬機。 監控三臺服務器&#xff1a; 192.168.114.10 Node1 #部署Prometheus、node_exporter、Grafana 192.168.114.20 Node2 …

數字孿生 :提高制造生產力的智能方法

近年來&#xff0c;在先進數字技術深度整合的推動下&#xff0c;制造業經歷了深刻變革。數字孿生技術作為其中最具前景的創新之一&#xff0c;正重塑工廠和生產流程的設計、監控和優化方式。該技術的核心在于為物理資產、系統或流程創建虛擬映射。這種虛擬映射實時同步現實世界…

【論文閱讀】-《SIGN-OPT: A QUERY-EFFICIENT HARD-LABEL ADVERSARIAL ATTACK》

Sign-OPT: 一種查詢高效的硬標簽對抗攻擊 原文鏈接&#xff1a;https://arxiv.org/pdf/1909.10773 摘要 我們研究在訪問受限情況下評估機器學習系統對抗魯棒性的最實用問題設置&#xff1a;用于生成對抗樣本的硬標簽黑盒攻擊設置&#xff0c;其中允許有限的模型查詢&#xff…

安卓11 12系統修改定制化_____如何去掉 搜狗輸入法 首次運行時權限授權彈窗 其他應用可借鑒

有些內置應用或者第三方應用在首次使用時會跳出權限允許彈窗。雖然這個是系統為了用戶安全設置的一道檢測機制。但無形之中會影響到定制類用戶的使用。那么能不能去除這個首次運行的權限彈窗呢。其實也有多方法可參閱解決。 通過博文了解?????? 1??????-----首次…

雙環模型:一個蘊含安全哲學的類設計解析

雙環模型&#xff1a;一個蘊含安全哲學的類設計解析 在編程世界中&#xff0c;優秀的類設計不僅能實現功能需求&#xff0c;更能體現開發者對系統本質的理解。本文將深入剖析一個看似簡單卻蘊含深刻安全哲學的OP類&#xff0c;探討其雙環模型背后的設計思想與實踐價值。 類結構…

牛津大學xDeepMind 自然語言處理(4)

牛津大學xDeepMind 自然語言處理 Natural Language Processing 語音識別 Speech Recognition語音識別概述 問題定義&#xff1a;自動語音識別&#xff08;ASR&#xff09;、文本到語音合成&#xff08;TTS&#xff09;等相關任務&#xff1a;說話人識別、語音增強、語音分離等語…

MyBatis處理SQL語句映射

基礎MyBatis問題以去看MyBatis基礎。 使用log4j設置日志在控制臺打印SQL語句及其執行信息 也可以使用MyBatis基礎中用的slf4j。 在pom.xml文件中引入log4j坐標依賴 <dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><…

嵌入式硬件篇---麥克納姆輪軌跡偏移

麥克納姆輪的軌跡偏移是機械結構、驅動系統、控制邏輯及外部環境等多因素共同作用的結果&#xff0c;其核心是各輪子的驅動力 / 運動狀態無法按理論模型實現協同&#xff0c;導致車體實際運動與期望軌跡產生偏差。以下是具體影響因素的詳細分析&#xff1a;一、機械結構偏差&am…

C語言安全函數分享

在日常寫程序中有一些功能函數是可以重復使用的&#xff0c;在c語言的標準庫里面也有對應的功能函數&#xff0c;但是那些功能函數有會有小問題然后我就整理了一下對應功能的安全函數的使用。其中前四個函數可以編譯成一個動態庫&#xff0c;然后在項目工程中只需要包含對應的頭…

汽車之家聯合HarmonyOS SDK,深度構建鴻蒙生態體系

汽車之家作為一家領先的汽車互聯網公司&#xff0c;致力于打造服務全球的汽車生態科技平臺&#xff0c;覆蓋"看選買用換"的一站式購車體驗。2023年12月底&#xff0c;汽車之家正式啟動鴻蒙開發&#xff0c;并于2024年年底成功構建了完整的鴻蒙生態體系&#xff0c;涵…

深度學習驅動的訂單簿分析與交易策略優化

訂單簿數據特征與預處理方法 高頻金融數據中&#xff0c;訂單簿&#xff08;Order Book&#xff09;承載著市場參與者的實時交易意圖。不同于K線數據的聚合特性&#xff0c;訂單簿數據具有獨特的時空特征&#xff1a; 多維層級結構&#xff1a;包含不同價格檔位的買賣盤深度信息…

Redis--day9--黑馬點評--分布式鎖(二)

&#xff08;以下所有內容全部來自上述課程&#xff09; 分布式鎖 1. Redisson功能介紹 基于setnx實現的分布式鎖存在下面的問題&#xff1a; 不可重入&#xff1a;同一個線程無法多次獲取同一把鎖不可重試&#xff1a;獲取鎖只嘗試一次就返回false&#xff0c;沒有重試機…

ES入門教程 (python 版)

ES入門教程 1. 創建ES對象from elasticsearch import Elasticsearch # 實例化一個ip為localhost&#xff0c;端口為9200&#xff0c;允許超時一小時的es對象 es Elasticsearch(hosts"localhost",port9200,timeout3600) # 1. 創建 索引 index_name "test"…

Gateway中Forward配置+源碼觀賞

系列文章目錄 文章目錄系列文章目錄一、ForwardPathFilter二、RouteToRequestUrlFilter三、ForwardRoutingFilteryaml forward配置gateway:routes:- id: user-route # uri: lb://useruri: forward:///user/indexpredicates:- Path/user/**- YoGET # filt…

BAS16XV2T1G ON安森美半導體 高速開關二極管 電子元器件IC

BAS16XV2T1G ON Semiconductor 高速開關二極管專業解析1. 產品技術檔案BAS16XV2T1G是安森美半導體(ON Semiconductor)推出的高速開關二極管&#xff0c;采用SOT-523超微型封裝&#xff08;1.60.80.95mm&#xff09;&#xff0c;專為現代高密度電子設備設計&#xff0c;以其超快…

親測可用 [安卓]《神秘來電》V1.1無需登入無廣告離線打開即用手機模擬發起虛假來電免費版

神秘來電是一款可以模擬虛擬電話的應用程序&#xff0c;它能夠在用戶需要的時候模擬各種來電&#xff0c;以便用戶能夠在尷尬的場合脫身。用戶可以預設多個不同的來電號碼和鈴聲&#xff0c;并可隨時觸發這些虛擬電話&#xff0c;在特殊情況下幫助用戶擺脫尷尬。它為那些社交恐…

8.20 dp

lc73矩陣置零queue隊列標記// 整行置零for(int y0; y<n; y) matrix[i][y] 0; // 整列置零for(int x0; x<m; x) matrix[x][j] 0; class Solution { public:void setZeroes(vector<vector<int>>& matrix) {int m matrix.size(), n matrix[0].size();//…

STL庫——string(類模擬實現)

? ? ? ? ? づ?ど &#x1f389; 歡迎點贊支持&#x1f389; 個人主頁&#xff1a;勵志不掉頭發的內向程序員&#xff1b; 專欄主頁&#xff1a;C語言&#xff1b; 文章目錄 前言 一、基本框架 二、構造函數 三、析構函數 四、拷貝構造 五、運算符重載 5.1、賦值重載 5.2…

Linux I/O 多路復用實戰:深入剖析 Select 與 Poll

## 引言:從“阻塞”的餐廳到“事件驅動”的盛宴 想象一下,你是一家小餐館的服務員。餐廳只有5張桌子。你的工作流程是這樣的:走到1號桌,問他們是否要點菜,然后站在那里等他們決定;等他們點完,再去2號桌,同樣站在那里等... 如果1號桌的客人看菜單看了半個小時,那么其他…