@TOC# Spring系列
記錄在程式走的每一步___auth:huf
非常感謝各位同學們;各位同事以及開發好友的關注與支持; 上一篇文章非常榮幸的沖到了熱榜第一; Spring連載內容 剩余內容不多了; 一個就是AOP的原始碼實作; 還有一個就是想說Spring 事務的原始碼實作; 就會進入其他原始碼的連載;
對于AOP Spring并不是首創,首創是 AspectJ,而且也不僅僅只有Spring提供了一套機制來支持AOP Spring是依賴了AspectJ的,或者說, Spring是直接把AspectJ中所定義的那些注解直接拿過來用,自己沒有再重復定義了,不過也僅僅只 是把注解的定義賦值過來了
上一章節我們講到; CGLIB 以及 JDK代理的基本實作;
下面給大家補齊AOP 切面的其他知識點;
Pointcut :切點
Advice :通知
Advisor :一個Advisor 就等于 一個Advice 加一個Pointcut;
Aspect : 表示切面,比如被@Aspect注解的類就是切面
join point :表示連接點;一個程式執行程序中的點.在Spring中一個連接點通常表示一個方法的執行;
Introduction :可以使用@DeclareParents來給所匹配的類添加一個介面,并指定一個默認實作
Target object:目標物件,被代理物件 也就是Spring 使用BeanDefinition 創建出來的物件;在沒有使用代理的時候; 我們用的那個容器當中的物件;
AOP proxy:表示代理工廠,用來創建代理物件的 在Spring中 要么是CGLIB 代理 要么是JDK代理;
Weaving:表示織入,表示創建代理物件的動作,這個動作可以發生在編譯時期(在Java 語言中,從織入切面的方式上來看,存在三種織入方式:編譯期織入、類加載期織入和運行期織入,編譯期織入是指在Java編譯期,采用特殊的編譯器,將切面織入到Java類中;而類加載期織入則指通過特殊的類加載器,在類位元組碼加載到JVM時,織入切面;運行期織入則是采用CGLib工具或JDK動態代理進行切面的織入,)
以上 幾個關鍵的知識點; 請務必熟悉;因為在面試中 有非常大的可能性會被問到;
以下是我找原始碼起源的方法:
我們在Spring啟動的時候; 大體可以分為這三部分. 如果看過我這一系列的同學應該知道. 這一個系列 都是圍繞著 Spring5.3.5 版本進行講解;
第一部分 為系統引數配置;
第二部分 為BeanPostProcessor ,BeanFactory 等主類進行一個實體化 初始化;
第三部分 為配置過的單例Bean進行一個實體化 初始化;
我們在啟動的時候 在console的地方 就可以看到 我們創建的細節程序; 例如 我們要找AOP 的起源;

我們全域搜索這個org.springframework.aop.config.internalAutoProxyCreator 這樣 我們就可以找到AopConfigUtils 這個類;
在這個變數中 我們發現;

下面有方法參考這個引數 進行BeanDefinition 的注冊; 一眼就可以看出來了 萬變不離其宗.在手寫Mybatis-Spring.jar的時候 作者明確的說明 如果 有插件 或者是 其他架構 需要跟Spring整合 就必須往Spring中的BeanDefinition 進行注冊.例如AOP ;

我們繼續往深追溯 這個方法由誰呼叫(這個不會的 自己的百度一下)

最后我們找到了這個類: AspectJAutoProxyRegistrar 實作了 ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar
在我們手寫Mybatis-Spring.jar 的時候 我介紹了幾種注冊Beandefinition的方式. 著是第三種方式; 有興趣可以看本系列 第十二章; 我為什么要這樣找; 原因是什么 ;這些都可以在第十二章找到相對應的答案; 通過這樣的方式 我們就可以知道代理物件是怎么創建的. OK 接下來我們分析原始碼:
開始前 我問幾個問題
1.我們的代理物件是怎么創建的? 2.在什么時候置換成為代理物件? 3.是什么條件 讓Spring去選擇使用CGLIB代理 還是 JDK代理?(我個人去面試別人的時候 非常喜歡問的問題;)
第一答: 我們的代理物件 是由 DefaultAopProxyFactory 創建的

第二答: 在初始化物件之后開始置換AOP

第三答: 在第一答的原始碼中已經明確回答了
- 被代理物件是否是介面?
- 被代理物件是否實作介面?
如果沒有 就使用CGLIB代理 如果有 就使用JDK代理; 當然也有其他幾種情況. 其他幾種情況
代碼給大家貼下來:
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
optimize為true,或proxyTargetClass為true,或用戶沒有給ProxyFactory物件添加interface
if (!NativeDetector.inNativeImage() &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
targetClass是介面,直接使用Jdk動態代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
否則 使用Cglib
return new ObjenesisCglibAopProxy(config);
}
上面判斷都為false 或者 !NativeDetector.inNativeImage() 為false 直接使用JDK代理;
else {
return new JdkDynamicAopProxy(config);
}
}
總結:
1:本章介紹了 (我個人) 尋找原始碼的方式;
2:介紹了AOP 的幾個知識點(還未分析每個知識點的具體邏輯;)
3:介紹了AOP 是通過什么創建代理物件的 是在什么時機創建的.是怎么判斷是CGLIB代理 還是JDK代理 的
下一篇知識點. 我們將會展開整個AOP 使用代理類; 使用AspectJ 徹底講解注解的應用. 執行順序; 以及AOP使用的責任鏈模式執行程序;沉浸式學習 Spring AOP 將會理解的透徹.
[因為作業緣故,更新速度較慢.作者也是特別無奈.因為一片文章需要我大量的閱讀原始碼;]
[希望能盡自己所能,把自己理解的東西.呈現出來給讀者.]
seeyou
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/347114.html
標籤:java
