模仿基本的web框架。
- 配置:先从最简单的变量配置开始,后续手写
xml
解析器添加上去。 - 注解:包含
controller
注解,被该注解标记的类是控制器,@requestMapping
注解,配置路由的url
- 依赖注入:使用
@Inject
注解,可以配置需要注入的类,以及主要注入类的实现类 ioc
容器,基本的注解扫描后的类对象都会存放在此处,使用的是Map<Class<?>, Object>
来实现类的单例对象。
基本的实现思路:
- 设置注解,这里用到的注解一般都为运行时的注解,因为需要根据反射获得该注解以及对应的值
- 实现文件(包)的扫描的扫描器
- 使用
IOC
容器实现类和对象的映射,用来存放类对应的对象,这样就能保证任何基于该类的反射操作的对象是唯一的那个对象 - 使用
Map
存放url
和对应需要执行方法的映射
基本的实现历程:
-
刚开始就只想做个简单的可以配置
controller
和requestMapping
的简单反射练习。 -
其中首先碰到的问题就是如何找到这些注解,参考了朋友李xx的答案,可以建立一个文件扫描,把配置的包进行一遍扫描即可。
-
再者碰到的问题就是如何根据
url
可以找到对应的类,最初实现的思路就是参考jfinal
的概念,设计了Action
的概念,我决定使用Action
来表示一次请求,反射操作的对象就保存在Action
中,此时的Action
设计如下。public class Action { // 保存需要的类对象 private Object classObject; private Method method; private Object[] args; // 这个方法是我当时设计的一个错误,还是记录下来吧 public void keepClassElseClear() { this.method = null; this.args = null; } }
因为当时的我搞混的一个概念,所以这块成为最后调试的一个大
bug
,在这里先说一下吧,就是我当时是这样设计的,因为一个类有很多方法,所以我觉得把单个类的对象保存下来,因为类对象是相同的,我想到对象可以复用,觉得清除类对象以外的就好了,然后就写出了如下代码。public void assembleMethodLevel(Class<?> cls) { final String className = cls.getName(); Action action = new Action(cls); for(Method method : cls.getDeclaredMethods()) { action.keepClassElseClear(); action.setMethod(method); // 等等 putActionInUrlMApping(cls + '/' + method.getName(), action); } }
当然,一眼就能看出来这个问题在哪,我以为对象能复用,然后每次只需要修改
method
就好了,然后把它放入url和mapping映射的Map中
。这样做的后果就是对象是固定的,所以放入的映射全部都会指向一个对象。 -
当时实现的简单,测试的方法也只有一个方法,所以没有什么大问题,想到有点简单,而且在我实际操作过程中,有使用到很多显式
new
的对象,然后我就觉得有点混乱,不方便修改,而且很麻烦,就想到加入一个依赖注入。 -
此时,我先前设计的弊端就暴露出来了,把对象放在
Action
中,依赖注入的类对象和Action
对应的对象,二者反射的对象不一样怎么办,我就想到线程池,(虽然我没有用过线程池,但是我觉得这种思想可以借鉴),然后我决定设计一个类和对象映射的ObjectPool
,相当于对于每个类只创建一个对象,然后把它们放入一个Map<Class<?>, Object>
中,这样,就保证了类对象的单例,我觉得这算是一种对象复用吧。因此设计了我认为的ObjectPool
,好像这个是叫IOC
吧,我也不知道,关于依赖注入和动态代理我都是在一个公众号码农翻身
上面找到的,通俗易懂,根据那个我很快理解了这些概念。十分推荐。 -
介于我之前看过的书
重构,改善既有代码的设计
,我的功能调整的很轻松,因为都比较通俗,代码组织我个人感觉还可以,所以,马上就做了修改,成效不错,成功了。 -
对于之前设计的很多接口,后续很多都删掉了,没有用,但是还有一个扫描的接口让我觉得大有可为,我就加上了,可以进行控制器以及依赖注入的扫描,将其分开,再加入新的东西,直接放进去就可以。
-
后续会补上
AOP
动态代理,以及支持Action
的参数注入,以及一个简单的XML
解析器