在前面咱們已經完成了IOC,DI,AOP的實現,基本的功能都已經完成了,咱們的手寫框架也能勉強使用起來。爲了讓咱們的框架可以使用起來比較簡單,這一節咱們來實現註解和xml的配置。git
本章的xml和註解的功能都是爲實現bean的建立,其餘如aop等功能可仿造實現。github
若是有同窗測試過咱們寫好的框架,可能會感覺到使用起來很是麻煩,在測試的時候咱們須要顯示的來定義bean以及運行過程當中須要的其餘對象。spring
public void test() throws Exception { DefaultBeanDefinition bd = new DefaultBeanDefinition(); bd.setClazz(User.class); bd.setSingleton(true); bd.setBeanFactoryName("TestFactory"); bd.setCreateBeanMethodName("createMethod"); bd.setStaticCreateBeanMethodName("staticCreateMethod"); factory.register(bd, "user"); bd = new DefaultBeanDefinition(); bd.setClazz(BeforeAdvice.class); factory.register(bd, "myBeforeAdvice"); AopProxyCreator aapc = new AopProxyCreator(); aapc.setBeanFactory(factory); factory.registerBeanPostProcessor(aapc); // 向AdvisorAutoProxyCreator註冊Advisor aapc.register(new RegexMatchAdvisor("myBeforeAdvice", "execution(* bean.User.*())", new RegexExpressionPointCutResolver())); User user = (User) factory.doGetBean("user"); user.sayHello(); } 複製代碼
如上爲測試一個AOP的功能,須要定義不少的對象來完成功能,這還只是一個對象的功能加強,在實際使用中確定會有大量的實例。這樣在使用起來就變得及其麻煩了。參考Spring中,能夠經過xml和annotation的方式來簡化類定義或者其餘一些處理。api
在實際實現以前,咱們先來宏觀的看一些註解和xml是如何來解析的。 bash
基本上在spring中xml就是這樣工做的,同理,註解也差很少是這樣一個過程。 markdown
上面的這一過程實際上就是咱們須要實現的功能,如今咱們就根據以上過程進行實現吧。網絡
這一小節的內容並不重要,實際就咱們的開發中做用並不大,稍微瞭解便可。沒興趣的能夠直接跳到下一節。框架
定義xml標記的方式有dtd和xsd兩種,假設我想定義一個下面這樣的xml標記:dom
<?xml version="1.0"?> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note> 複製代碼
那麼咱們既能夠用dtd實現,也能夠用xsd實現:oop
dtd
<!ELEMENT note (to, from, heading, body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> 複製代碼
xsd
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3schools.com" xmlns="http://www.w3schools.com" elementFormDefault="qualified"> <xs:element name="note"> <xs:complexType> <xs:sequence> <xs:element name="to" type="xs:string"/> <xs:element name="from" type="xs:string"/> <xs:element name="heading" type="xs:string"/> <xs:element name="body" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> 複製代碼
這節內容只是稍微提下,有興趣的能夠搜一些資料學習。
要來加載文件那麼首先咱們須要知道這個文件的位置,很明顯這個位置須要由用戶來指定,由用戶來告訴咱們須要加載那些配置文件,那麼用戶該如何來指定呢?
這裏咱們須要定義新的類和接口來完成這件事,這個新定義的類用來完成xml文件的加載,解析以及對bean實例的建立和註冊等。同時該類是給用戶使用的,在bean建立後還須要讓用戶可以取到容器中的實例,即該類還須要具有beanfactory的部分功能。
說到加載,首先咱們須要明白這些配置文件可能會以什麼樣的形式展示,通常來講有着如下的類型:
可能還有其餘不一樣的形式,固然這不重要。咱們須要明白的是很明顯不一樣形式的內容加載的方式確定是不一樣的,好比經過文件系統加載的是得到一個文件,而url形式的是從網絡獲取數據。因此咱們須要爲每一種方式都提供個性的加載方式。
加載的方式不同,那麼解析呢?
解析xml,咱們都是須要獲取到xml的流信息,都是解析xml的InputStream,因此雖然加載方式各不相同,可是解析的方法是能夠通用的。
根據上面的分析,咱們能夠知道,加載的過程實際上就是獲取一個InputStream的過程,很明顯每一種方式獲取配置文件都須要最終返回一個InputStream,這裏咱們定義一個獲取InputStream的接口。
對於配置文件的加載實際上無論經過哪種方式,實際上都是對文件進行操做,爲了方便可以對解析提供一致的接口,咱們須要對不一樣方式加載進行抽象,使其能接受任意類型的加載方式對象。這裏咱們定義Resource接口來表示xml資源,不一樣的實現類表示不一樣的加載方式。Resource接口具有一部分文件的特性。
到了如今咱們還有一個很重要的問題,就是咱們如何來分辨當前須要加載的配置是屬於哪種類型呢?只有解決了這一問題才能正確的解析。
這裏咱們使用前綴匹配的方式來分配不一樣類型的配置文件加載器,好比:
經過不一樣的前綴來來返回不一樣的對象,若是看過前面幾節的同窗應該立刻就能反應過來這裏確定要用工廠模式了[笑]。
那麼加載配置文件這一行爲在何時進行呢?
考慮到類ApplicationContext是用戶使用框架的入口,該類還包含獲取bean實例的操做,要保證在該類實例化完成後讓ApplicationContext具有獲取實例的能力,那麼加載配置文件的功能就須要在ApplicationContext的構造方法中完成。
結合以上分析,對ApplicationContext類圖作出修改。
加載已經完成了,就是說咱們如今已經取到不一樣的Resource,那麼如今如何對其進行解析呢?
對於xml類型的文件解析咱們這裏使用dom4j,這個東西不必深刻研究,要用到的時候查下api就好了。對於xml的解析就是獲取節點,而後對獲取節點的內容。回顧咱們以前在作IOC的時候,建立一個bean首先是須要獲取BeanDefinition。xml這裏也同樣,根據解析到的內容構造BeanDefinition,經過BeanDefinitionRegistery註冊。在對bean實例化時取用。因此很明顯咱們須要定義一個新的接口用於解析Resource,將解析後的內容封裝爲BeanDefinition並註冊。
好了,到這裏關於xml的加載和解析基本就完成了,而對於annotation的解析流程基本也是這樣的,用戶指定須要掃描的包,框架遍歷包所在目錄及子目錄,記錄下相應被註解修飾的類,反射生成class對象,獲取class對象數據生成BeanDefinition。類圖在上面也已經體現出來了。後面就須要咱們去寫代碼了。
相關的代碼已經託管到github