JFinal實現原理

                        JFinal學習筆記web

一切都從web.xml開始提及:服務器

當服務器初始化的時候會初始化web.xml裏面的相關配置信息。下面咱們來看一個重要的過濾器配置:JFinalFilter。下面是相關的配置信息app

<filter>jsp

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

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

<init-param> ui

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

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

</init-param>spa

    </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的實現原理。

相關文章
相關標籤/搜索