【JavaEE進階】Spring AOP使用篇

目錄

1.AOP概述

2.SpringAOP快速入門

2.1 引入AOP依賴

2.2 編寫AOP程序

3. Spring AOP詳解

3.1 Spring AOP 核心概念

3.1.1切點(Pointcut)

3.1.2 連接點 (Join Point)

3.1.3 通知(Advice)

3.1.4 切面(Aspect)

3.2 通知類型

3.3@PointCut

3.4 切面優先級

3.5 切點表達式

3.5.1 execution 表達式

3.5.2 @annotation

3.5.2.1 自定義注解 @MyAspect

3.5.2.2 切面類

3.5.2.3 添加自定義注解

4. Spring AOP的實現方式


1.AOP概述

AOP是Spring框架的一大核心(第一大核心是loC)

什么是AOP?

Aspect Oriented Programming(面向切面編程)

什么是面向切面編程呢?切面就是指某一類特定問題, 所以 AOP 也可以理解為面向特定方法編程.

什么是面向特定方法編程呢? 比如以前學習的"登錄校驗", 就是一類特定問題.? 登錄校驗攔截器, 就
是對 "登錄校驗" 這類問題的統一處理. 所以,攔截器也是 AOP 的一種應用. AOP 是一種思想,攔截器是 AOP 思想的一種實現. Spring 框架實現了這種思想,? 提供了攔截器技術的相關接口.

同樣的, 統一數據返回格式和統一異常處理,也是AOP思想的一種實現.

簡單來說:? AOP是一種思想,是對某一類事情的集中處理.
?

什么是 Spring AOP ?

AOP是一種思想,它的實現方法有很多,有Spring AOP, 也有AspectJ, CGLIB等.

Spring AOP是其中的一種實現方式.

學會了統一功能之后,是不是就學會了Spring AOP呢,當然不是.

截器作用的維度是URL(一次請求和響應), @ControllerAdvice 應用場景主要是全局異常處理
(配合自定義異常效果更佳), 數據綁定 , 數據預處理.? AOP 作用的維度更加細致(可以根據包、類、方法名、參數等進行攔截),? 能夠實現更加復雜的業務邏輯.

舉個例子:

我們現在有一個項目, 項目中開發了很多的業務功能

現在有一些業務的執行效率比較低, 耗時較長, 我們需要對接口進行優化.

第一步就需要定位出執行耗時比較長的業務方法, 在針對該業務方法來進行優化

如何定位呢? 我們就需要統計當前項目中每一個業務方法的執行耗時.

如何統計呢? 可以在業務方法運行前和運行后,? 記錄下方法的開始時間和結束時間, 兩者之差就是這個方法的耗時.?

這種方法是可以解決問題的,但一個項目中會包含很多業務模塊,每個業務模塊又有很多接口,一個接口又包含很多方法, 如果我們要在每個業務方法中都記錄方法的耗時,對于程序員而言, 會增加很多的工作量.

AOP 就可以做到在不改動這些原始方法的基礎上, 針對特定的方法進行功能的增強.

AOP 的作用: 在程序執行期間不修改源代碼的基礎上對已有方法的增強(無侵入性: 解耦)

接下來我們來看看 SpringAOP 如何來實現.

2.SpringAOP快速入門

學習完什么是 AOP 后, 我們先通過下面的程序體驗下 AOP 的開發, 并掌握 Spring 中 AOP 的開發步驟.

需求: 統計圖書系統中各個接口方法的執行時間.

2.1 引入AOP依賴

在 pom.xml 文件中添加配置

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.2 編寫AOP程序

記錄 Controller 中每個方法的執行時間

先看看傳統的方法:

/*** 根據ID查詢圖書信息** @param bookId* @return*/@RequestMapping("/queryBookById")public BookInfo queryBookById(Integer bookId) {log.info("根據ID查詢圖書信息, id:{}", bookId);long start = System.currentTimeMillis();BookInfo bookInfo = bookService.queryBookById(bookId);long end = System.currentTimeMillis();log.info("[BookController] queryBookById 耗時: " + (end-start) + " ms");return bookInfo;}

使用這種方式, 當要測試多個接口的時候, 就需要對每個接口的代碼進行修改?, 工作量比較復雜, 很影響我們的時間和效率.

下面來看看使用AOP的代碼吧:

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;@Component
@Slf4j
@Aspect
public class TimeRecordAspect {/*** 記錄耗時*/@Around("execution(* com.example.demo.controller.*.*(..))")public Object TimeRecord(ProceedingJoinPoint joinPoint) throws Throwable {//記錄開始事件long start = System.currentTimeMillis();//執行目標方法Object proceed = joinPoint.proceed();//記錄結束時間long end = System.currentTimeMillis();//日志打印耗時log.info(joinPoint.getSignature() + " 耗時時間: " + (end- start) + " ms");return proceed;}
}

運行程序, 觀察日志

對程序進行簡單的講解:

1. @Aspect: 標識這是一個切面類

2. @Around:?環繞通知, 在目標方法的前后都會被執行. 后?的表達式表示對哪些方法進行增強.

3. ProceedingJoinPoint.proceed(): 讓原始方法執行

整個代碼劃分為三部分

我們通過AOP入門程序完成了業務接口執行耗時的統計.

通過上面的程序,我們也可以感受到AOP面向切面編程的一些優勢:

  • 代碼無侵入: 不修改原始的業務方法, 就可以對原始的業務方法進行了功能的增強或者是功能的改變
  • 減少了重復代碼
  • 提高開發效率
  • 維護方便
    ?

3. Spring AOP詳解

下面我門再來詳細學習AOP, 主要是一下幾個部分

Spring AOP 中涉及的核心概念

Spring AOP 的通知類型

多個 AOP 的執行順序

3.1 Spring AOP 核心概念

3.1.1切點(Pointcut)

切點(Pointcut), 也稱之為 "切入點"

Pointcut 的作用就是提供一組規則(使用 AspectJ pointcut expression language 來描述), 告訴程序對哪些方法來進行功能增強.

上面的表達式??execution(* com.example.demo.controller.*.*(..)) 就是切點表達式.

3.1.2 連接點 (Join Point)

滿足切點表達式規則的方法, 就是連接點, 也就是可以被 AOP 控制的方法

以如門程序舉例, 所有?com.example.demo.controller 路徑下的方法, 都是連接點

package com.example.demo.controller;@RequestMapping("/book")
@RestController
public class BookController {@RequestMapping("/addBook")public Result addBook(BookInfo bookInfo) {//...代碼省略 }@RequestMapping("/queryBookById")public BookInfo queryBookById(Integer bookId) {//...代碼省略 }@RequestMapping("/updateBook")public Result updateBook(BookInfo bookInfo) {//...代碼省略 }
}

上述 BookController 中的方法都是連接點

切點和連接點的關系

連接點是滿足切點表達式的元素, 切點可以看作是保存了眾多連接點的一個集合.

比如:

切點表達式: 全體教師

連接點就是: 張三, 李四等各個教室

3.1.3 通知(Advice)

通知就是具體要做的事情, 指哪些重復的邏輯, 也就是共性功能(最終體現為一個方法)

比如上述程序中記錄業務方法的耗時時間, 就是通知

在AOP面向切面編程當中, 我門把這部分重復的代碼邏輯抽取出來單獨定義, 這部分代碼就是通知類容.

3.1.4 切面(Aspect)

切面(Aspect) = 切點(Pointcut) + 通知(Advice)

通過切面就能描述當前AOP程序需要針對于哪些方法, 在什么時候執行什么樣的操作.

切面既包含了通知邏輯的定義, 也包括了連接點的定義.

切面所在的類, 我們一般稱為切面類(被@Aspect注解標識的類)

3.2 通知類型

上面我們講了什么是通知, 接下來學習通知的類型. @Around 就是其中的一種通知類型, 表示環繞通知.

Spring 中 AOP 的通知類型有一下幾種:

@Around: 環繞通知, 次注解標注的通知方法在目標方法前, 后都被執行

@Before: 前置通知, 次注解表述的通知方法在目標方法前被執行

@After: 后置通知, 次注解標注的通知方法在目標方法后被執行, 無論是否有異常都會執行

@AfterReturning: 返回后通知, 次注解標注的通知方法在目標方法返回后被執行, 有異常不會執行

@AfterThrowing: 次注解標注的通知方法發生異常后執行

接下來我門通過代碼來加深對這幾個通知的理解:

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Component
@Slf4j
@Aspect
public class AspectDemo {//前置通知@Before("execution(* com.example.aop.controller.*.*(..))")public void doBefore() {log.info("AspectDemo do before...");}//后置通知@After("execution(* com.example.aop.controller.*.*(..))")public void doAfter() {log.info("AspectDemo do after...");}//環繞通知@Around("execution(* com.example.aop.controller.*.*(..))")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {log.info("AspectDemo do around before...");Object result = null;try {result = joinPoint.proceed();}catch (Exception e) {log.error("do around 執行目標函數, 內部發生異常");}log.info("AspectDemo do around after...");return result;}//返回后通知@AfterReturning("execution(* com.example.aop.controller.*.*(..))")public void doAfterReturning() {log.info("AspectDemo do AfterReturning...");}//拋出異常后通知@AfterThrowing("execution(* com.example.aop.controller.*.*(..))")public void doAfterThrowing() {log.info("AspectDemo do AfterThrowing...");}
}

寫一些測試程序:

import com.example.aop.config.MyAspect;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/test")
@RestController
@Slf4j
public class TestController {@MyAspect@RequestMapping("/t1")public String t1() {log.info("執行t1方法....");return "t1";}@RequestMapping("/t2")public String t2() {log.info("執行t2方法....");int a = 10/0;return "t2";}
}

運行程序, 觀察日志:

1.正常運行的情況

觀察日志

程序正常運行的情況下, @AfterThrowing 標識的通知方法不會執行

從上圖也可以看出來, @Around 標識的通知方法包含兩個部分, 一個 "前置邏輯" , 一個 "后置邏輯" .其中 "前置邏輯" 會先于 @Before 標識的通知方法執行. "后置邏輯" 會晚于 @After 標識的通知方法執行

2. 異常時的情況

觀察日志

程序發生異常的情況下:

@AfterReturning 標識的通知方法不會執行, @AfterThrowing?標識的通知方法執行了

@Around 環繞通知中原始方法調用時有異常, 通知中的環繞后的代碼也不會在執行了(因為原始方法調用出異常了)

注意事項:

@Around 環繞通知需要調用 ProceedingJoinPoint.proceed() 來讓原始方法執行, 其他通知不需要考慮目標方法執行.

@Around環繞通知方法的返回值, 必須指定為Object , 來接收原始方法的返回值, 否則原始方法執行完畢, 是獲取不到返回值的.

一個切面類可以有多個切點

3.3@PointCut

上面代碼存在一個問題, 就是存在大量重復的切點表達式 execution(* com.example.demo.controller.*.*(..)) , Spring 提供了 @Pointcut 注解, 把公共的切點表達式提取出來, 需要用到時引入該切點表達式即可.

上述代碼就可以修改為:

@Component
@Slf4j
@Aspect
public class AspectDemo {@Pointcut("execution(* com.example.aop.controller.*.*(..))")public void pt(){};//前置通知@Before("pt()")public void doBefore() {//...代碼省略}//后置通知@After("pt()")public void doAfter() {//...代碼省略}//添加環繞通知@Around("pt()")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {//...代碼省略}//返回后通知@AfterReturning("pt()")public void doAfterReturning() {//...代碼省略}//拋出異常后通知@AfterThrowing("pt()")public void doAfterThrowing() {//...代碼省略}
}

當請切點使用 private 修飾時, 僅能在當前切面類中使用, 當其他切面類也要使用當前切點定義時, 就需要把 private 改為 public, 引用方式為: 全限定類名.方法名()

@Component
@Slf4j
@Aspect
public class AspectDemo2 {@Before("com.example.aop.aspect.AspectDemo.pt()")public void doBefore() {log.info("AspectDemo2 do before...");}@After("com.example.aop.aspect.AspectDemo.pt()")public void doAfter() {log.info("AspectDemo2 do after...");}
}

3.4 切面優先級

當我們在一個項目中,定義了多個切面類時,并且這些切面類的多個切入點都匹配到了同一個目標方法. 當目標方法運行的時候,這些切面類中的通知方法都會執行,那么這幾個通知方法的執行順序是什么樣的呢?

我們還是通過程序來驗證:

定義多個切?類:

為了防止干擾, 我們把AspectDemo這個切面先去掉(把@Component注解去掉就可以)

為了簡單化, 只寫了@Before 和 @After 兩個通知

@Component
@Slf4j
@Aspect
public class AspectDemo2 {@Before("com.example.aop.aspect.AspectDemo.pt()")public void doBefore() {log.info("AspectDemo2 do before...");}@After("com.example.aop.aspect.AspectDemo.pt()")public void doAfter() {log.info("AspectDemo2 do after...");}
}
@Component
@Slf4j
@Aspect
public class AspectDemo3 {@Before("com.example.aop.aspect.AspectDemo.pt()")public void doBefore() {log.info("AspectDemo3 do before...");}@After("com.example.aop.aspect.AspectDemo.pt()")public void doAfter() {log.info("AspectDemo3 do after...");}
}
@Component
@Slf4j
@Aspect
public class AspectDemo4 {@Before("com.example.aop.aspect.AspectDemo.pt()")public void doBefore() {log.info("AspectDemo4 do before...");}@After("com.example.aop.aspect.AspectDemo.pt()")public void doAfter() {log.info("AspectDemo4 do after...");}
}

運行程序, 訪問接口:

?觀察日志:

通過上述程序的運行結果, 可以看出:

存在多個切面類時, 默認按照切面類的名字母排序:

  • @Before 通知: 字母名字靠前的先執行
  • @After 通知: 字母排名靠前的后執行

但這種方式不方便管理,我們的類名更多還是具備一定含義的.

Spring給我們提供了一個新的注解,來控制這些切面通知的執行順序: @Order

使用方式如下:

重新運行程序, 觀察日志:

通過上述程序的運行結果, 得出結論:

@Order 注解標識的切面類, 執行順序如下:

@Before 通知: 數字越小先執行

@After 通知: 數字越大先執行

@Order 控制切面的優先級, 先執行優先級高的切面, 在執行優先級較低的切面, 最終執行目標方法.

3.5 切點表達式

上面的代碼中,我們一直在使用切點表達式來描述切點. 下面我們來介紹一下切點表達式的語法.

切點表達式常見有兩種表達方式

1. execution(......): 根據方法的簽名來匹配

2. @annotation(......): 根據注解匹配

3.5.1 execution 表達式

execution() 是最常用的切點表達式, 用來匹配方法, 語法為:

其中: 訪問修飾符和異常可以省略

切點表達式支持通配符表達:

1. *?: 匹配任意字符, 只匹配一個元素(返回類型, 包, 類名, 方法或者方法參數)

a. 包名使用?*?表示任意包(一層包使用一個 * )

b. 類名使用?*?表示任意類

c. 返回值使用?*?表示任意返回值類型

d. 方法名使用 *?表示任意方法

e. 參數使用 *?表示一個任意類型的參數

2. .. : 匹配多個連續的任意符號, 可以通配任意層級的包, 或任意類型, 任意個數的參數

a. 使用 .. 配置包名, 標識次包以及此包下的所有子包

b. 可以使用 .. 配置參數, 任意個任意類型的參數

切點表達式示例

TestController 下的 public 修飾, 返回類型為 String 方法名為 t1, 無參方法

execution(public String com.example.demo.controller.TestController.t1())

省略訪問修飾符

execution(String com.example.demo.controller.TestController.t1())

匹配所有返回類型

execution(* com.example.demo.controller.TestController.t1())

匹配 TestController 下的所有無參方法

execution(* com.example.demo.controller.TestController.*())

匹配 TestController 下的所有方法

execution(* com.example.demo.controller.TestController.*(..))

匹配 controller 包下所有的類的所有方法

execution(* com.example.demo.controller.*.*(..))

匹配所有包下面的 TestController

execution(* com..TestController.*(..))

匹配 com.example.demo 包下, 子孫包下的所有類的所有方法

execution(* com.example.demo..*(..))

匹配特定方法名且有特定參數的方法:

execution(* myMethod(String, int))

?匹配特定方法名且有特定參數, 并且拋出特定異常的方法

execution(* myMethod(String, int) throws IOExeception)

3.5.2 @annotation

execution 表達式更適合有規則的, 如果我門要匹配多個無規則的方法呢, 比如: TestController中的 t1() 和 UserController 中的 u1() 這兩個方法.

這個時候我們使用 execution 這種切點表達式來描述就不是很方便了.

我們可以借助自定義注解的方法以及另一種切點表達式 @annotation 來描述這一類的切點

實現步驟:

1. 編寫自定義注解

2. 使用 @annotation 表達式來描述切點

3. 在連接點的方法上添加自定義注解

準備測試代碼

@RequestMapping("/test")
@RestController
@Slf4j
public class TestController {@RequestMapping("/t1")public String t1() {log.info("執行t1方法....");return "t1";}@RequestMapping("/t2")public String t2() {log.info("執行t2方法....");int a = 10/0;return "t2";}
}
@Slf4j
@RequestMapping("/user")
@RestController
public class UserController{@RequestMapping("/u1")public String u1() {log.info("執行u1方法...");return "u1";}@RequestMapping("/u2")public String u2() {log.info("執行u2方法...");return "u2";}
}
3.5.2.1 自定義注解 @MyAspect

創建一個注解類(和創建Class文件一樣的流程, 選擇Annotation就可以了)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAspect {}

代碼簡單說明, 了解即可, 不做過多的解釋

1. @Target 標識了 Annotation 所修飾的對象范圍, 及該注解可以用在什么地方.

常用取值:?

ElementType.TYPE: 用于描述類, 接口(包括注解類型)或 enum 聲明

ElementType.METHOD: 描述方法

ElementType.PARAMETER: 描述參數

ElementType.TYPE_USE: 可以標注任意類型

2. @Retention 指 Annotation 被保留的時間長短, 標明注解的聲明周期

@Retention的取值有三種

1. RetentionPolicy.SOURCE: 表示注解僅存在于源代碼中,編譯成字節碼后會被丟棄. 這意味著在運行時無法獲取到該注解的信息,? 只能在編譯時使用.? 比如@SuppressWarnings,? 以及lombok? 提供的注解?@Data, @Slf4j

2.?RetentionPolicy.CLASS: 編譯時注解. 表示注解存在于源代碼和字節碼中,但在運行時會被丟棄. 這意味著在編譯時和字節碼中可以通過反射獲取到該注解的信息,? 但在實際運行時無法獲取. 通常用于一些框架和工具的注解.

3.?RetentionPolicy.RUNTIME: 運行時注解. 表示注解存在于源代碼,字節碼和運行時中. 這意味著在編譯時,字節碼中和實際運行時都可以通過反射獲取到該注解的信息. 通常用于一些需要在運行時處理的注解,如Spring的 @Controller @ResponseBody

3.5.2.2 切面類

使用 @annotation 切點表達式定義切點, 只對 @MyAspect 生效

切面類代碼如下:

@Component
@Slf4j
@Aspect
public class MyAspectDemo {//前置通知@Before("@annotation(com.example.aop.config.MyAspect)")public void before() {log.info("MyAspect -> before...");}//后置通知@After("@annotation(com.example.aop.config.MyAspect)")public void after() {log.info("MyAspect -> after...");}
}
3.5.2.3 添加自定義注解

在 TestController 中 t1() 和 UserController 中的 u1() 這兩個方法上添加自定義注解 @MyAspect, 其他方法不加

運行程序, 測試接口:

觀察日志:

繼續測試 t2, 觀察日志:

切面通知未執行

4. Spring AOP的實現方式

1.基于注解 @Aspect

2. 基于自定義注解(參考上面自定義注解 @annotation 部分的內容)

3. 基于Spring API (通過xml配置的方法, 自從SpringBoot廣泛使用之后, 這種方法幾乎看不到了, 稍作了解即可)

4. 基于代理來實現(更加久遠的一種方式, 寫法笨重, 不建議使用)

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

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

相關文章

基于經典滑膜控制的永磁同步電機調速系統MATLAB仿真

滑膜控制器 取PMSM狀態變量為&#xff1a; ωref為目標轉速&#xff0c;ωm為電機輸出轉速。將此式求導得&#xff1a; 定義系統滑模面函數為&#xff1a; 對滑模面函數求導 在電機實際控制時&#xff0c;滑模控制方法存在高頻抖振問題&#xff0c;則需要選取合適的指數趨近率…

web前端——css(一篇教會網頁制作)

目錄 一、基本語法 1.行內樣式表 2.內嵌樣式表 3.外部樣式表 二、選擇器 1.標簽選擇器 2.類選擇器 3.id 選擇器 4.通配選擇器 三、常見修飾 1.文本 2.背景 3.列表 4.偽類 5.透明度 6.塊級、行級、行級塊標簽 7.div 和 span 四、盒子模型&#xff08;重點&…

【PostgreSQL】守護數據安全:事務與數據完整性管理

目錄 事務管理&#xff1a;確保操作的原子性 事務的概念與重要性 事務的啟動與提交 事務的回滾&#xff08;ROLLBACK&#xff09;&#xff08; 數據一致性與隔離級別 隔離級別的解釋 設置隔離級別 錯誤處理與事務的高級策略 異常處理&#xff08;SAVEPOINT & EXCE…

25屆最近5年重慶郵電大學自動化考研院校分析

重慶郵電大學 目錄 一、學校學院專業簡介 二、考試科目指定教材 三、近5年考研分數情況 四、近5年招生錄取情況 五、最新一年分數段圖表 六、歷年真題PDF 七、初試大綱復試大綱 八、學費&獎學金&就業方向 一、學校學院專業簡介 二、考試科目指定教材 1、考試…

[數據集][目標檢測]電纜鋼絲繩線纜缺陷檢測數據集VOC+YOLO格式1800張3類別

數據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件) 圖片數量(jpg文件個數)&#xff1a;1800 標注數量(xml文件個數)&#xff1a;1800 標注數量(txt文件個數)&#xff1a;1800 標注…

單例模式(下)

文章目錄 文章介紹步驟安排及單例講解step1&#xff1a;注冊單例類型&#xff08;main.cpp&#xff09;step2&#xff1a;定義類和私有構造函數&#xff08;keyboardinputmanager.h&#xff09;step3:&#xff08;keyboardinputmanager.cpp&#xff09;step4&#xff1a;在qml中…

雷卯一站式解決電子設備靜電浪涌與接口安全

在快速演進的數字時代&#xff0c;電子設備不僅是日常生活的核心&#xff0c;更是工業自動化、智能穿戴、智能家居乃至未來交通的基石。然而&#xff0c;隨著技術邊界的不斷拓展&#xff0c;設備面臨的挑戰也日益嚴峻&#xff0c;尤其是來自靜電放電(ESD)、浪涌沖擊及電磁干擾的…

【2024最新華為OD-C/D卷試題匯總】[支持在線評測] 特殊加密算法(200分) - 三語言AC題解(Python/Java/Cpp)

&#x1f36d; 大家好這里是清隆學長 &#xff0c;一枚熱愛算法的程序員 ? 本系列打算持續跟新華為OD-C/D卷的三語言AC題解 &#x1f4bb; ACM銀牌&#x1f948;| 多次AK大廠筆試 &#xff5c; 編程一對一輔導 &#x1f44f; 感謝大家的訂閱? 和 喜歡&#x1f497; &#x1f…

Rust 跨平臺-Android 和鴻蒙 OS

1. 安裝 rustup rustup 是 Rust 的安裝和版本管理工具 $ curl --proto https --tlsv1.2 https://sh.rustup.rs -sSf | sh 該命令會安裝 rusup 和最新的穩定版本的 Rust&#xff1b;包括&#xff1a; rustc Rust 編譯器&#xff0c;用于將 Rust 代碼編譯成可執行文件或庫。 ca…

技術速遞|Visual Studio Code 的 .NET MAUI 擴展現已正式發布

作者&#xff1a;Maddy Montaquila 排版&#xff1a;Alan Wang 今天&#xff0c;我們非常高興地宣布 .NET MAUI VS Code 擴展插件結束了預覽階段&#xff0c;并將包含一些期待已久的新功能 - 包括 XAML IntelliSense 和 Hot Reload&#xff01; 什么是 .NET MAUI 擴展插件&…

GuLi商城-商品服務-API-三級分類-刪除-頁面效果

一步步學習Vue太慢了&#xff0c;準備跳過前端的學習&#xff0c;直接使用前端完整的項目 下載依賴npm install&#xff0c;會報錯&#xff0c;排查了好久 我安裝的是Node14&#xff0c;所以必須要安裝4.14 Vscode終端輸入&#xff1a;npm install node-sass4.14 輸入&#x…

【Android面試八股文】如果需要在Activity間傳遞大量的數據怎么辦?

文章目錄 1. 使用Intent傳遞數據2. 使用靜態變量3. 使用Parcelable或Serializable接口4. 使用文件5. 使用數據庫存儲6. 使用ContentProvider7. 匿名共享內存(Ashmem)總結在Android開發中,如果需要在Activity之間傳遞大量數據,可以采取以下幾種方法: 1. 使用Intent傳遞數據…

【博士每天一篇文獻-綜述】A survey on few-shot class-incremental learning

閱讀時間&#xff1a;2023-12-19 1 介紹 年份&#xff1a;2024 作者&#xff1a;田松松&#xff0c;中國科學院半導體研究所&#xff1b;李璐思&#xff0c;老道明大學助理教授&#xff1b;李偉軍&#xff0c;中國科學院半導體研究所AnnLab&#xff1b; 期刊&#xff1a; Neu…

LearnOpenGL - Android OpenGL ES 3.0 使用 FBO 進行離屏渲染

系列文章目錄 LearnOpenGL 筆記 - 入門 01 OpenGLLearnOpenGL 筆記 - 入門 02 創建窗口LearnOpenGL 筆記 - 入門 03 你好&#xff0c;窗口LearnOpenGL 筆記 - 入門 04 你好&#xff0c;三角形OpenGL - 如何理解 VAO 與 VBO 之間的關系LearnOpenGL - Android OpenGL ES 3.0 繪制…

《Windows API每日一練》6.4 程序測試

前面我們討論了鼠標的一些基礎知識&#xff0c;本節我們將通過一些實例來講解鼠標消息的不同處理方式。 本節必須掌握的知識點&#xff1a; 第36練&#xff1a;鼠標擊中測試1 第37練&#xff1a;鼠標擊中測試2—增加鍵盤接口 第38練&#xff1a;鼠標擊中測試3—子窗口 第39練&…

3.imput 字符串常用方法 字符串倒序,切片

1.input input()函數接收一個標準輸入數據返回string類型 2.字符串常用方法 upper()將字符串中的小寫字母變為大寫 lower()大寫變小寫 len()獲取長度 count(子字符串)統計某個字符出現的次數 index(子字符串)可以返回子字符串出現的位置, rindex從右邊找 find(子字符串)可以返回…

vite-ts-cesium項目集成mars3d修改相關的包和配置參考

如果vite技術棧下使用原生cesium&#xff0c;請參考下面文件的包和配置修改&#xff0c;想用原生創建的viewer結合我們mars3d的功能的話。 1. package.json文件 "dependencies": {"cesium": "^1.103.0","mars3d": "^3.7.18&quo…

重啟ubuntu后命令行出現(initramfs),無圖形界面問題。

由于ubuntu內部軟件問題&#xff0c;需要重啟ubuntu&#xff0c;導致重啟后圖像界面消失&#xff0c;出現如下的命令行&#xff1a; (initramfs): 這里表示進入圖形界面初始化時&#xff0c;某個分區的文件損壞&#xff0c;損壞文件名稱會在上方顯示。 解決方法&#xff1a;…

深度學習 - Transformer 組成詳解

整體結構 1. 嵌入層&#xff08;Embedding Layer&#xff09; 生活中的例子&#xff1a;字典查找 想象你在讀一本書&#xff0c;你不認識某個單詞&#xff0c;于是你查閱字典。字典為每個單詞提供了一個解釋&#xff0c;幫助你理解這個單詞的意思。嵌入層就像這個字典&#xf…

Micrometer+ZipKin分布式鏈路追蹤

目錄 背景MicrometerMicrometer與ZipKin之間的關系專業術語分布式鏈路追蹤原理 ZipKin安裝下載 MicrometerZipKin 案例演示相關文獻 背景 一個系統頁面上的按鈕點擊到結果反饋&#xff0c;在微服務框架里&#xff0c;是由N個服務組成返回結果&#xff0c;中間可能經過a->b-…