Summer——從頭開始寫一個簡易的Spring框架

Summer——從頭開始寫一個簡易的Spring框架

              

​ 參考Spring框架實現一個簡易類似的Java框架。計劃陸續實現IOCAOP、以及數據訪問模塊和事務控制模塊。項目持續維護中...歡迎Star!Thanks~~~

​ 本項目參考自Spring,但又做出了自己的創新,最大的創新點在於解決循環依賴的問題,引入了自己的解決方案,具體方法可以參考更新日誌中Version 0.5(Pre-release)的更新記錄。

項目計劃:

  • [x] IOC容器
  • [x] AOP切面
  • [x] 對外的擴展接口
  • [ ] 數據訪問集成模塊(JDBC、事務控制)

​ 關於對IOC和AOP功能爲什麼要使用(why),以及應該如何使用(how)請移步使用文檔,要了解每個版本更新的內容請移步更新日誌

​ 關於如何將自己的框架適配到summer,請查看如何適配summer

運行環境

JDK 8

項目主要技術棧

註解、反射

如何使用

​ 倉庫地址: https://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容器的構造過程分爲四步來進行:

  1. 遍歷包,找到所有需要被IOC管理的類,封裝成BeanDefinition
  2. 根據第一步獲取到的BeanDefinition實例化那些單例且非延遲加載的對象,並將其加入到二級緩存的earlyRealObjects
  3. 對第二步得到的earlyRealObjects中的對象進行檢查,看是否需要設置代理,如果需要則對其進行代理,並將代理對象加入到二級緩存中的earlyProxyObjects中(並不刪除earlyRealObjects中對應的真正的對象)。
  4. 對第二步得到的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

  1. 更新功能:

    • aop增加了一種切入方式,目前有以下切入方式

      @Before@AfterReturning@AfterThrowing@After

      以上對應的切入時機如下:

      try {
          @Before
          fun.invoke();
          @AfterReturning
      } catch (Throwable t) {
          @AfterThrowing
      } finally {
          @After
      }
      
    • 切面方法可以通過JoinPoint類獲取被切的方法的參數、方法名、返回值類型。對於@AfterReturning的切入方式可以獲取返回值,類型爲Object,而@AfterThrowing可以獲取拋出的異常,類型爲Throwable

  2. 修復了重複代理的bug

    bug描述:當一個待注入bean中有超過一個需要注入的域(帶有註解@Autowired且未完成賦值),如果對它中的方法進行切面,這時切面方法會重複執行

Version 0.1(Pre-release)

​ 本次更新主要修復了一些bug,以及優化了代碼的結構

  1. 修復對於注入對象的切面方法失效的bug

    bug描述:在controller中注入service,但是如果有對於service的切面方法,則切面方法無法被調用

  2. 修復延遲加載的對象注入失敗的bug

    bug描述:對於標註了延遲加載的類注入時會發生異常

  3. 修復對非單例的bean注入失敗的bug

    bug描述:對於標註了非單例的類注入時會發生異常,且會調用多次構造函數的問題

  4. 增加核心代碼的註釋。

  5. 優化代碼結構,重構了大部分冗餘的代碼塊

  6. 抽取可重用方法。

Version 0.0(Pre-release)

  1. 完成IOC容器的初步搭建

  2. 完成AOP功能的簡單使用(還需修改)

  3. 支持@Component@Autowired@Qualifier@Value@Repository@Service@Controller註解的使用

    • @Component(同@Respository、@Service、@Controller):標註在類上,將此類註冊到ioc容器中
    • @Autowired:自動注入ioc容器中的對象
    • @Qualifier:自動注入ioc中對象的時候指定beanName,如不指定則按照beanType注入
    • @Value:指定將類注入到容器是基本類型(包括包裝類)字段的值
  4. 支持根據beanNamebeanType獲取ioc中的對象

  5. 自定義類型轉化異常,@Value接受String類型,如果傳入的值並不能正確轉化,就拋出DataConversionException異常。

  6. 增加單例模式與非單例模式的配置註解@Scope,以及增加延遲加載的配置註解@Lazy

  7. 可以使用接口來接受IOC中返回的對象

  8. AOP可以對方法進行@Before@After@AfterThrowing的切面,需要配置方法的全方法名

  9. AOP使用JDK的動態代理,set可以不添加,內部實現是直接通過設置域的可訪問屬性,然後直接設置值

  10. 後續計劃:

    • 支持根據xml配置ioc容器中的對象
    • 對於運行過程可能發生的異常使其儘可能可控,且明確的拋出或處理
    • 對於AOP可選擇性的加入CGLIB代理
    • 對於AOP一些已注入對象的代理失效bug進行修復(已定位)
    • etc... for more...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章