设计一个可拔插的 IOC 容器
前言
磨了许久,借助最近的一次通宵上线 cicada 终于更新了 v2.0.0
版本。
之所以大的版本号变为 2,确实是向下不兼容了;主要表现为:
- 修复了几个反馈的
bug
。 - 灵活的路由方式。
- 可拔插的
IOC
容器选择。
其中重点是后面两个。
新的路由方式
先来看第一个:路由方式的更新。
在之前的版本想要写一个接口必须的实现一个 WorkAction
;而且最麻烦的是一个实现类只能做一个接口。
因此也有朋友给我提过这个 issue。
于是改进后的使用方式如下:
是否有点似曾相识的感觉。
如上图所示,不需要实现某个特定的接口;只需要使用不同的注解即可。
同时也支持自定义 pojo
, cicada
会在调用过程中对参数进行实例化。
拿这个 getUser
接口为例,当这样请求时这些参数就会被封装进 DemoReq
中.
http://127.0.0.1:5688/cicada-example/routeAction/getUser?id=1234&name=zhangsan
同时得到响应:
{"message":"hello =zhangsan"}
实现过程也挺简单,大家查看源码便会发现;这里贴一点比较核心的步骤。
- 扫描所有使用
@CicadaAction
注解的类。 - 扫描所有使用
@CicadaRoute
注解的方法。 - 将他们的映射关系存入
Map
中。 - 请求时根据
URL
去Map
中查找这个关系。 - 反射构建参数及方法调用。
扫描类以及写入映射关系
请求时查询映射关系
反射调用这些方法
是否需要 IOC 容器
上面那几个步骤其实我都是一把梭写完的,但当我写到执行具体方法时感觉有点意思
了。
大家都知道反射调用方法有两个重要的参数:
obj
方法执行的实例。args..
自然是方法的参数。
我第一次写的时候是这样的:
method.invoke(method.getDeclaringClass().newInstance(), object);
然后一测试,也没问题。
当我写完之后 review
代码时发现不对:这样这里每次都会创建一个新的实例,而且反射调用 newInstance()
效率也不高。
这时我不自觉的想到了 Spring 中 IOC 容器,和这里场景也非常的类似。
在应用初始化时将所有的接口实例化并保存到 bean 容器中,当需要使用时只需要从容器中获取即可。
这样只是会在启动时做很多加载工作,但造福后代啊。
可拔插的 IOC 容器
于是我打算自己实现一个这样的 bean 容器。
但在实现之前又想到一个 feature:
不如把实现 bean 容器的方案交给使用者选择,可以选择使用 bean 容器,也可以就用之前的每次都创建新的实例,就像 Spring 中的 prototype 作用域一样。
甚至可以自定义容器实现,比如将 bean 存放到数据库、Redis 都行;当然一般人也不会这么干。
和 SPI
的机制也有点类似。
要实现上述的需求大致需要以下步骤:
- 一个通用的接口,包含了注册容器、从容器中获取实例等方法。
BeanManager
类,由它来管理具体使用哪种IOC
容器。
所以首先定义了一个接口;CicadaBeanFactory
:
包含了注册和获取实例的接口。
同时分别有两个不同的容器实现方案。
默认实现;CicadaDefaultBean
:
也就是文中说道的,每次都会创建实例;由于这种方式其实根本就没有 bean 容器,所以也不存在注册了。
接下来是真正的 IOC 容器;CicadaIoc
:
它将所有的实例都存放在一个 Map 中。
当然也少不了刚才提到的 CicadaBeanManager
,它会在应用启动的时候将所有的实例注册到 bean
容器中。
重点是图中标红的部分:
- 需要根据用户的选择实例化
CicadaBeanFactory
接口。 - 将所有的实例注册到 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 会有一些自己的理解。
你的点赞与分享是对我最大的支持
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
用any-loader封装jQuery的XHR —— 随便写着玩系列
哎,都说没人用JQuery啦,叫你别写这个。 其实我也是好高骛远使用过npm上某个和某个很出名的XHR库,嗯,认识我的人都知道我喜欢喷JQ,以前天天喷,见面第一句,你还用JQ,赶紧丢了吧。但我也是用过了npm那些脑残玩意,才知道,艾玛,其实$.ajax还不错,于是乎,我又开始天天喷那些某某知名类库。今天到处都能看到jQuery老矣的话题,饭否(不是jQuery能饭否,是用jQuery的人能饭否)?嗯,其实我觉得jQ还是可堪一用的,prop、attr、data,以及$.fn的扩展,这些方面还是很实用的,特别是基于此结合React.js用来做Web组件使用。 嗯,是的,自从2016年折腾过了一年用Reactjs大前端化(全站前后台都用),到今天为止我始终只是把React.js作为组件库来使用。彻底的纯前端化,所要解决的难题,太多太多,有一些问题可能都超越目前的技术极限。做网站做项目,不是一个纯粹的技术理想化的事情。传统服务器端输出有着大量的技术积累,框架积累,能够迅速的解决项目需求,满足市场发展需要,能确保公司、资金、项目、市场良性的互动。对任何团队,就算用antd这些全家桶,仍然要求团队...
- 下一篇
基于Spring Boot实现图片上传/加水印一把梭操作
文章共 537字,阅读大约需要 2分钟 ! 概述 很多网站的图片为了版权考虑都加有水印,尤其是那些图片类网站。自己正好最近和图片打交道比较多,因此就探索了一番基于 Spring Boot这把利器来实现从 图片上传 → 图片加水印 的一把梭操作! 注: 本文首发于 My Personal Blog:程序羊,欢迎光临 小站 本文内容脑图如下: 搭建 Spring Boot基础工程 过程不再赘述了,这里给出 pom中的关键依赖: <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-star...
相关文章
文章评论
共有0条评论来说两句吧...