磨了許久,藉助最近的一次通宵上線 cicada 終於更新了 v2.0.0
版本。java
之因此大的版本號變爲 2,確實是向下不兼容了;主要表現爲:git
bug
。IOC
容器選擇。其中重點是後面兩個。github
先來看第一個:路由方式的更新。數據庫
在以前的版本想要寫一個接口必須的實現一個 WorkAction
;並且最麻煩的是一個實現類只能作一個接口。json
所以也有朋友給我提過這個 issue。性能
因而改進後的使用方式以下:測試
是否有點似曾相識的感受😊。
如上圖所示,不須要實現某個特定的接口;只須要使用不一樣的註解便可。spa
同時也支持自定義 pojo
, cicada
會在調用過程當中對參數進行實例化。prototype
拿這個 getUser
接口爲例,當這樣請求時這些參數就會被封裝進 DemoReq
中.3d
http://127.0.0.1:5688/cicada-example/routeAction/getUser?id=1234&name=zhangsan
同時獲得響應:
{"message":"hello =zhangsan"}
實現過程也挺簡單,你們查看源碼便會發現;這裏貼一點比較核心的步驟。
@CicadaAction
註解的類。@CicadaRoute
註解的方法。Map
中。URL
去 Map
中查找這個關係。掃描類以及寫入映射關係
請求時查詢映射關係
反射調用這些方法
上面那幾個步驟其實我都是一把梭寫完的,但當我寫到執行具體方法時感受有點意思
了。
你們都知道反射調用方法有兩個重要的參數:
obj
方法執行的實例。args..
天然是方法的參數。我第一次寫的時候是這樣的:
method.invoke(method.getDeclaringClass().newInstance(), object);
而後一測試,也沒問題。
當我寫完以後 review
代碼時發現不對:這樣這裏每次都會建立一個新的實例,並且反射調用 newInstance()
效率也不高。
這時我不自覺的想到了 Spring 中 IOC 容器,和這裏場景也很是的相似。
在應用初始化時將全部的接口實例化並保存到 bean 容器中,當須要使用時只須要從容器中獲取便可。
這樣只是會在啓動時作不少加載工做,但造福後代啊。
因而我打算本身實現一個這樣的 bean 容器。
但在實現以前又想到一個 feature:
不如把實現 bean 容器的方案交給使用者選擇,能夠選擇使用 bean 容器,也能夠就用以前的每次都建立新的實例,就像 Spring 中的 prototype 做用域同樣。
甚至能夠自定義容器實現,好比將 bean 存放到數據庫、Redis 都行;固然通常人也不會這麼幹。
和 SPI
的機制也有點相似。
要實現上述的需求大體須要如下步驟:
BeanManager
類,由它來管理具體使用哪一種 IOC
容器。因此首先定義了一個接口;CicadaBeanFactory
:
包含了註冊和獲取實例的接口。
同時分別有兩個不一樣的容器實現方案。
默認實現;CicadaDefaultBean
:
也就是文中說道的,每次都會建立實例;因爲這種方式其實根本就沒有 bean 容器,因此也不存在註冊了。
接下來是真正的 IOC 容器;CicadaIoc
:
它將全部的實例都存放在一個 Map 中。
固然也少不了剛纔提到的 CicadaBeanManager
,它會在應用啓動的時候將全部的實例註冊到 bean
容器中。
重點是圖中標紅的部分:
CicadaBeanFactory
接口。同時也提供了一個獲取實例的方法:
就是直接調用 CicadaBeanFactory
接口的方法。
而後在上文提到的反射調用方法處就變爲:
從 bean
容器中獲取實例了;獲取的過程能夠是每次都建立一個新的對象,也能夠是直接從容器中獲取實例。這點對於這裏的調用者來講並不關心。
因此這也實現了標題所說的:可拔插
。
爲了實現這個目的,我將 CicadaIoc
的實現單獨放到一個模塊中,以 jar 包的形式提供實現。
因此若是你想要使用 IOC
容器的方式獲取實例時只須要在你的應用中額外加入這個 jar 包便可。
<dependency> <groupId>top.crossoverjie.opensource</groupId> <artifactId>cicada-ioc</artifactId> <version>2.0.0</version> </dependency>
若是不使用則是默認的 CicadaDefaultBean
實現,也就是每次都會建立對象。
這樣有個好處:
當你本身想實現一個 IOC
容器時;只須要實現 cicada
提供的 CicadaBeanFactory
接口,並在你的應用中只加入你的 jar
包便可。
其他全部的代碼都不須要改變,即可隨意切換不的容器。
固然我是推薦你們使用
IOC
容器的(其實就是單例),犧牲一點應用啓動時間帶來後續性能的提高是值得的。
cicada
的大坑填的差很少了,後續也會作一些小功能的迭代。
尚未關注的朋友趕忙關注一波:
https://github.com/TogetherOS/cicada
PS:雖然沒有仔細分析 Spring IOC 的實現,但相信看完此篇的朋友應該對 Spring IOC 以及 SpringMVC 會有一些本身的理解。
你的點贊與分享是對我最大的支持