博客
关于我
JFinal个人学习笔记之源码分析2
阅读量:322 次
发布时间:2019-03-04

本文共 9663 字,大约阅读时间需要 32 分钟。

本篇是接着上篇讲

上篇我们讲到了`actionMapping.buildActionMapping();`源码:
void buildActionMapping() {        mapping.clear();        Set
excludedMethodName = buildExcludedMethodName(); InterceptorManager interMan = InterceptorManager.me(); for (Entry
> entry : routes.getEntrySet()) { Class
controllerClass = entry.getValue(); Interceptor[] controllerInters = interMan.createControllerInterceptor(controllerClass); boolean sonOfController = (controllerClass.getSuperclass() == Controller.class); Method[] methods = (sonOfController ? controllerClass.getDeclaredMethods() : controllerClass.getMethods()); for (Method method : methods) { String methodName = method.getName(); if (excludedMethodName.contains(methodName) || method.getParameterTypes().length != 0) continue ; if (sonOfController && !Modifier.isPublic(method.getModifiers())) continue ; Interceptor[] actionInters = interMan.buildControllerActionInterceptor(controllerInters, controllerClass, method); String controllerKey = entry.getKey(); ActionKey ak = method.getAnnotation(ActionKey.class); String actionKey; if (ak != null) { actionKey = ak.value().trim(); if ("".equals(actionKey)) throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank."); if (!actionKey.startsWith(SLASH)) actionKey = SLASH + actionKey; } else if (methodName.equals("index")) { actionKey = controllerKey; } else { actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName; } Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey)); if (mapping.put(actionKey, action) != null) throw new RuntimeException(buildMsg(actionKey, controllerClass, method)); } } // support url = controllerKey + urlParas with "/" of controllerKey Action action = mapping.get("/"); if (action != null) mapping.put("", action); }
我们看到`Set
excludedMethodName = buildExcludedMethodName();` 这里buildExcludedMethodName方法:
private Set
buildExcludedMethodName() { Set
excludedMethodName = new HashSet
(); Method[] methods = Controller.class.getMethods(); for (Method m : methods) { if (m.getParameterTypes().length == 0) excludedMethodName.add(m.getName()); } return excludedMethodName; }
从代码中我们可以看出先创建了一个HashSet
,猜也能猜出是为了除去重复。接着`Controller.class.getMethods();`方法是利用了反射。①Controller.class获得了Controller类的Class对象。之后又调用了getMethods()方法,获得了Controller类中的所有方法,也就说它的返回值是个数组,里面存的全是Controller类中的方法。接着它又执行一个循环,该循环里if判断`m.getParameterTypes().length == 0`,其中`m.getParameterTypes()`是获取到遍历的当前方法的参数数组。可以看出,这个循环最终保存是Controller方法中无参的方法名。我们再回到ActionMapping中的buildActionMapping方法中。`InterceptorManager interMan = InterceptorManager.me();`该方法获得了一个`InterceptorManager`对象。InterceptorManager我认为应该是个拦截器管理者;管理 控制层、业务层全局拦截器。我们再回到ActionMapping中的buildActionMapping方法中。看到接下来是个for循环。这里是对routes进行遍历。这里的routes对象是我们在JFinal类中执行`Config.configJFinal(jfinalConfig);`语句时,已经初始化了的。它是Config类的一个属性。所以打断点时,你会发现他是`com.jfinal.core.Config$1@1a245833`。而它里面遍历的键值对就是:`/blog=class com.demo.blog.BlogController, /=class com.demo.index.IndexController`接着开始分析该循环,
for (Entry
> entry : routes.getEntrySet()) { Class
controllerClass = entry.getValue(); Interceptor[] controllerInters = interMan.createControllerInterceptor(controllerClass); boolean sonOfController = (controllerClass.getSuperclass() == Controller.class); Method[] methods = (sonOfController ? controllerClass.getDeclaredMethods() : controllerClass.getMethods()); for (Method method : methods) { String methodName = method.getName(); if (excludedMethodName.contains(methodName) || method.getParameterTypes().length != 0) continue ; if (sonOfController && !Modifier.isPublic(method.getModifiers())) continue ; Interceptor[] actionInters = interMan.buildControllerActionInterceptor(controllerInters, controllerClass, method); String controllerKey = entry.getKey(); ActionKey ak = method.getAnnotation(ActionKey.class); String actionKey; if (ak != null) { actionKey = ak.value().trim(); if ("".equals(actionKey)) throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank."); if (!actionKey.startsWith(SLASH)) actionKey = SLASH + actionKey; } else if (methodName.equals("index")) { actionKey = controllerKey; } else { actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName; } Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey)); if (mapping.put(actionKey, action) != null) throw new RuntimeException(buildMsg(actionKey, controllerClass, method)); } }
首先它执行是`interMan.createControllerInterceptor(controllerClass)`方法。它是把遍历到的Controller的Class,作为参数传入进去。该方法源码:
// 此处不缓存控制层 Class 级拦截器,已经在 com.jfinal.core.Action 对象中缓存    public Interceptor[] createControllerInterceptor(Class
controllerClass) { return createInterceptor(controllerClass.getAnnotation(Before.class)); }
可以看到它通过Class调用用了getAnnotation()方法。该方法会返回Controller上被Before注解包裹的拦截器。例如:
@Before(BlogInterceptor.class)public class BlogController extends Controller {   }
那么getAnnotation方法就会返回Before注解。例如`@com.jfinal.aop.Before(value=[class com.demo.blog.BlogInterceptor])`接着嵌套调用了`createInterceptor(beforeAnnotation.value());`方法。其中`beforeAnnotation.value()`得到的就是使用Before注解包裹的全类名数组。比如:`[class com.demo.blog.BlogInterceptor]`.接着我们看看createInterceptor(beforeAnnotation.value())的源码。
public Interceptor[] createInterceptor(Class
[] interceptorClasses) { if (interceptorClasses == null || interceptorClasses.length == 0) { return NULL_INTERS; } Interceptor[] result = new Interceptor[interceptorClasses.length]; try { for (int i=0; i
从上面代码中我们可以看出,如何我们没有使用自定义拦截器,它会return一个`NULL_INTERS`,而`NULL_INTERS`是一个Interceptor[]。
public static final Interceptor[] NULL_INTERS = new Interceptor[0];
这里需要注意的是,Interceptor是个接口,这里`new Interceptor[0]`不是new一个接口,而是new了这个接口的实现类的数组。说白了它就是new了一个数组,类型是Interceptor,只不过Interceptor是个接口罢了。我们回到createInterceptor()方法。接下来是`Interceptor[] result = new Interceptor[interceptorClasses.length];`这里根据Before注解得到的Interceptor类数组大小类创建一个`Interceptor`数组。接着又是个循环,目的是为了通过循环创建相应的实例类(用反射)。并且保存到`InterceptorManager`类中`singletonMap`属性中去。该属性是ConcurrentHashMap类型,HashMap是非线程安全的。官方的说singletonMap是单例拦截器。最后singletonMap保存的是key拦截器的Class,value是拦截器的实例。最后return(返回)存储了自定义拦截器的实例的数组。我们再回到`buildActionMapping()`的方法中。看到`boolean sonOfController = (controllerClass.getSuperclass() == Controller.class);`这里判断遍历到的Controller的父类是不是Controller类型。也就是说该Controller有没有继承Controller类。接着下面这句`Method[] methods = (sonOfController ? controllerClass.getDeclaredMethods() : controllerClass.getMethods());`意思是:如果是继承了Controller类,则调用`getDeclaredMethods()`方法。否则调用`getMethods()`的方法。getMethods()返回的是包括此`Class`对象所表示的类或接口的公共 member方法。也就是说该数组类返回包含的从Object 类继承的所有(公共)member 方法。getDeclaredMethods方法:返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。接着下面又是个循环,遍历之前得到的methods`interMan.buildControllerActionInterceptor`我们再看到`interMan.buildControllerActionInterceptor(controllerInters, controllerClass, method);`方法。该方法也是嵌套了很多层。最后一层的`doBuild(5个参数)` 方法中的`createInterceptor(method.getAnnotation(Before.class));`这个方法之前也讲解过。只不过这次调用getAnnotation()方法的是method。说白了,就是之前是获取controller层的拦截器,而这次是为了获得方法层(method)的拦截器。最后这个doBuild方法返回的是:list数组,里面存储的都是相应拦截器的实例。我们再回到ActionMapping类中的buildActionMapping方法。接下来`entry.getKey()`获得controllerKey。接下来`method.getAnnotation(ActionKey.class)`这里应该是获得jfinal自定义的注解ActionKey,接下来的if判断就是对路径进行组装,就是把methodName组装进去。例如:/blog/add、/blog/update等等。最后它会根据上面的参数new一个action出来。
Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey));
if (mapping.put(actionKey, action) != null)                    throw new RuntimeException(buildMsg(actionKey, controllerClass, method));
这里的mapping.put(actionKey, action)是有返回值的,如果保存的key在mapping中已经存在了,那么它会保存新值,并且返回原来的旧值。如果不存在就为null。至此,buildActionMapping()方法执行完毕。到这里我们也就知道这里封装了controller的信息,controller类中每个方法且方法层的拦截器和路由都封装在一个action(new 出来的)。而每个new出来的action,最后有保存在mapping中。key是路由,value是相对于的action在执行完循环后最后还有一段代码:
Action action = mapping.get("/");        if (action != null)            mapping.put("", action);
官方的解释是:`// support url = controllerKey + urlParas with "/" of controllerKey`为了支持这种格式的路由。之后我们就回到了JFinal类中的initActionMapping()方法中的`Config.getRoutes().clear();` 方法。这个方法清除掉了Routes中的map与viewPathMap。这些信息都已经保存到了相应的action中。至此 initActionMapping()方法执行完成。

转载地址:http://qzfh.baihongyu.com/

你可能感兴趣的文章
快速排序
查看>>
Pyinstaller打包的exe文件过大的解决方法
查看>>
Linux的软链接跟Windows快捷方式一样?
查看>>
更改github的默认语言类型
查看>>
使用bigdecima实例化时传int和string时的精度丢失
查看>>
使用第三方sdk,微信wechat扫码登录
查看>>
windows下的netstat命令略解和linux下的netstat命令/awk打印或分割字符串
查看>>
mysql中的行转列
查看>>
shell脚本中冒泡排序、直接排序、反转排序
查看>>
WPS及Excel中Alt键的妙用 快捷键
查看>>
C - 食物链 并查集
查看>>
Pycharm 常用快捷键
查看>>
ValueError: check_hostname requires server_hostname
查看>>
基于LabVIEW的入门指南
查看>>
PCB布局系列汇总
查看>>
电阻入门知识
查看>>
电容入门知识
查看>>
C++面向对象
查看>>
专题(七)贪心——AcWing 112. 雷达设备
查看>>
深入理解JVM(一)JVM概述、类的声明周期、JVM整体架构、JMM、volatile
查看>>