最近閒來無事,順帶看了下jfinal的源碼,如下均爲本身的我的理解,若有錯誤請指定;web
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: 添加多個處理器,這裏能夠看做是一個工具類,只是把多個處理器保存到列表中;數據庫
咱們先看filter初始化的方法,代碼量不多緩存
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裏的變量;app
從過濾器來看,大部分的初始化碼在jfinal.init(jfinalConfig,servletContext)方法中;
代碼以下:工具
// 設置變量,不用理會
this.servletContext = servletContext;
this.contextPath = servletContext.getContextPath();
// 根據servletContext變量來初始化PathKit工具類的webRootPath;
initPathUtil();
Config.configJFinal(jfinalConfig); // start plugin, init log factory and init engine in this method
constants = Config.getConstants();
initActionMapping();
initHandler();
initRender();
initOreillyCos();
initTokenManager();
return true;
Config.configJFinal(jfinalConfig): 將jfinalConfig中定義的內容全配置到Config類中,後面的參數變量均在Config類中定義,很容易看懂,代碼以下:this
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方法;url
initRender(); // 初始化render
initOreillyCos(); //初始化上傳相關
initTokenManager(); //初始化token緩存,若是在Constants中沒有設置tokenCache,則跳過;spa
至此 ,全部初始化完成 ;插件
看完以後發現核心的代碼就一句:
handler.handle(target, request, response, isHandled);
若是有自定義處理器,在本身的邏輯處理完成以後,記得加一句: next.handle()來執行下一個控制器;
到最後必然會執行到ActionHandler的handle方法;
核心的代碼也就幾句:
//獲取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的思想;