在jfinal中,通过JFinalFilter对所有的类进行过滤。
以下是路由的调用关系(我在调用关系旁边做了标记,会贴出具体的代码和解释):
-1- Config: Routes -2- Interceptors Handlers -3- public void init(){ createJFinalConfig -4- init: initActionMapping: new ActionMapping buildActionMapping -5- initHandler new ActionHandler getHandler initRender } -6- public void dofilter(){ -7- handle: Action action = new actionMapping.getAction(target) -8- new ActionInvocation.invoke() render }
-1-Config是基本的配置。
在Config这个类中,Routes、Interceptors、Handlers均以成员变量的形式存在。
class Config { private static final Routes routes = new Routes(){public void config() {}}; private static final Interceptors interceptors = new Interceptors(); private static final Handlers handlers = new Handlers(); }
-2-
Routes
在Route中有两个Map:map和viewPathMap。
map中放置的是controllerKey和controllerClass的键值对。
viewPathMap中放置的是controllerKey和viewPath的键值对。
public abstract class Routes { private final Map<String, Class<? extends Controller>> map = new HashMap<String, Class<? extends Controller>>(); private final Map<String, String> viewPathMap = new HashMap<String, String>(); public Routes add(String controllerKey, Class<? extends Controller> controllerClass, String viewPath) { if (controllerKey == null) throw new IllegalArgumentException("The controllerKey can not be null"); // if (controllerKey.indexOf(".") != -1) // throw new IllegalArgumentException("The controllerKey can not contain dot character: /"./""); controllerKey = controllerKey.trim(); if ("".equals(controllerKey)) throw new IllegalArgumentException("The controllerKey can not be blank"); if (controllerClass == null) throw new IllegalArgumentException("The controllerClass can not be null"); if (!controllerKey.startsWith("/")) controllerKey = "/" + controllerKey; if (map.containsKey(controllerKey)) throw new IllegalArgumentException("The controllerKey already exists: " + controllerKey); map.put(controllerKey, controllerClass); if (viewPath == null || "".equals(viewPath.trim())) // view path is controllerKey by default viewPath = controllerKey; viewPath = viewPath.trim(); if (!viewPath.startsWith("/")) // "/" added to prefix viewPath = "/" + viewPath; if (!viewPath.endsWith("/")) // "/" added to postfix viewPath = viewPath + "/"; if (baseViewPath != null) // support baseViewPath viewPath = baseViewPath + viewPath; viewPathMap.put(controllerKey, viewPath); return this; } }
-3-JFinalFilter中的init方法
public void init(FilterConfig filterConfig) throws ServletException { 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()); }
-4-在JFinalFilter中调用了方法jfinal.init,进行初始化
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; }
-5-在initActionMapping中将Routes和Interceptors组织起来。其中,在initActionMapping中有一个重要的方法:buildActionMapping
void buildActionMapping() { mapping.clear(); Set<String> excludedMethodName = buildExcludedMethodName(); ActionInterceptorBuilder interceptorBuilder = new ActionInterceptorBuilder(); Interceptor[] globalInters = interceptors.getGlobalActionInterceptor(); interceptorBuilder.addToInterceptorsMap(globalInters); for (Entry<String, Class<? extends Controller>> entry : routes.getEntrySet()) { Class<? extends Controller> controllerClass = entry.getValue(); Interceptor[] controllerInters = interceptorBuilder.buildControllerInterceptors(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[] methodInters = interceptorBuilder.buildMethodInterceptors(method); Interceptor[] actionInters = interceptorBuilder.buildActionInterceptors(globalInters, controllerInters, methodInters, 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 actoin = mapping.get("/"); if (actoin != null) mapping.put("", actoin); }
-6-JFinalFilter中的doFilter。在doFilter中主要是调用了handle方法。
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) target = target.substring(contextPathLength); boolean[] isHandled = {false}; try { 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); }
-7-handle方法
/** * handle * 1: Action action = actionMapping.getAction(target) * 2: new Invocation(...).invoke() * 3: render(...) */ public final void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { if (target.indexOf('.') != -1) { return ; } isHandled[0] = true; String[] urlPara = {null}; //通过url得到action!!! Action action = actionMapping.getAction(target, urlPara); 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 ; } try { //根据action得到controller!!! Controller controller = action.getControllerClass().newInstance(); controller.init(request, response, urlPara[0]); if (devMode) { boolean isMultipartRequest = ActionReporter.reportCommonRequest(controller, action); //用获得的action进行调用处理请求!!! new Invocation(action, controller).invoke(); if (isMultipartRequest) ActionReporter.reportMultipartRequest(controller, action); } else { new Invocation(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, action.getViewPath()).render(); } catch (Throwable t) { if (log.isErrorEnabled()) { String qs = request.getQueryString(); log.error(qs == null ? target : target + "?" + qs, t); } renderFactory.getErrorRender(500).setContext(request, response, action.getViewPath()).render(); } }
-8-getAction方法:通过url得到action
Action getAction(String url, String[] urlPara) { Action action = mapping.get(url); if (action != null) { return action; } // -------- int i = url.lastIndexOf(SLASH); if (i != -1) { action = mapping.get(url.substring(0, i)); urlPara[0] = url.substring(i + 1); } return action; }