JFinal实现原理

                        JFinal学习笔记

一切都从web.xml开始说起:

当服务器初始化的时候会初始化web.xml里面的相关配置信息。下面我们来看一个重要的过滤器配置:JFinalFilter。下面是相关的配置信息

<filter>

        <filter-name>jfinal</filter-name>

        <filter-class>com.jfinal.core.JFinalFilter</filter-class>

<init-param>

<param-name>configClass</param-name>

<param-value>demo.DemoConfig</param-value>

</init-param>

    </filter>

    <filter-mapping>

        <filter-name>jfinal</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

</filter>

这就意味着所有的请求都要经过JFinalFiter过滤了

从中我们可以看到在web.xml之中配置了一个名为JFinalFilter的过滤器。下面我们来看看JFinalFiter的源码。

public final class JFinalFilter implements Filter {

   

    private Handler handler;

    private String encoding;

    private JFinalConfig jfinalConfig;

    private Constants constants;

    private static final JFinal jfinal = JFinal.me();

    private static Logger log;

    private int contextPathLength;

    //系统在初始化Servlet的时候自动调用该方法

    public void init(FilterConfig filterConfig) throws ServletException {

       //创建JFianlConfig对象

       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();

       //如果项目路径为null或者只有一个'/',就定义项目路径的长度为0,否则还是其原来的长度。

       contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());

    }

    //requestresponse的作用不用过多介绍了。这个FilterChain的左右主要是用来连续调用下一个Filter时候使用的,下面给出了FilterChain的作用介绍

     /**

    * A FilterChain is an object provided by the servlet container to the developer

    * giving a view into the invocation chain of a filtered request for a resource. Filters

    * use the FilterChain to invoke the next filter in the chain, or if the calling filter

    * is the last filter in the chain, to invoke the resource at the end of the chain.

    *

    * @see Filter

    * @since Servlet 2.3

    **/

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

       HttpServletRequest request = (HttpServletRequest)req;

       HttpServletResponse response = (HttpServletResponse)res;

       request.setCharacterEncoding(encoding);

      

       String target = request.getRequestURI();

       if (contextPathLength != 0)

           //得到其ServletPath以及相关的参数

           target = target.substring(contextPathLength);

      

       boolean[] isHandled = {false};

       try {

           //idHandler用来判断该Target是否应该被相应的handler处理

//这是整个Filter的最核心方法

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

       }

       catch (Exception e) {

           if (log.isErrorEnabled()) {

              String qs = request.getQueryString();

              log.error(qs == null ? target : target + "?" + qs, e);

           }

       }

      

       if (isHandled[0] == false)

           chain.doFilter(request, response);

    }

   

    public void destroy() {

       jfinalConfig.beforeJFinalStop();

       jfinal.stopPlugins();

    }

   

    private void createJFinalConfig(String configClass) {

       if (configClass == null)

           throw new RuntimeException("Please set configClass parameter of JFinalFilter in web.xml");

      

       try {

           Object temp = Class.forName(configClass).newInstance();

           if (temp instanceof JFinalConfig)

              jfinalConfig = (JFinalConfig)temp;

           else

              throw new RuntimeException("Can not create instance of class: " + configClass + ". Please check the config in web.xml");

       } catch (InstantiationException e) {

           throw new RuntimeException("Can not create instance of class: " + configClass, e);

       } catch (IllegalAccessException e) {

           throw new RuntimeException("Can not create instance of class: " + configClass, e);

       } catch (ClassNotFoundException e) {

           throw new RuntimeException("Class not found: " + configClass + ". Please config it in web.xml", e);

       }

    }

   

    static void initLogger() {

       log = Logger.getLogger(JFinalFilter.class);

    }

}

让我们重点看看这个handler的由来。

首先由handler = jfinal.getHandler();知道这个handler是由jfinal对象得来的,现在让我们看看jfinal的部分源码:

public final class JFinal {

    private Constants constants;

    private ActionMapping actionMapping;

    private Handler handler;。。。。。定义了其他成员变量

 

 

Handler getHandler() {

        return handler;

    }

private static final JFinal me = new JFinal();

//初始化JFinal时候调用的方法(在上面已经提到过这一点)

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();

       initI18n();

       initTokenManager();

      

       return true;

    }

private void initHandler() {

       Handler actionHandler = new ActionHandler(actionMapping, constants);

       handler = HandlerFactory.getHandler(Config.getHandlers().getHandlerList(), actionHandler);

    }

}

由这里我们知道handler是由HandlerFactorygetHandler方法得来的。

让我们再次看看HandlerFactory的部分源码以探个究竟:

public class HandlerFactory {

    private HandlerFactory() {

    }

    /**

     * Build handler chain

     */

    public static Handler getHandler(List<Handler> 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;

    }

}

显然这里返回的是一个actionHandler为首handler chain

让我们再来看看这个:

Handler actionHandler = new ActionHandler(actionMapping, constants);

       handler = HandlerFactory.getHandler(Config.getHandlers().getHandlerList(), actionHandler);

此处传进去并不是简单的handler,而是他的字类ActionHandler,并且传进去了有两个参数,一个是ActionMapping类的变量,一个是constants。对于后者将就是一些常量的设置所以不进行过多介绍。让我们先看看ActionMapping之后再来看这个ActionHandler

final class ActionMapping {

    private static final String SLASH = "/";

    private Routes routes;

    private Interceptors interceptors;

   

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

   

    ActionMapping(Routes routes, Interceptors interceptors) {

       this.routes = routes;

       this.interceptors = interceptors;

    }

ActionMapping中定义了一个路由(routes)和一个Interceptors,这个routes类里面主要的核心是两个Map,内容如下(截取了部分源码过来)

//每一个访问路径(controllerKey)都对应有一个相应的controller,并作为一对Entry放到map

    private final Map<String, Class<? extends Controller>> map = new HashMap<String, Class<? extends Controller>>();

    //每一个访问路径(controllerKey)都对应一个在项目中的实际存放路径(WEB-INF/index.jsp等等),并作为一对Entry放到viewPathMap

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

因此我们知道这个ActionHandler就是处理一些关于ActionMapping中对应的ControllerKeyController.class的事情。

所以现在既然这些都已经清楚了,我们可以看看ActionHandler的庐山真面目了。

ActionHandler中我们可以看到这样一行注释:

/**

          * handle

          * 1: Action action = actionMapping.getAction(target)

          * 2: new ActionInvocation(...).invoke()

          * 3: render(...)

          */

这就解释了handle方法需要做的事情了,首先是根据ActionMapping获得相应的Action,然后利用反射进行方法的调用,最后把结果映射到相应的页面上去。这就是核心的三个步骤了,接下来让我们详细的读一下这个源码:

final class ActionHandler extends Handler {

        

         private final boolean devMode;

         private final ActionMapping actionMapping;

         private static final RenderFactory renderFactory = RenderFactory.me();

         private static final Logger log = Logger.getLogger(ActionHandler.class);

        

         public ActionHandler(ActionMapping actionMapping, Constants constants) {

                   this.actionMapping = actionMapping;

                   this.devMode = constants.getDevMode();

         }

        

         /**

          * handle

          * 1: Action action = actionMapping.getAction(target)

          * 2: new ActionInvocation(...).invoke()

          * 3: render(...)

          */

//这里进行了核心的handle方法描述:

这里的target为以下格式:http://localhost:8080/ContextPath/ControllerKey/MethodName/parameters

         public final void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {

                   if (target.indexOf(".") != -1) {

                            return ;

                   }

                  

                   isHandled[0] = true;

                   String[] urlPara = {null};

                   Action action = actionMapping.getAction(target, urlPara);

                   //判断Action是否为空

                  if (action == null) {

                            if (log.isWarnEnabled()) {

                                     String qs = request.getQueryString();

                                     log.warn("404 Action Not Found: " + (qs == null ? target : target + "?" + qs));

                            }

                            renderFactory.getErrorRender(404).setContext(request, response).render();

                            return ;

                   }

                   //Action不为空时候:

                   try {

//得到对应的Controller

                            Controller controller = action.getControllerClass().newInstance();

                            controller.init(request, response, urlPara[0]);

                           

                            if (devMode) {

                                     boolean isMultipartRequest = ActionReporter.reportCommonRequest(controller, action);

//利用反射执行相关的Action

                                     new ActionInvocation(action, controller).invoke();

                                     if (isMultipartRequest) ActionReporter.reportMultipartRequest(controller, action);

                            }

                            else {

                                     new ActionInvocation(action, controller).invoke();

                            }

                           

                            Render render = controller.getRender();

                            if (render instanceof ActionRender) {

                                     String actionUrl = ((ActionRender)render).getActionUrl();

                                     if (target.equals(actionUrl))

                                               throw new RuntimeException("The forward action url is the same as before.");

                                     else

                                               handle(actionUrl, request, response, isHandled);

                                     return ;

                            }

                           

                            if (render == null)

                                     render = renderFactory.getDefaultRender(action.getViewPath() + action.getMethodName());

                            render.setContext(request, response, action.getViewPath()).render();

                   }

                   catch (RenderException e) {

                            if (log.isErrorEnabled()) {

                                     String qs = request.getQueryString();

                                     log.error(qs == null ? target : target + "?" + qs, e);

                            }

                   }

                   catch (ActionException e) {

                            int errorCode = e.getErrorCode();

                            if (errorCode == 404 && log.isWarnEnabled()) {

                                     String qs = request.getQueryString();

                                     log.warn("404 Not Found: " + (qs == null ? target : target + "?" + qs));

                            }

                            else if (errorCode == 401 && log.isWarnEnabled()) {

                                     String qs = request.getQueryString();

                                     log.warn("401 Unauthorized: " + (qs == null ? target : target + "?" + qs));

                            }

                            else if (errorCode == 403 && log.isWarnEnabled()) {

                                     String qs = request.getQueryString();

                                     log.warn("403 Forbidden: " + (qs == null ? target : target + "?" + qs));

                            }

                            else if (log.isErrorEnabled()) {

                                     String qs = request.getQueryString();

                                     log.error(qs == null ? target : target + "?" + qs, e);

                            }

                            e.getErrorRender().setContext(request, response).render();

                   }

                   catch (Exception e) {

                            if (log.isErrorEnabled()) {

                                     String qs = request.getQueryString();

                                     log.error(qs == null ? target : target + "?" + qs, e);

                            }

                            renderFactory.getErrorRender(500).setContext(request, response).render();

                   }

         }

}

到这里,我们简单了看了一下JFinal的实现原理。


你可能感兴趣的:(JFinal实现原理)