您的位置:首页 > 移动开发

JFinal源码分析------初始化那些事儿3之ActionMapping

2013-05-30 22:14 441 查看
今儿话题,ActionMapping,这个过程主要是建立起你URL访问使用具体是使用哪儿个Action去处理你的请求,这个过程主要也是也是发生在JFinalFilter初始化过程中的,下面我们就具体好好分析分析,ActionMapping他是如何做的,他的内部是如何实现的,上篇博文中我们就说过,ActionMapping是我认为最巧妙的地方,如何巧妙,我尽量用我自己对JFinal的理解去解释这么过过程!!先看代码:

<!-- lang: java -->

private void initActionMapping() {
actionMapping = new ActionMapping(Config.getRoutes(), Config.getInterceptors());
actionMapping.buildActionMapping();
}

我们看到在initActionMapping中是这样定义的,他主要是做了一下的两件事情:
1、创建一个ActionMapping的实例,初始化他的routes,和interceptors,具体的作用是什么,一会详细说说
2、创建ActionMapping(也就是Action的映射)

我们打开ActionMapping发现有如下的类属性:

private static final String SLASH = "/";
private Routes routes;
private Interceptors interceptors;

private final Map<String, Action> mapping = new HashMap<String, Action>();

当我们的程序执行到这个ActionMapping文件时候,刚刚我们看到的routes,interceptors属性在我们的ActionMapping的构造函数中已经被初始化了,还有一个就是我们的mapping类属性,大家能看到,这个是一个Map集合类型,你能猜到他是做什么的么??

也许你能猜到,其实这个就是我们装载我们Action映射的容器,因为Map这个东西通过Key来得到Value,(也就是我们所说的键值对),有这个以后,我们就直接可以通过我们的Key去取得我们先要的Action了,当然,理论是这么个理论,但是如何实现的话, 我们就需要通过分析BuildActionMapping的方法去找寻我们的答案了!!由于BuildActionMapping中的代码比较多,那么我只能选取一些我认为比较重要的代码进行解析,有遗漏的欢迎各位不全,不胜感激!!!

进入buildActionMapping方法,我们可以看到有这样么一段代码:
Set<String> excludedMethodName = buildExcludedMethodName();
这个主要是做啥的?不知道的话 我们就找到这个方法,然后看看 他做了啥?

private Set<String> buildExcludedMethodName() {
Set<String> excludedMethodName = new HashSet<String>();
Method[] methods = Controller.class.getMethods();
for (Method m : methods) {
if (m.getParameterTypes().length == 0)
excludedMethodName.add(m.getName());
}
return excludedMethodName;
}

喏,看吧 他是想获取Controller中所有的类的方法,然后通过循环的方式,找出那些个么有不带参数的方法,并且减那些不带参数的方法添加至一个HashSet的集合类型当中。他为什么要做这个操作,以及他的意图何在?先别急,接着往下看。

当我们获取了上述的方法的执行结果之后,我们看看后面的几句代码:

//创建一个interceptorBuilder实例,这个不用解释了吧,搞过JAVA的都会啊
InterceptorBuilder interceptorBuilder = new InterceptorBuilder();

//这个就是获取所有的Interceptor,然后全部转换成为数组然后保存
Interceptor[] defaultInters = interceptors.getInterceptorArray();

//使用interceptorBuilder建立defaultInters 映射
interceptorBuilder.addToInterceptorsMap(defaultInters);

这三个的操作主要是完成对JFinal框架中默认提供的Interceptor进行加载并且映射,步骤基本就是上面说的那些

顺便插一句题外话:

public Interceptors add(Interceptor globalInterceptor) {
if (globalInterceptor != null)
this.interceptorList.add(globalInterceptor);
return this;
}

还记不记得在我们的自定义继承JFinalCofig那个中有一个
public void configInterceptor(Interceptors me) {
....
}

这个方法,根据JFinal文档说要注册全局的Interceptor要在这里加,现在看到这个,你应该知道为什么作者要特殊的声明说 "Global级拦截器要在JFinalConfig.configInterceptor(Interceptors me)中进行配置“(这是作者的原话,有错误不要找我)

好了,继续回到我们的话题,继续看代码:
下面就会有一个循环迭代,代码如下:
for (Entry<String, Class<? extends Controller>> entry : routes.getEntrySet()) {
....
}
有没有看到熟悉的变量了?”routes“,这个我们刚刚初始化过的,他现在有值了,现在我告诉你这个routes他从哪儿来??他就从下面的方法中来:

public void configRoute(Routes me) {
....(这里是你配置的路由,对吧??)
}

他迭代的就是你这里面所配置的所有路由信息,然后一个一个的将其迭代出他的值,看到以下代码
Class<? extends Controller> controllerClass = entry.getValue();

你是不是感觉反射又来了,恭喜你 都会抢答了,这个框架中就是大量的使用了Java的反射技术,以前都不知道这个是干啥用的,现在我终于似乎好像有点明白了。看到这里,你可能会问,他为什么或得的值是一个Controller类型的,答案就在这里:
public void configRoute(Routes me) {
me.add("/", CommonController.class);(在路由中你是这样写的,对吧??)
}
所以,在迭代routes的时候,他不获取Controller,他拿什么??嘿嘿....

继续向下(额.....分析这个方法,好累,太多了)

//构建一个ControllerInter数组,用来装所有的Controller级别的ControllerInter

Interceptor[] controllerInters = interceptorBuilder.buildControllerInterceptors(controllerClass);
喏,Jfinal框架中的另外一个级别的拦截器出来了(Controller级别),以后被人问起来说,Controller级别的Interceptor什么时候被加载创建的,这就是答案啊!!

//获取某个Controller中的所有的Method,记住这个Controller是我们自己定义,继承Controller类的那个Controller(额,好拗口)
Method[] methods = controllerClass.getMethods();

刚刚我们得到了某一个Controller中的所有方法,然后又开始一个循环,完成对这个获取这个Controller中的所有方法,然后进行迭代,具体代码可以看源码,这个里面的代码太长了,我还是挑重要的说。

当我们进入一下的循环以后,主要做了一下操作:
1、获取method[]中的每一个方法名
2、检查这个方法名是否包含在我们刚刚获取的excludedMethodName中,并且还要检查该方法是否有参数,加入不在excludedMethodName中,并且也没有任何参数,则进入第3步
3、分别构造一个Action级别的MethodInterceptor和构造一个ActionInterceptors,并且获取controllerkey
4、看看有没有使用ActionKey这个注解符,并且对Actionkey注解符中设定的值继续合理性的验证,验证无误以后,新建一个action实例,然后将该实例放入放入mapping这个类型集合中
5、当我们的Action中没有放入Actionkey注解符,就先看看methodname是不是”index“,(我们知道index这个是Controller中默认的一个方法),如果是,则创建一个Action实例,将这个action实例放入mapping这个集合变量中去。

6、假如我们在Controller了中没有使用ActionKey,我们的方法名称是index以外的方法,那么我们就按照这样的方式来构造actionkey(当然创建action实例,是和上面类似的,因为他们使用的是一个action创建的方法)

actionkey的格式
String actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName;

这个够清楚了吧,格式就是这样了。如果以后再出现action无法访问,那么,你就需要从这里来找原因了

7、在最后,我们从mapping中获取”/“对应的方法,等待着触发

完整至此,ActionMapping中的映射建立了。哎哟,妈呀 可把我累坏了!!关于ActionMapping的好处,或者是其他的一些特点,下次再开扒吧!!因为扒源码真的是个力气活!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息