輕量級Java Web框架的實現原理


搭建輕量級Java Web框架

    MVC(Model-View-Controller,模型-視圖-控制器)是一種常用的設計模式,可以使用這個模式將應用程序進行解耦。

IOC

    通過Controller注解來定義Controller類,在該類中,可通過Inject注解定義一系列Service成員變量,這就是"依賴注入"。此外,有一系列被Action注解所定義的方法(簡稱Action方法),在這些Action方法中,調用了Service成員變量的方法來完成具體的業務邏輯。若返回View對象,則表示JSP頁面;若返回Data對象,則表示一個JSON數據。

    我們需要開發一個"類加載器"來加載該基礎包名下的所有類,比如使用了某注解的類,或者實現了某接口的類,再或者繼承了某父類的所有子類等。

    獲取類加載器實現起來最為簡單,只需獲取當前線程中的ClassLoader即可。

    我們的目標是在控制器類上使用Controller注解,在控制器類的方法上使用Action注解,在服務類上使用Service注解,在控制器類中可使用Inject注解將服務類依賴注入進來。因此需要自定義4個注解類。

    可以將帶有Controller注解與Service注解的類所產生的對象,理解為由Smart框架所管理的Bean。

    我們需要獲取所有被Smart框架管理的Bean類,根據類來實例化對象,最后將每次創建的對象存放在一個靜態的Map<Class<?>,Object>中,我們需要隨時獲取該Map,還需要通過該Map的key(類名)去獲取所對應的value(Bean對象)。該Map<Class<?>,Object>相當於一個"Bean容器",在Bean Map中存放了Bean類與Bean實例的映射關系,我們只需要通過getBean方法,傳入一個Bean類,就能獲取Bean實例。

    我們再Cotroller中定義Service成員變量,然后在Controller的Action方法中調用Service成員變量的方法。那么,如何實例化Service成員變量呢?

    還記得之前定義的Inject注解嗎?我們就用它來實現Service實例化。那么,誰來實例化呢?

    不是開發者自己通過new的方式來實例化,而是通過框架自身來實例化,像這類實例化過程,稱為IoC(Inversion of Control,控制反轉)。控制不是由開發者來決定的,而是反轉給框架了。一般地,我們也將控制反轉稱為DI(Dependency Injection,依賴注入),可以理解為將某個類需要依賴的成員注入到這個類中。那么,如何實現依賴注入呢?

    最簡單的方式是,先通過BeanHelper獲取所有BeanMap(是一個Map<Class<?>,Object>結構,記錄了類與對象的映射關系)。然后遍歷這個映射關系,分別取出Bean類與Bean實例,進而通過反射獲取類中所有成員變量。繼續遍歷這些成員變量,在循環中判斷當前成員變量是否帶有Inject注解,若帶有該注解,則從Bean Map中根據Bean類取出Bean實例。最后通過ReflectionUtil#setField方法來修改當前成員變量的值。

    此時,在IoC框架中所管理的對象都是單例的,由於IoC框架底層還是從BeanHelper中獲取Bean Map的,而Bean Map中的對象都是事先創建好並放入到這個Bean容器的,所有的對象都是單利的。

請求轉發器

    我們需要創建一個ControllerHelper類,讓它來處理如下邏輯:

    通過ControllerHelp,我們可以獲取所有定義了Controller注解的類,可以通過反射獲取該類所有帶有Action注解的方法(簡稱"Action"方法),獲取Action注解中的請求表達式,進而獲取請求方法與請求路徑,封裝一個請求對象(Request)與處理對象(Handler),最后將Request與Handler建立一個映射關系,放入一個Action Map中,並提供一個可根據請求方法與請求路徑獲取處理對象的方法。

    現在需要編寫一個Servlet,讓它來處理所有的請求。從HttpServletRequest對象中獲取請求方法與請求路徑,通過ControllerHelper#getHandler方法來獲取Handler對象。當拿到Handler對象后,我們可以方便地獲取Controller的類,進而通過BeanHelp.getBean方法獲取Controller的實例對象。

    一個簡單的MVC框架就開發完畢了,通過這個DispatcherServlet來處理所有的請求,根據請求信息從ControllerHelper中獲取對應的Action方法,然后使用反射技術調用Action方法,同時需要具體的傳入方法參數,最后拿到返回值並判斷返回值的類型,進行相應的處理。

    通過Controller注解來定義Controller類;通過Inejct注解來實現依賴注入;通過Action注解來定義Action方法。通過一系列的Helper類來初始化MVC框架。通過DispatcherServlet來處理所有的請求;根據請求方法與請求路徑來調動具體的Action方法,判斷Action方法的返回值,若為View類型,則跳轉到JSP頁面,若為Data類型,而返回JSON數據。

AOP

    在AOP中,我們需要定義一個Aspect(切面)類來編寫需要橫切業務邏輯的代碼,也就是上面提到的性能監控代碼。此外,我們需要通過一個條件來匹配想要攔截的類,這個條件在AOP中稱為Pointcut(切點)。

    代理,或稱為Proxy,意思就是你不用去做,別人代替你去處理。

    通過CGLib實現動態代理

    在客戶端代碼繼承AspectProxy;

    proxy為通過CGLib返回后的具有AOP實現的目標類,targetClass為原來的類

    Object proxy = ProxyManager.createProxy(targetClass, proxyList);
BeanHelper.setBean(targetClass, proxy);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM