天天看點

手寫一個簡易的IOC

這個小項目是我讀過一點Spring的源碼後,模仿Spring的IOC寫的一個簡易的IOC,當然Spring的在天上,我寫的在馬裡亞納海溝,哈哈

感興趣的小夥伴可以去我的github拉取代碼看着玩

項目中有兩種方式實作IOC:

  • 第一種是基于dom4j實作的解析XML配置檔案版
  • 第二種是基于自定義注解實作全配置版

全注解版

模仿Spring原生的IOC機制如下:

  • Interface類型的beanDefinition不會被執行個體化**
  • String類型的beanDefinition不會被執行個體化
  • 維護三個核心的map容器
  • 使用底層存放執行個體化對象的容器是一個叫​

    ​singletonObjects​

    ​的CurrentHashMap
  • 第二個用來輔助解決循環依賴的容器叫​

    ​singletonFactories​

    ​類型:CurrentHashMap
  • 第三個用來存放bean定義資訊的map容器叫​

    ​beanDefinitionMap​

    ​類型:CurrentHashMap

Spring底層的自己還封裝了BeanDefinition, 當然我沒幹這件事,直接用的類的描述對象 Class

自定義了四種注解如下:

  • CDao 用于辨別持久層的對象
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CDao {
    String value()default "";
}      
  • CService 用來辨別服務層的對象
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CService {
    String value()default "";
}      
  • CComponentScan 用來辨別主配置類,提供包掃描需要的base-packet
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface CComponentScan {
    String value()default "";
}      
  • CAutowired 用來辨別需要自動裝配的對象
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CAutowired {
    String value()default "";
}      

當然他跟Spring原生的@Autowired是沒法比的,Spring自動裝配類型預設是Autowired_no, 但是被Spring原生标記上的對象會先按照預設的裝配類型進行裝配,如果沒有預設的裝配類型,再按照byType,如果容器中存在多個相同類型的對象,就按照byName, 名字再一樣就直接報錯了

另外我說一下,說了這麼多byName和byType, 那麼byName,是通過哪個name呢? 如果是基于setter方法的話就是setter去掉set後,後面的名字, 如果是通過@Autowired的byName,這個name其實就是屬性名

Spring是允許程式員去改這個預設的裝配類型的

然後在我的IOC中就比較遜色了,直接預設按照byType,沒有合适的類型再按照byName進行自動裝配

解決了循環依賴的問題

在我手動寫如何解決循環依賴的時候,那時候我還沒有去看源碼, 當時我畫了幾個流程圖,但是還是卡殼了, 于是我去調試Spring的實作, 簡直了!Spring的作者們簡直是真神!

其實說Spring如何解決循環依賴的,我前面有幾個源碼閱讀的部落格,感興趣可以去看看

這裡我就簡單的說下, 這件事是一個叫​

​AutowiredAnnotationBeanDefinitonPostprocessor​

​的後置處理器完成的, Spring在做這件事是時候,前前後後是一個偌大的繼承體系在支援,但是歸根結底是Spring玩了個漂亮的遞歸,方法名是getBean(),當然這個遞歸還有幾個輔助容器,這幾個容器就是我上面說的幾個map ,我的IOC能寫成,就得益于這一點

XML版

注解版的IOC我是用DOM4j解析XML配置檔案實作的, 做了下面的功能

  • 支援setter方法依賴注入

辨別性的資訊是 ​

​property​

<bean id="dao1" class="com.changwu.dao.DaoImpl1"></bean>
<bean id="service" class="com.changwu.service.UserServiceImpl4">
    <property ref="dao1" name="daoImpl"></property>
</bean>      
  • 支援構造方法的依賴注入

辨別性的資訊是 ​

​constructor-arg​

<bean id="DaoImpl" class="com.changwu.dao.DaoImpl1"></bean>
<bean id="service" class="com.changwu.service.UserServiceImpl3">
    <constructor-arg ref ="DaoImpl" name="DaoImpl1"></constructor-arg>
</bean>
</bean>      
  • 支援byType的自動裝配

辨別性的資訊是 ​

​byType​

<beans  default-autowire="byType">      
  • 主持byName的自動裝配
<beans  default-autowire="byName">      

感興趣的小夥伴可以去我的github拉取代碼看着玩