源由

最近闲来无事,顺带看了下jfinal的源码,以下均为自己的个人理解,如有错误请指定;

jfinal 使用

  • 在web.xml中配置JfinalFilter 并定义JfinalConfig的类
  • 自定义JfinalConfig 继承抽象类JfinalConfig并实现抽象方法
  1. public abstract void configConstant(Constants me);
    public abstract void configRoute(Routes me);
    public abstract void configEngine(Engine me);
    public abstract void configPlugin(Plugins me);
    public abstract void configInterceptor(Interceptors me);
    public abstract void configHandler(Handlers me);

由上面的几个方法可以知道,我们一会就要跟上面的几个类打交道了;
Constants : 主要定义项目的常量,比如说是否是开发模式了,上传下载的根路径,默认的视图类型、上传文件的最大长度、编码等等;
Routes: 定义访问路径与controller的路由关系,可以新加Routes,如me.add(Routes routes),便于分模块;基本的me.add(controllerKey,controllerClass,viewPath),如果视图为空,则默认为controllerKey;
Engine : 指定模板引擎,是3.0新增的功能;
Plugins : 添加插件,如数据库插件、连接池插件、缓存插件等,也可以实现自己的插件;这里的plugins可以看作是一个工具类,将多个插件保存在Plugins中的列表中;
Interceptors : 添加全局的拦截器,自定义的拦截器需要实现intercept(Invocation inv)的方法,在inv中可以获取controller中的相关内容,具体可以参考ActionHandler中的handle方法;
Handlers: 添加多个处理器,这里可以看作是一个工具类,只是把多个处理器保存到列表中;

初始化逻辑

JfinalFilter

我们先看filter初始化的方法,代码量很少

  1.         createJFinalConfig(filterConfig.getInitParameter("configClass"));
    if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false) {
    throw new RuntimeException("JFinal init error!");
    }
    handler = jfinal.getHandler();
    constants = Config.getConstants();
    encoding = constants.getEncoding();
    jfinalConfig.afterJFinalStart();
    String contextPath = filterConfig.getServletContext().getContextPath();
    contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());

我们一个一个过:
createJFinalConfig : 这个就是在web.xml jfinalFilter中定义的参数:configClass,指向自定义JfinalConfig,会尝试根据字符串加载类并生成实例,赋值给该filter中的jfinalConfig;
jfinal.init() : 初化jfinal ,大部分的逻辑都在这里
handler = jfinal.getHandler() : 这一句依赖jfinal的初始化,获取Handler,大家可以会问这里为什么只有一个Handler,我定义的多个处理器哪去了? 想要了解可以看下Handler的类定义,里面有一个next的变量,类型也是Handler,没错,是一个链表,在上一步jfinal初始化过程中将Handlers中保存的多个handler组装成了一个链表,这里返回头,并且在尾部加了一个ActionHandler,用来初始化controller,想了解初始化controller的过程,请参考ActionHandler中的handle的方法;
Config.getConstants(): 在jfinal的初给化方法里,有初始化Config里的变量;

jfinal

从过滤器来看,大部分的初始化码在jfinal.init(jfinalConfig,servletContext)方法中;
代码如下:

    1. // 设置变量,不用理会
    2. this.servletContext = servletContext;
    3. this.contextPath = servletContext.getContextPath();
    4. // 根据servletContext变量来初始化PathKit工具类的webRootPath;
    5. initPathUtil();
    6. Config.configJFinal(jfinalConfig); // start plugin, init log factory and init engine in this method
    7. constants = Config.getConstants();
    8. initActionMapping();
    9. initHandler();
    10. initRender();
    11. initOreillyCos();
    12. initTokenManager();
    13. return true;


Config.configJFinal(jfinalConfig): 将jfinalConfig中定义的内容全配置到Config类中,后面的参数变量均在Config类中定义,很容易看懂,代码如下:

  1.         jfinalConfig.configConstant(constants);            initLogFactory();    initEngine();
    jfinalConfig.configRoute(routes);
    jfinalConfig.configEngine(engine);
    jfinalConfig.configPlugin(plugins); startPlugins(); // very important!!!
    jfinalConfig.configInterceptor(interceptors);
    jfinalConfig.configHandler(handlers);

initActionMapping(): 初始化ActionMapping,在这里完成路由及拦截器的功能,过程如下:
遍历Config.routes()中的路由关系,根据路由关系中定义的contrllerKey,controllerClass,viewPaht,根据controllerClass利用反射获取Before()的注解,获取controller级别的拦截器集合;通过反射获取所有的方法,再获取方法上面Before()注解来获取方法级别的拦截器集合;还可以获取routes中的路由级别的拦截器集合及Interceptormanager获取全局的拦截器集合;
然后将cotrollerKey,actionKey,conrollerClass,method,methodName,ins[],viewPath 构建为Action,再放入到以actionKey为key,action为value的map中;至此,actionMapping初始给完成,直接可以在jinal中通过actionKey来获取所有的Action对象;

initHandler(): 初始化处理器
使用HandlerFactory类将handlers中的list中的所有处理器构建为Handler的链表,并在链表尾部加入ActionHandler来完成核心功能,其中包括req/resp赋值,ins[]的执行,具体参考该类的handle方法;

initRender(); // 初始化render
initOreillyCos(); //初始化上传相关
initTokenManager(); //初始化token缓存,如果在Constants中没有设置tokenCache,则跳过;

至此 ,所有初始化完成 ;

业务请求逻辑

jfinal doFilter方法

看完之后发现核心的代码就一句:

  1. handler.handle(target, request, response, isHandled);

如果有自定义处理器,在自己的逻辑处理完成之后,记得加一句: next.handle()来执行下一个控制器;
到最后必然会执行到ActionHandler的handle方法;

ActionHandler handle方法

核心的代码也就几句:

  1. //获取controller对象
    Controller controller = action.getControllerClass().newInstance();
    //初始化controller
    controller.init(request, response, urlPara[0]);
    newInvocation(action, controller).invoke();
    Render render = controller.getRender();
    render.render();

inv.invoke(): 执行 当该action有拦截器时,先执行拦截器,ints[i++].interceptor(this);在拦截器内部完成拦截后还执行this.invoke(),一直到所有拦截器都执行完成为止;
当所有的拦截器都完成之后,this.invoke()实质上就去执行方法:action.getMethod().invoke(controllerInstance,args);
执行完成之后就去获取Render去做相应的渲染了;

//TODO 虽然大致明白了加载过程,但为什么要这么用还需要细细体会;
//TODO 看下渲染的相关过程
//TODO 看下activeRecord的思想;

jfinal 源码学习的更多相关文章

  1. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  2. jQuery源码学习感想

    还记得去年(2015)九月份的时候,作为一个大四的学生去参加美团霸面,结果被美团技术总监教育了一番,那次问了我很多jQuery源码的知识点,以前虽然喜欢研究框架,但水平还不足够来研究jQuery源码, ...

  3. MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)

    前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...

  4. MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则)

    前言:上篇介绍了下自己的MVC框架前两个版本,经过两天的整理,版本三基本已经完成,今天还是发出来供大家参考和学习.虽然微软的Routing功能已经非常强大,完全没有必要再“重复造轮子”了,但博主还是觉 ...

  5. MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)

    前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...

  6. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)

    前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎.这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之 ...

  7. 我的angularjs源码学习之旅2——依赖注入

    依赖注入起源于实现控制反转的典型框架Spring框架,用来削减计算机程序的耦合问题.简单来说,在定义方法的时候,方法所依赖的对象就被隐性的注入到该方法中,在方法中可以直接使用,而不需要在执行该函数的时 ...

  8. ddms(基于 Express 的表单管理系统)源码学习

    ddms是基于express的一个表单管理系统,今天抽时间看了下它的代码,其实算不上源码学习,只是对它其中一些小的开发技巧做一些记录,希望以后在项目开发中能够实践下. 数据层封装 模块只对外暴露mod ...

  9. leveldb源码学习系列

    楼主从2014年7月份开始学习<>,由于书籍比较抽象,为了加深思考,同时开始了Google leveldb的源码学习,主要是想学习leveldb的设计思想和Google的C++编程规范.目 ...

随机推荐

  1. 吾八哥学Python(一):搭建Python开发环境(Windows)

    学习Python的第一步当然是要配置一下开发环境了,这里记录一下本人在windows 10(64位)下配置Python开发环境的过程,供跟我一样的新手参考一下. 一.下载Python安装包 目前最新的 ...

  2. python初步(附学习思维导图)

    python,原意为蟒蛇,至于它的发展史,度娘应该比我讲述的更为专业/偷笑.这里我们要梳理的是整个学习的脉络,当然,今后的随笔也会从基础部分说起,希望能给进门python的小伙伴一些建议. 一.环境的 ...

  3. FreeType in OpenCASCADE

    FreeType in OpenCASCADE eryar@163.com Abstract. FreeType is required for text display in the 3D view ...

  4. JDBC工具类实例

    本文以讲解用单利模式实现一个简单的JDBC实用工具类JDBC连接的四个基本步骤:1.加载相应数据库驱动2.建立相应数据库连接3.构建Statement语句,即增删改查SQL语句4.执行Statemen ...

  5. Java Scanner类

    package io; import java.util.*; public class useScanner { public static void main(String[] args) { S ...

  6. Debian GNU/Linux 8.4 (jessie)编译安装php.md

    编译遇到的问题很多.网上的文章往往是记录遇到的报错,贴上对应的解决. 而实际的环境,如操作系统,安装的软件必然有差异,所以,更重要的是,如何找到解决方法(不担保按步骤做可以编译成功),并将过程自动化. ...

  7. C#设计模式之十一外观模式(Facade)【结构型】

    一.引言 快12点半了,要开始今天的写作了.很快,转眼设计模式已经写了十个了,今天我们要讲[结构型]设计模式的第五个模式,该模式是[外观模式],英文名称是:Facade Pattern.我们先从名字上 ...

  8. Leetcode题解(十四)

    39.Combination Sum 题目 题目要求找出和为target的数字组合,并且每个整数可以多次使用.仔细思考可以发现,这道题目可以采用递归的方法来完成,比如举的例子,target=7,一开始 ...

  9. escape、unescape、encodeURIComponent、decodeURLComponent

    项目中遇到的问题,当我设置一个标签的属性,这个属性值含有js内容,这样就会被执行产生安全问题 解决办法:,可以将后端给的内容先encodeURIComponent,获取的时候再decodeURICom ...

  10. http 500错误怎么解决方法

    出现500错误的原因是很多的,一般来说,如果程序出错,那么在浏览器内会返回给用户一个友好的错误提示,统一称之为服务器500错误. 解决的方法就是您必须在http中能够正确的获得错误信息,方法为:请打开 ...