JAVA反射+运行时注解实现URL路由

一直想了解一下Spring mvc这套框架,但是每次看完就头大,大量的注解、XML配置让人捉摸不透。

为了减少一些痛苦,我决定简单的学习一下JAVA的反射与注解,实现一个简单的URL路由来验证这些高级功能。

目标

最终我可以写一些Controller类,在里面通过注解配置URL路由:

访问/login时,路由应该调用IndexController.actionLogin方法;访问/logout时,路由应该调用IndexController.actionLogout方法。

对于一个强类型语言来说,如何实现这样的动态效果呢?答案就是:注解,反射。

预备知识

我是通过学习这篇博客对注解有了基本的掌握,建议大家也先学习一下:《自己动手实现JAVA注解》。

注解

上面使用的@RouteMapping是一个注解,它声明了action方法对应的URI地址是什么。

注解相当于对方法附加了一些描述信息,后续可以通过反射机制获得注解里的信息,从而获知action对应的uri是/login还是/logout。

定义注解需要使用@interface语法,Target说明注解可以用于一个类方法还是一个类成员变量。

Retention说明注解在什么阶段可以被访问,这里我的需求是在程序运行时通过反射解析注解里的uri变量,所以配置了RUNTIME。

注册路由

Spring是通过XML配置指定controller类存储的目录,这样Spring框架会在初始化时扫描下面的所有class,解析其中的注解并生成路由表。

为了简化,我这里需要显式的向路由添加controller的完整class名称,避免扫描目录的步骤:

Router是路由器类,它查找controller的根路径是target/classes,这个目录存放了所有controller编译后的.class文件。

接下来通过addRouter注册一个controller到路由器,Router会根据类名在target/classes目录下找到对应的.class文件进行类加载。

此后,通过testRoute方法进行测试,传入一个URI会触发某个action被调用。

路由器

addRouter首先调用controllerLoader对象从磁盘上的.class文件加载对应的controller类。

这里用到了JAVA的另外一个重要概念就是class loader,我是通过这篇博客学习的:《深入探讨JAVA类加载器》。

无论如何,在这里IndexController类在运行时从.class文件被加载到运行时环境中,也就是得到了对应的class对象。

通过class对象可以进行反射,得到这个类的方法,再解析方法上的注解。

如果注解对象的class类型等于RouteMapping.class,就获取注解对象的uri属性,也就是之前@RouteMapping(uri=…)配置的属性。

通过controllerBeans维护controller单例对象,通过uri2Action维护uri -> action的关联关系。

Action

所谓action就是一个接口,它使用单例controller对象作为调用主体,通过method反射可以完成方法的调起:

相当于object.method(),应该不难理解

最后,testAction方法根据uri在uri2Action中找到对应的Action对象,通过action.call()唤起对应的处理方法。

class loader

实现自己的class loader,只需要覆写findClass方法,在该方法中将对应的类文件读取进来,通过defineClass方法完成加载,最后返回即可。

最后

项目地址:https://github.com/owenliang/annotation

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~