Spring AOP看這篇就夠了

2021-02-19 IT牧場
基本知識

其實, 接觸了這麼久的 AOP, 我感覺, AOP 給人難以理解的一個關鍵點是它的概念比較多, 而且坑爹的是, 這些概念經過了中文翻譯後, 變得面目全非, 相同的一個術語, 在不同的翻譯下, 含義總有著各種莫名其妙的差別. 鑑於此, 我在本章的開頭, 著重為為大家介紹一個 Spring AOP 的各項術語的基本含義. 為了術語傳達的準確性, 我在接下來的敘述中, 能使用英文術語的地方, 儘量使用英文.

什麼是 AOP

AOP(Aspect-Oriented Programming), 即 面向切面編程 , 它與 OOP( Object-Oriented Programming, 面向對象編程) 相輔相成, 提供了與 OOP 不同的抽象軟體結構的視角. 在 OOP 中, 我們以類(class)作為我們的基本單元, 而 AOP 中的基本單元是 Aspect(切面)

術語Aspect(切面)

aspect 由 pointcount 和 advice 組成, 它既包含了橫切邏輯的定義, 也包括了連接點的定義. Spring AOP就是負責實施切面的框架, 它將切面所定義的橫切邏輯織入到切面所指定的連接點中. AOP的工作重心在於如何將增強織入目標對象的連接點上, 這裡包含兩個工作:

如何通過 pointcut 和 advice 定位到特定的 joinpoint 上

可以簡單地認為, 使用 @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織入有三種方式:

動態代理織入, 在運行期為目標類添加增強(Advice)生成子類的方式. Spring 採用動態代理織入, 而AspectJ採用編譯器織入和類裝載期織入.advice 的類型before advice, 在 join point 前被執行的 advice. 雖然 before advice 是在 join point 前被執行, 但是它並不能夠阻止 join point 的執行, 除非發生了異常(即我們在 before advice 代碼中, 不能人為地決定是否繼續執行 join point 中的代碼)after return advice, 在一個 join point 正常返回後執行的 adviceafter throwing advice, 當一個 join point 拋出異常後執行的 adviceafter(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 操作.

@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 = "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 = "aspectMethod()  &&  args(name)")
public void doSomething(String name) {
}

// 匹配第一個參數為 name 的方法
@Before(value = "aspectMethod()  &&  args(name, ..)")
public void doSomething(String name) {
}

// 匹配第二個參數為 name 的方法
Before(value = "aspectMethod()  &&  args(*, name, ..)")
public void doSomething(String name) {
}

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

@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 了.

乾貨分享

最近將個人學習筆記整理成冊,使用PDF分享。關注我,回復如下代碼,即可獲得百度盤地址,無套路領取!

•001:《Java並發與高並發解決方案》學習筆記;•002:《深入JVM內核——原理、診斷與優化》學習筆記;•003:《Java面試寶典》•004:《Docker開源書》•005:《Kubernetes開源書》•006:《DDD速成(領域驅動設計速成)》•007:全部•008:加技術群討論

近期熱文

•LinkedBlockingQueue vs ConcurrentLinkedQueue•解讀Java 8 中為並發而生的 ConcurrentHashMap•Redis性能監控指標匯總•最全的DevOps工具集合,再也不怕選型了!•微服務架構下,解決資料庫跨庫查詢的一些思路•聊聊大廠面試官必問的 MySQL 鎖機制

關注我

喜歡就點個"在看"唄^_^

相關焦點

  • Spring5.0源碼學習系列之Spring AOP簡述
    com.example.spring.aop.service.UserService.addUser(com.example.spring.aop.bean.User); target is of class [com.example.spring.aop.service.impl.UserServiceImpl]方法調用後(after method invoke) :User
  • 詳解Spring框架的AOP機制
    下面列出的是spring-aop-5.0版本,其它版本也可以。● spring-aop-5.0.8.RELEASE● spring-aspects-5.0.8.RELEASE另外還需要引入下面的Jar包:● aspectjrt● aspectjweaver在課程案例SpringProgram項目中,相關的Teacher實體類、EmailNotice業務類、Spring配置文件已經存在
  • 如何理解 Spring AOP 以及使用 AspectJ?
    在spring AOP中連接點就是指方法的調用。Pointcut,切入點,切入點是指切面與程序流程的交叉點,即那些需要處理的連接點,通常在程序中切入點是指。類或者是方法名,比如說某個通知要應用到所有的以add開頭的方法中。那麼所有滿足這一規則的方法都是切入點。
  • Spring框架IOC和AOP簡介
    運行期動態代理:Spring AOP、JbossAOP(3)AOP的幾個相關概念(4)Advice的類型(5)有接口和無接口的Spring AOP實現區別◎Spring AOP默認使用標準的Java SE動態代理作為AOP代理,這使得任何接口
  • spring AOP是什麼?你都拿它做什麼?
    AOP的出現彌補了OOP的這點不足。 為了闡述清楚spring AOP,我們從將以下方面進行討論: 1.代理模式。 2.靜態代理原理及實踐。 3.動態代理原理及實踐。 4.spring AOP原理及實戰。 1.代理模式。 代理模式:為其他對象提供一種代理以控制對這個對象的訪問。
  • Spring AOP是什麼?你都拿它做什麼?
    這段話比較官方,但我更傾向於用自己的語言理解:比如A對象要做一件事情,在沒有代理前,自己來做;在對 A 代理後,由 A 的代理類 B 來做。代理其實是在原實例前後加了一層處理,這也是 AOP 的初級輪廓。2. 靜態代理原理及實踐靜態代理模式:靜態代理說白了,就是在程序運行前就已經存在代理類的字節碼文件、代理類和原始類的關係在運行前就已經確定。廢話不多說,我們看一下代碼。
  • Java 第一大框架:Spring 的 IoC 跟 AOP 雛形如何實現?
    對於某個具體的對象而言,以前是它控制其他對象,現在是所有對象都被spring控制,所以這叫控制反轉(IOC)。當我們程序運行到需要某個對象到時候,會自動到實現依賴注入也就是DI。:aop="http://www.springframework.org/schema/aop"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/
  • 求求你,下次面試別再問我什麼是AOP了!
    手動3種方式ProxyFactory方式這種是硬編碼的方式,可以脫離spring直接使用,用到的比較多,自動化方式創建代理中都是依靠ProxyFactory來實現的,所以這種方式的原理大家一定要了解,上篇文章中已經有介紹過了,不清楚的可以去看一下:Spring系列第32篇:AOP核心源碼、原理詳解AspectJProxyFactory方式AspectJ是一個面向切面的框架
  • 聊聊AOP
    看一下spring-aop中的 Advisor 接口的定義:public interface Advisor { Advice EMPTY_ADVICE = new Advice() {}; /** * Return the advice part
  • 上盤硬菜,@Transaction源碼深度解析 | Spring系列第48篇
    3、@Transaction事務原理原理比較簡單,內部是通過spring aop的功能,通過攔截器攔截 @Transaction 方法的執行,在方法前後添加事務的功能。Spring系列第18篇:@import詳解(bean批量註冊),這個註解的value是TransactionManagementConfigurationSelector,看一下這個類的源碼,重點是他的selectImports方法,這個方法會返回一個類名數組,spring容器啟動過程中會自動調用這個方法,將這個方法指定的類註冊到spring容器中;方法的參數是AdviceMode,這個就是@EnableTransactionManagement
  • Spring事務管理
    -- 配置事務的AOP切面 --> <aop:config> <aop:pointcut id="allService" expression="execution(* com.study.leesmall.spring.sample.tx.service.*Service.*(..)))"
  • 你知道Spring是怎麼將AOP應用到Bean的生命周期中的嗎?
    」在上篇文章中(Spring中AOP相關的API及源碼解析,原來AOP是這樣子的)我們已經分析過了AOP的實現的源碼,那麼Spring是如何將AOP應用到Bean的生命周期的呢?這篇文章就帶著大家來探究下這個問題。
  • Spring原理只要看這篇文章就夠了
    Context 組件Context 在 Spring 的 org.springframework.context 包下,前面已經講解了 Context 組件在 Spring 中的作用,他實際上就是給 Spring 提供一個運行時的環境,用以保存各個對象的狀態。下面看一下這個環境是如何構建的。
  • Spring SPI和Spring Boot SPI - 第345篇
    相關歷史文章(閱讀本文前,您可能需要先看下之前的系列
  • Spring事務基礎
    (4)serializable:這是花費最高代價但最可靠的事務隔離級別。事務被處理為順序執行。/p"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:tx="http://www.springframework.org/schema/tx"
  • 教妹學Java:Spring基礎篇
    其實從形式上看,Java 配置和註解配置沒什麼區別,因為 Java 配置也用的是註解,只不過,以前用 application-context.xml 配置數據源等信息,現在用 註解的類配置。org.springframeworkgroupId>spring-contextartifactId>5.2.2.RELEASEversion>dependency>dependencies
  • 帶妹學Java:Spring基礎篇
    其實從形式上看,Java 配置和註解配置沒什麼區別,因為 Java 配置也用的是註解,只不過,以前用 application-context.xml 配置數據源等信息,現在用 @Configuration 註解的類配置。02、Spring 特性「二哥,據說 Spring 的特性非常豐富,你能給我說說嗎?」「沒問題啊。」
  • Spring集成RabbitMQ簡單實現RPC
    /tx"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context
  • 漫畫| Spring AOP的底層原理是什麼?
    >4、談談Spring如何配置聲明式事務控制聲明式事務管理有兩種常用的方式:基於tx和aop
  • 搞Java的你還不會Spring?一篇文章帶你掌握
    本篇文章將帶你掌握Spring框架,滿滿的乾貨,內容有點多,希望你能有耐心看完,看完後一定會有所收穫。Spring容器在SpringIOC容器讀取Bean配置創建Bean之前,必須對它進行實例化。看這段配置,bean節點下的屬性depends-on,其值為address,若IOC容器中找不到一個id為address的Bean,則拋出異常,也就是說,該person依賴於address。