Summer——從頭開始寫一個簡易的Spring框架
- 2021 年 5 月 19 日
- 筆記
Summer——從頭開始寫一個簡易的Spring框架
參考Spring
框架實現一個簡易類似的Java
框架。計劃陸續實現IOC
、AOP
、以及數據訪問模組和事務控制模組
。項目持續維護中…歡迎Star!Thanks~~~
本項目參考自Spring,但又做出了自己的創新,最大的創新點在於解決循環依賴的問題,引入了自己的解決方案,具體方法可以參考更新日誌中Version 0.5(Pre-release)
的更新記錄。
項目計劃:
- [x] IOC容器
- [x] AOP切面
- [x] 對外的擴展介面
- [ ] 數據訪問集成模組(JDBC、事務控制)
關於對IOC和AOP功能為什麼要使用(why)
,以及應該如何使用(how)
請移步使用文檔,要了解每個版本更新的內容請移步更新日誌。
關於如何將自己的框架適配到summer,請查看如何適配summer。
運行環境
JDK 8
項目主要技術棧
註解、反射
如何使用
倉庫地址: //github.com/vfdxvffd/Summer
下載最新的jar包 ,將其導入項目中,即可使用,目錄結構如下圖,藍色框內為
summer
的核心程式碼,ch
包下為logback
日誌依賴,net.sf.cglib
下為cglib動態代理的依賴,org.slf4j
下為slf4j
的日誌門面依賴。
Version 1.0(Release)
本次更新測試了之前的版本的穩定性,以及增加了框架的擴展性,開放出別的框架適配的介面。
- 對之前的
pre-release
版本進行了多次測試以確保穩定性。 - 框架對外開放
Extension
介面,該介面中的方法在ioc
容器構造的多個階段進行了切入,增加了框架的可擴展性。 - 如何將自己的框架適配到
Summer
,請看如何適配summer或者可以提issues。
Version 0.5(Pre-release)
bug描述:循環依賴的問題復現出來
因為之前v0.1
更新中引入的一個解決bug的方法導致了這個重大的bug,這次通過設置二級快取來解決循環依賴
的問題,具體bug的產生原因詳情可見更新日誌,更新日誌對這次bug的出現原因以及解決方法做了詳細的說明。
bug解決:
針對目前掌握的代理方面的知識,對之前的做法做出一些調整。設置二級快取,一級快取一個(即真正的ioc容器),二級快取兩個,都是負責存放實例化但未初始化的對象,但一個是存放原對象,另一個負責存放代理對象,二級快取的示意圖如下:
將ioc容器的構造過程分為四步來進行:
- 遍歷包,找到所有需要被IOC管理的類,封裝成
BeanDefinition
- 根據第一步獲取到的
BeanDefinition
實例化那些單例且非延遲載入的對象,並將其加入到二級快取的earlyRealObjects
中 - 對第二步得到的
earlyRealObjects
中的對象進行檢查,看是否需要設置代理,如果需要則對其進行代理,並將代理對象加入到二級快取中的earlyProxyObjects
中(並不刪除earlyRealObjects
中對應的真正的對象)。 - 對第二步得到的
earlyRealObjects
中的對象進行注入工作(即開始進行初始化),檢查每個對象的每個域,如果標註了@Autowired
註解且值為null
,則對其進行注入工作,現在一級快取中查找,如果有直接取出為其注入,如果沒有檢查二級快取的earlyProxyObjects
,如果有則取出為其注入,如果沒有則接著檢查二級快取的earlyRealObjects
,找到後為其注入,此時如果還沒有則說明這個域對應的bean是非單例(prototype)模式或者懶載入模式的,則為其實例化並設置代理(如果需要),並初始化,然後注入其中。如果是非ioc容器管理的域,則直接注入null
,也可以考慮改為拋出異常給用戶提示。
Version 0.4(Pre-release)
本次更新加入了新功能,修改了一個已知的bug
-
本次更新引入
CGLib
依賴,增加動態代理的方式,對於實現了介面的方法採用JDK
動態代理來實現切面功能,對於沒有實現介面的類採用CGLib
來實現切面。 -
修改bug,之前版本中的
判斷當前類是否已經完成了實例對象全部的創建注入工作
的方法,判斷沒有包含所有情況。bug描述:對於一個沒有任何域
且
需要代理的對象,進行注入工作的時候會由於沒有域需要注入,從而直接判斷其已經完成注入,而跳過了代理階段。
Version 0.3(Pre-release)
-
本次更新引入了日誌依賴,增加了對ioc構造過程中的日誌記錄
-
對於標註了
@Aspect
註解的類自動將其加入IOC容器中,不用再重複標註註解
Version 0.2(Pre-release)
本次更新加入了一些新功能,修復了一些bug
-
更新功能:
-
aop增加了一種切入方式,目前有以下切入方式
@Before
、@AfterReturning
、@AfterThrowing
、@After
以上對應的切入時機如下:
try { @Before fun.invoke(); @AfterReturning } catch (Throwable t) { @AfterThrowing } finally { @After }
-
切面方法可以通過
JoinPoint
類獲取被切的方法的參數、方法名、返回值類型。對於@AfterReturning
的切入方式可以獲取返回值,類型為Object
,而@AfterThrowing
可以獲取拋出的異常,類型為Throwable
。
-
-
修復了重複代理的bug
bug描述:當一個待注入bean中有超過一個需要注入的域(帶有註解@Autowired且未完成賦值),如果對它中的方法進行切面,這時切面方法會重複執行
Version 0.1(Pre-release)
本次更新主要修復了一些bug,以及優化了程式碼的結構
-
修復對於注入對象的切面方法失效的bug
bug描述:在controller中注入service,但是如果有對於service的切面方法,則切面方法無法被調用
-
修復延遲載入的對象注入失敗的bug
bug描述:對於標註了延遲載入的類注入時會發生異常
-
修復對非單例的bean注入失敗的bug
bug描述:對於標註了非單例的類注入時會發生異常,且會調用多次構造函數的問題
-
增加核心程式碼的注釋。
-
優化程式碼結構,重構了大部分冗餘的程式碼塊
-
抽取可重用方法。
Version 0.0(Pre-release)
-
完成IOC容器的初步搭建
-
完成AOP功能的簡單使用(還需修改)
-
支援
@Component
、@Autowired
、@Qualifier
、@Value
、@Repository
、@Service
、@Controller
註解的使用- @Component(同@Respository、@Service、@Controller):標註在類上,將此類註冊到ioc容器中
- @Autowired:自動注入ioc容器中的對象
- @Qualifier:自動注入ioc中對象的時候指定
beanName
,如不指定則按照beanType
注入 - @Value:指定將類注入到容器是基本類型(包括包裝類)欄位的值
-
支援根據
beanName
、beanType
獲取ioc中的對象 -
自定義類型轉化異常,
@Value
接受String
類型,如果傳入的值並不能正確轉化,就拋出DataConversionException
異常。 -
增加單例模式與非單例模式的配置註解
@Scope
,以及增加延遲載入的配置註解@Lazy
-
可以使用介面來接受IOC中返回的對象
-
AOP可以對方法進行
@Before
、@After
、@AfterThrowing
的切面,需要配置方法的全方法名 -
AOP使用JDK的動態代理,
set
可以不添加,內部實現是直接通過設置域的可訪問屬性,然後直接設置值 -
後續計劃:
- 支援根據
xml
配置ioc容器中的對象 - 對於運行過程可能發生的異常使其儘可能可控,且明確的拋出或處理
- 對於AOP可選擇性的加入
CGLIB
代理 - 對於AOP一些已注入對象的代理失效bug進行修復(已定位)
- etc… for more…
- 支援根據