主頁 > 後端開發 > 9,000+ 字,徹底征服 Spring AOP!

9,000+ 字,徹底征服 Spring AOP!

2021-03-03 18:14:37 後端開發

基本知識

其實, 接觸了這么久的 AOP, 我感覺, AOP 給人難以理解的一個關鍵點是它的概念比較多, 而且坑爹的是, 這些概念經過了中文翻譯后, 變得面目全非, 相同的一個術語, 在不同的翻譯下, 含義總有著各種莫名其妙的差別. 鑒于此, 我在本章的開頭, 著重為為大家介紹一個 Spring AOP 的各項術語的基本含義,

為了術語傳達的準確性, 我在接下來的敘述中, 能使用英文術語的地方, 盡量使用英文,

什么是 AOP

AOP(Aspect-Oriented Programming), 即 面向切面編程, 它與 OOP( Object-Oriented Programming, 面向物件編程) 相輔相成, 提供了與 OOP 不同的抽象軟體結構的視角,

在 OOP 中, 我們以類(class)作為我們的基本單元, 而 AOP 中的基本單元是 Aspect(切面)

術語

Aspect(切面)

aspectpointcountadvice 組成, 它既包含了橫切邏輯的定義, 也包括了連接點的定義. Spring AOP就是負責實施切面的框架, 它將切面所定義的橫切邏輯織入到切面所指定的連接點中,

AOP的作業重心在于如何將增強織入目標物件的連接點上, 這里包含兩個作業:

  1. 如何通過 pointcut 和 advice 定位到特定的 joinpoint 上
  2. 如何在 advice 中撰寫切面代碼.

可以簡單地認為, 使用 @Aspect 注解的類就是切面,

advice(增強)

由 aspect 添加到特定的 join point(即滿足 point cut 規則的 join point) 的一段代碼,

許多 AOP框架, 包括 Spring AOP, 會將 advice 模擬為一個攔截器(interceptor), 并且在 join point 上維護多個 advice, 進行層層攔截,

例如 HTTP 鑒權的實作, 我們可以為每個使用 RequestMapping 標注的方法織入 advice, 當 HTTP 請求到來時, 首先進入到 advice 代碼中, 在這里我們可以分析這個 HTTP 請求是否有相應的權限, 如果有, 則執行 Controller, 如果沒有, 則拋出例外. 這里的 advice 就扮演著鑒權攔截器的角色了,

連接點(join point)

a point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution.

程式運行中的一些時間點, 例如一個方法的執行, 或者是一個例外的處理,

在 Spring AOP 中, join point 總是方法的執行點, 即只有方法連接點,

切點(point cut)

匹配 join point 的謂詞(a predicate that matches join points),

Advice 是和特定的 point cut 關聯的, 并且在 point cut 相匹配的 join point 中執行,

在 Spring 中, 所有的方法都可以認為是 joinpoint, 但是我們并不希望在所有的方法上都添加 Advice, 而 pointcut 的作用就是提供一組規則(使用 AspectJ pointcut expression language 來描述) 來匹配joinpoint, 給滿足規則的 joinpoint 添加 Advice,

關于join point 和 point cut 的區別

在 Spring AOP 中, 所有的方法執行都是 join point. 而 point cut 是一個描述資訊, 它修飾的是 join point, 通過 point cut, 我們就可以確定哪些 join point 可以被織入 Advice. 因此 join point 和 point cut 本質上就是兩個不同緯度上的東西,

advice 是在 join point 上執行的, 而 point cut 規定了哪些 join point 可以執行哪些 advice,

introduction

為一個型別添加額外的方法或欄位. Spring AOP 允許我們為 目標物件 引入新的介面(和對應的實作). 例如我們可以使用 introduction 來為一個 bean 實作 IsModified 介面, 并以此來簡化 caching 的實作,

目標物件(Target)

織入 advice 的目標物件. 目標物件也被稱為 advised object

因為 Spring AOP 使用運行時代理的方式來實作 aspect, 因此 adviced object 總是一個代理物件(proxied object),

注意, adviced object 指的不是原來的類, 而是織入 advice 后所產生的代理類,

AOP proxy

一個類被 AOP 織入 advice, 就會產生一個結果類, 它是融合了原類和增強邏輯的代理類,

在 Spring AOP 中, 一個 AOP 代理是一個 JDK 動態代理物件或 CGLIB 代理物件,

織入(Weaving)

將 aspect 和其他物件連接起來, 并創建 adviced object 的程序,

根據不同的實作技術, AOP織入有三種方式:

  • 編譯器織入, 這要求有特殊的Java編譯器.
  • 類裝載期織入, 這需要有特殊的類裝載器.
  • 動態代理織入, 在運行期為目標類添加增強(Advice)生成子類的方式.
    Spring 采用動態代理織入, 而AspectJ采用編譯器織入和類裝載期織入.

advice 的型別

  • before advice, 在 join point 前被執行的 advice. 雖然 before advice 是在 join point 前被執行, 但是它并不能夠阻止 join point 的執行, 除非發生了例外(即我們在 before advice 代碼中, 不能人為地決定是否繼續執行 join point 中的代碼)
  • after return advice, 在一個 join point 正常回傳后執行的 advice
  • after throwing advice, 當一個 join point 拋出例外后執行的 advice
  • after(final) advice, 無論一個 join point 是正常退出還是發生了例外, 都會被執行的 advice.
  • around advice, 在 join point 前和 joint point 退出后都執行的 advice. 這個是最常用的 advice.

關于 AOP Proxy

Spring AOP 默認使用標準的 JDK 動態代理(dynamic proxy)技術來實作 AOP 代理, 通過它, 我們可以為任意的介面實作代理,

如果需要為一個類實作代理, 那么可以使用 CGLIB 代理,當一個業務邏輯物件沒有實作介面時, 那么Spring AOP 就默認使用 CGLIB 來作為 AOP 代理了. 即如果我們需要為一個方法織入 advice, 但是這個方法不是一個介面所提供的方法, 則此時 Spring AOP 會使用 CGLIB 來實作動態代理. 鑒于此, Spring AOP 建議基于介面編程, 對介面進行 AOP 而不是類,

徹底理解 aspect, join point, point cut, advice

看完了上面的理論部分知識, 我相信還是會有不少朋友感覺到 AOP 的概念還是很模糊, 對 AOP 中的各種概念理解的還不是很透徹. 其實這很正常, 因為 AOP 中的概念是在是太多了, 我當時也是花了老大勁才梳理清楚的.
下面我以一個簡單的例子來比喻一下 AOP 中 aspect, jointpoint, pointcut 與 advice 之間的關系,

讓我們來假設一下, 從前有一個叫爪哇的小縣城, 在一個月黑風高的晚上, 這個縣城中發生了命案. 作案的兇手十分狡猾, 現場沒有留下什么有價值的線索. 不過萬幸的是, 剛從隔壁回來的老王恰好在這時候無意中發現了兇手行兇的程序, 但是由于天色已晚, 加上兇手蒙著面, 老王并沒有看清兇手的面目, 只知道兇手是個男性, 身高約七尺五寸. 爪哇縣的縣令根據老王的描述, 對守門的士兵下命令說: 凡是發現有身高七尺五寸的男性, 都要抓過來審問. 士兵當然不敢違背縣令的命令, 只好把進出城的所有符合條件的人都抓了起來,

來讓我們看一下上面的一個小故事和 AOP 到底有什么對應關系,

首先我們知道, 在 Spring AOP 中 join point 指代的是所有方法的執行點, 而 point cut 是一個描述資訊, 它修飾的是 join point, 通過 point cut, 我們就可以確定哪些 join point 可以被織入 Advice. 對應到我們在上面舉的例子, 我們可以做一個簡單的類比, join point 就相當于 爪哇的小縣城里的百姓, point cut 就相當于 老王所做的指控, 即兇手是個男性, 身高約七尺五寸, 而 advice 則是施加在符合老王所描述的嫌疑人的動作: 抓過來審問

為什么可以這樣類比呢?

  • join point --> 爪哇的小縣城里的百姓: 因為根據定義, join point 是所有可能被織入 advice 的候選的點, 在 Spring AOP中, 則可以認為所有方法執行點都是 join point. 而在我們上面的例子中, 命案發生在小縣城中, 按理說在此縣城中的所有人都有可能是嫌疑人.
  • point cut --> 男性, 身高約七尺五寸: 我們知道, 所有的方法(joint point) 都可以織入 advice, 但是我們并不希望在所有方法上都織入 advice, 而 pointcut 的作用就是提供一組規則來匹配joinpoint, 給滿足規則的 joinpoint 添加 advice. 同理, 對于縣令來說, 他再昏庸, 也知道不能把縣城中的所有百姓都抓起來審問, 而是根據兇手是個男性, 身高約七尺五寸, 把符合條件的人抓起來. 在這里 兇手是個男性, 身高約七尺五寸 就是一個修飾謂語, 它限定了兇手的范圍, 滿足此修飾規則的百姓都是嫌疑人, 都需要抓起來審問.
  • advice --> 抓過來審問, advice 是一個動作, 即一段 Java 代碼, 這段 Java 代碼是作用于 point cut 所限定的那些 join point 上的. 同理, 對比到我們的例子中, 抓過來審問 這個動作就是對作用于那些滿足 男性, 身高約七尺五寸爪哇的小縣城里的百姓.
  • aspect: aspect 是 point cut 與 advice 的組合, 因此在這里我們就可以類比: "根據老王的線索, 凡是發現有身高七尺五寸的男性, 都要抓過來審問" 這一整個動作可以被認為是一個 aspect.

或則我們也可以從語法的角度來簡單類比一下. 我們在學英語時, 經常會接觸什么 定語被動句 之類的概念, 那么可以做一個不嚴謹的類比, 即 joinpoint 可以認為是一個 賓語, 而 pointcut 則可以類比為修飾 joinpoint 的定語, 那么整個 aspect 就可以描述為: 滿足 pointcut 規則的 joinpoint 會被添加相應的 advice 操作,

另外,關注公眾號Java技術堆疊,在后臺回復:面試,可以獲取我整理的 Spring 系列面試題和答案,非常齊全,

@AspectJ 支持

@AspectJ 是一種使用 Java 注解來實作 AOP 的編碼風格,

@AspectJ 風格的 AOP 是 AspectJ Project 在 AspectJ 5 中引入的, 并且 Spring 也支持@AspectJ 的 AOP 風格,

使能 @AspectJ 支持

@AspectJ 可以以 XML 的方式或以注解的方式來使能, 并且不論以哪種方式使能@ASpectJ, 我們都必須保證 aspectjweaver.jar 在 classpath 中,

使用 Java Configuration 方式使能@AspectJ

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}

使用 XML 方式使能@AspectJ

<aop:aspectj-autoproxy/>

定義 aspect(切面)

當使用注解 @Aspect 標注一個 Bean 后, 那么 Spring 框架會自動收集這些 Bean, 并添加到 Spring AOP 中, 例如:

@Component
@Aspect
public class MyTest {
}

注意, 僅僅使用@Aspect 注解, 并不能將一個 Java 物件轉換為 Bean, 因此我們還需要使用類似 @Component 之類的注解. 注意, 如果一個 類被@Aspect 標注, 則這個類就不能是其他 aspect 的 advised object 了, 因為使用 @Aspect 后, 這個類就會被排除在 auto-proxying 機制之外,

宣告 pointcut

一個 pointcut 的宣告由兩部分組成:

  • 一個方法簽名, 包括方法名和相關引數
  • 一個 pointcut 運算式, 用來指定哪些方法執行是我們感興趣的(即因此可以織入 advice).

在@AspectJ 風格的 AOP 中, 我們使用一個方法來描述 pointcut, 即:

@Pointcut("execution(* com.xys.service.UserService.*(..))") // 切點運算式
private void dataAccessOperation() {} // 切點前面

這個方法必須無回傳值,

這個方法本身就是 pointcut signature, pointcut 運算式使用@Pointcut 注解指定,

上面我們簡單地定義了一個 pointcut, 這個 pointcut 所描述的是: 匹配所有在包 com.xys.service.UserService 下的所有方法的執行,

切點標志符(designator)

AspectJ5 的切點運算式由標志符(designator)和操作引陣列成. 如 "execution( greetTo(..))" 的切點運算式, execution 就是 標志符, 而圓括號里的 greetTo(..) 就是操作引數,

execution

匹配 join point 的執行, 例如 "execution(* hello(..))" 表示匹配所有目標類中的 hello() 方法. 這個是最基本的 pointcut 標志符,

within

匹配特定包下的所有 join point, 例如 within(com.xys.*) 表示 com.xys 包中的所有連接點, 即包中的所有類的所有方法. 而 within(com.xys.service.*Service) 表示在 com.xys.service 包中所有以 Service 結尾的類的所有的連接點,

this 與 target

this 的作用是匹配一個 bean, 這個 bean(Spring AOP proxy) 是一個給定型別的實體(instance of). 而 target 匹配的是一個目標物件(target object, 即需要織入 advice 的原始的類), 此物件是一個給定型別的實體(instance of),

bean

匹配 bean 名字為指定值的 bean 下的所有方法, 例如:

bean(*Service) // 匹配名字后綴為 Service 的 bean 下的所有方法
bean(myService) // 匹配名字為 myService 的 bean 下的所有方法
args

匹配引數滿足要求的的方法,

例如:

@Pointcut("within(com.xys.demo2.*)")
public void pointcut2() {
}

@Before(value = "https://www.cnblogs.com/javastack/p/pointcut2()  &&  args(name)")
public void doSomething(String name) {
    logger.info("---page: {}---", name);
}
@Service
public class NormalService {
    private Logger logger = LoggerFactory.getLogger(getClass());

    public void someMethod() {
        logger.info("---NormalService: someMethod invoked---");
    }


    public String test(String name) {
        logger.info("---NormalService: test invoked---");
        return "服務一切正常";
    }
}

當 NormalService.test 執行時, 則 advice doSomething 就會執行, test 方法的引數 name 就會傳遞到 doSomething 中,

常用例子:

// 匹配只有一個引數 name 的方法
@Before(value = "https://www.cnblogs.com/javastack/p/aspectMethod()  &&  args(name)")
public void doSomething(String name) {
}

// 匹配第一個引數為 name 的方法
@Before(value = "https://www.cnblogs.com/javastack/p/aspectMethod()  &&  args(name, ..)")
public void doSomething(String name) {
}

// 匹配第二個引數為 name 的方法
Before(value = "https://www.cnblogs.com/javastack/p/aspectMethod()  &&  args(*, name, ..)")
public void doSomething(String name) {
}
@annotation

匹配由指定注解所標注的方法, 例如:

@Pointcut("@annotation(com.xys.demo1.AuthChecker)")
public void pointcut() {
}

則匹配由注解 AuthChecker 所標注的方法,

常見的切點運算式

匹配方法簽名
// 匹配指定包中的所有的方法
execution(* com.xys.service.*(..))

// 匹配當前包中的指定類的所有方法
execution(* UserService.*(..))

// 匹配指定包中的所有 public 方法
execution(public * com.xys.service.*(..))

// 匹配指定包中的所有 public 方法, 并且回傳值是 int 型別的方法
execution(public int com.xys.service.*(..))

// 匹配指定包中的所有 public 方法, 并且第一個引數是 String, 回傳值是 int 型別的方法
execution(public int com.xys.service.*(String name, ..))
匹配型別簽名
// 匹配指定包中的所有的方法, 但不包括子包
within(com.xys.service.*)

// 匹配指定包中的所有的方法, 包括子包
within(com.xys.service..*)

// 匹配當前包中的指定類中的方法
within(UserService)


// 匹配一個介面的所有實作類中的實作的方法
within(UserDao+)
匹配 Bean 名字
// 匹配以指定名字結尾的 Bean 中的所有方法
bean(*Service)
切點運算式組合
// 匹配以 Service 或 ServiceImpl 結尾的 bean
bean(*Service || *ServiceImpl)

// 匹配名字以 Service 結尾, 并且在包 com.xys.service 中的 bean
bean(*Service) && within(com.xys.service.*)

宣告 advice

advice 是和一個 pointcut 運算式關聯在一起的, 并且會在匹配的 join point 的方法執行的前/后/周圍 運行. pointcut 運算式可以是簡單的一個 pointcut 名字的參考, 或者是完整的 pointcut 運算式,

下面我們以幾個簡單的 advice 為例子, 來看一下一個 advice 是如何宣告的.

Before advice

/**
 * @author xiongyongshun
 * @version 1.0
 * @created 16/9/9 13:13
 */
@Component
@Aspect
public class BeforeAspectTest {
    // 定義一個 Pointcut, 使用 切點運算式函式 來描述對哪些 Join point 使用 advise.
    @Pointcut("execution(* com.xys.service.UserService.*(..))")
    public void dataAccessOperation() {
    }
}
@Component
@Aspect
public class AdviseDefine {
    // 定義 advise
    @Before("com.xys.aspect.PointcutDefine.dataAccessOperation()")
    public void doBeforeAccessCheck(JoinPoint joinPoint) {
        System.out.println("*****Before advise, method: " + joinPoint.getSignature().toShortString() + " *****");
    }
}

這里, @Before 參考了一個 pointcut, 即 "com.xys.aspect.PointcutDefine.dataAccessOperation()" 是一個 pointcut 的名字,

如果我們在 advice 在內置 pointcut, 則可以:

@Component
@Aspect
public class AdviseDefine {
    // 將 pointcut 和 advice 同時定義
    @Before("within(com.xys.service..*)")
    public void doAccessCheck(JoinPoint joinPoint) {
        System.out.println("*****doAccessCheck, Before advise, method: " + joinPoint.getSignature().toShortString() + " *****");
    }
}

around advice

around advice 比較特別, 它可以在一個方法的之前之前和之后添加不同的操作, 并且甚至可以決定何時, 如何, 是否呼叫匹配到的方法,

@Component
@Aspect
public class AdviseDefine {
    // 定義 advise
    @Around("com.xys.aspect.PointcutDefine.dataAccessOperation()")
    public Object doAroundAccessCheck(ProceedingJoinPoint pjp) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        // 開始
        Object retVal = pjp.proceed();
        stopWatch.stop();
        // 結束
        System.out.println("invoke method: " + pjp.getSignature().getName() + ", elapsed time: " + stopWatch.getTotalTimeMillis());
        return retVal;
    }
}

around advice 和前面的 before advice 差不多, 只是我們把注解 @Before 改為了 @Around 了,

最后,關注公眾號Java技術堆疊,在后臺回復:面試,可以獲取我整理的 Spring 系列面試題和答案,非常齊全,

作者:永順
來源:segmentfault.com/a/1190000007469968

近期熱文推薦:

1.600+ 道 Java面試題及答案整理(2021最新版)

2.終于靠開源專案弄到 IntelliJ IDEA 激活碼了,真香!

3.阿里 Mock 工具正式開源,干掉市面上所有 Mock 工具!

4.Spring Cloud 2020.0.0 正式發布,全新顛覆性版本!

5.《Java開發手冊(嵩山版)》最新發布,速速下載!

覺得不錯,別忘了隨手點贊+轉發哦!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/265538.html

標籤:Java

上一篇:從高級語言到機器語言

下一篇:springmvc處理模型資料

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more