JFinal Handler源码解析——从配置到工作原理

JFinal顶层是一个Handler链是责任链模式的一个变种,会拦截到所有请求,包括静态资源请求。

首先、我们来看看Handler的配置,我们在JFinal的Config中可用来配置自定义的Handler。

@Override
public void configHandler(Handlers me) {
    me.add(new FakeStaticHandler());
}

在这个添加JFinal内置或者我们自己的Handler,在Handlers中有一个ArrayList来存储她们。

final public class Handlers {

    private final List handlerList = new ArrayList();

    public Handlers add(Handler handler) {
        if (handler != null)
            handlerList.add(handler);
        return this;
    }

    public List getHandlerList() {
        return handlerList;
    }
}

下面、是Handler的初始化,在项目启动JFinalFilter.init初始化时执行了jfinal.init完成了对整个框架的初始化!我们的Handler也是在这里完成初始化的。

boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {
    this.servletContext = servletContext;
    this.contextPath = servletContext.getContextPath();

    initPathUtil();

    Config.configJFinal(jfinalConfig);    // start plugin and init logger factory in this method
    constants = Config.getConstants();

    initActionMapping();
    initHandler();
    initRender();
    initOreillyCos();
    initTokenManager();

    return true;
}

// 初始化Handler
private void initHandler() {
    Handler actionHandler = new ActionHandler(actionMapping, constants);
    handler = HandlerFactory.getHandler(Config.getHandlers().getHandlerList(), actionHandler);
}

大家再来看看HandlerFactory,在这里从ArrayList的尾部向头部循环,完成对每个Handler中的nextHandler参数赋值。下面是Handler的结构,她是一个单向的链表。

/**
 * Handler.
 *  * You can config Handler in JFinalConfig.configHandler() method,
 * Handler can do anything under the jfinal action.
 */
public abstract class Handler {

    protected Handler nextHandler;

    /**
     * Handle target
     * @param target url target of this web http request
     * @param request HttpServletRequest of this http request
     * @param response HttpServletRequest of this http request
     * @param isHandled JFinalFilter will invoke doFilter() method if isHandled[0] == false,
     *             it is usually to tell Filter should handle the static resource.
     */
    public abstract void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled);
}

再来、看看HandlerFactory中的getHandler方法。Handler链条的末端是ActionHandler,是专门处理action动态请求的地方。

/**
 * Build handler chain
 */
public static Handler getHandler(List handlerList, Handler actionHandler) {
    Handler result = actionHandler;

    for (int i=handlerList.size()-1; i>=0; i--) {
        Handler temp = handlerList.get(i);
        temp.nextHandler = result;
        result = temp;
    }

    return result;
}

最后、我们来看看Handler是怎么工作的

上图描述了JFinal中的一个请求的完整过程JFinalFilter->Handler->Action,请求到达Handler中之后有三种结局。

① 直接跳出链条,执行下一个Filter(如果web.xml中有配置)tomcat、jetty容器对静态资源请求处理。

如果都不满足,将返回容器级别的404,可在web.xml中配置404页。*此处的404不受JFinal配置的404页控制。

静态资源进入到ActionHandler时会被直接跳出,执行同上。请求不会到达Action。(示例代码:JFinal/ActionHandler.java)

if (target.indexOf('.') != -1) {
    return ;
}

② 请求已经在Handler完成了该有的使命。在Handler执行了render或者在response中返回了我们想要的数据。

该请求也不会到达Action,这里设置isHandled[0] = true;请求到此为止,也不会去执行后面的Filter。(示例代码:jnode/XmlHandler.java)

if (target.endsWith(".xml")) {
    String view = target.replace(".xml", ".vm");
    RenderFactory.me().getRender("/xml".concat(view)).setContext(request, response).render();
    // 跳出
    isHandled[0] = true;
    return;
}

③ 酒肉穿肠过,佛祖心中留。请求会依次经过各个Handler,抵达Action。

nextHandler.handle(target, request, response, isHandled);

参考:jfinal处理请求的流程问题:http://www.oschina.net/question/1047244_132206

JFinal2.0极速开发视频教程:http://blog.dreamlu.net/blog/79

如梦技术JFinalQQ交流群:237587118

本文首发于开源中国我的博客中:http://my.oschina.net/qq596392912/blog/504685

捐助共勉
版权声明:若无特殊注明,本文皆为原创,转载请保留文章出处。