磨了许久,借助最近的一次通宵上线 cicada 终于更新了 v2.0.0
版本。java
之因此大的版本号变为 2,确实是向下不兼容了;主要表现为:git
bug
。IOC
容器选择。其中重点是后面两个。github
先来看第一个:路由方式的更新。数据库
在以前的版本想要写一个接口必须的实现一个 WorkAction
;并且最麻烦的是一个实现类只能作一个接口。json
所以也有朋友给我提过这个 issue。性能
因而改进后的使用方式以下:测试
是否有点似曾相识的感受。prototype
如上图所示,不须要实现某个特定的接口;只须要使用不一样的注解便可。3d
同时也支持自定义 pojo
, cicada
会在调用过程当中对参数进行实例化。code
拿这个 getUser
接口为例,当这样请求时这些参数就会被封装进 DemoReq
中.
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 会有一些本身的理解。
你的点赞与分享是对我最大的支持