jfinal 最大亮點就是零配置極速 WEB (通過對servlet的極薄封裝實現的極速)+ ORM (獨創(chuàng)Db + Record模式,靈活便利)
那極速 WEB 和 獨創(chuàng)Db + Record模式 是怎么實現的呢?
所以看了下jfinal2.2的源碼。
jfinal是通過過濾器攔截服務來實現路由的分發(fā)(web.xml 中配置的filter)。
jfnal 的核心攔截器為:com.jfinal.core.JFinalFilter.java
所以從這個類開始看。
// final 關鍵字修飾,表示不可被繼承,實現了Filter接口
public final class JFinalFilter implements Filter {}
然后實現了 init 初始化方法 在服務啟動過的過程中就由容器調用
現在來看看 init 方法中具體干了哪些事
public void init(FilterConfig filterConfig) throws ServletException {
// 利用反射初始化開發(fā)項目中實現了JfinalConfig類的子類,并且賦值給當前對象的jfinalConfig 變量
createJFinalConfig(filterConfig.getInitParameter("configClass"));
// 然后調用 Jfinal 中的初始化方法
1、配置項目路徑
2、配置 Config 在config中初始化一些項目配置
2.1、配置常量Constant 然后初始化日志使框架日志與系統日期保持一致,默認使用log4j日志,如果項目沒有使用則直接使用jdk日志
2.2、配置路由Route,
2.3、配置插件(Plugin),配置完成后啟動插件,調用插件的start方法。
2.4、配置攔截器(Interceptor),
2.5、配置處理器(Handler)
3、初始化ActionMapping(配置請求路徑對應的控制器對象)
4、初始化處理器,增加ActionHandler()處理器,并且和用戶自定義處理器串聯連接。
5、初始化 render 視圖渲染組件
6、初始化 OreillyCos 文件上傳處理插件
7、初始化 TokenManager(token管理器)
if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false)
throw new RuntimeException("JFinal init error!");
// 獲取jfinal處理器(在 jfinal.init函數中 調用 initHandler 函數 初始化的)
// 在初始化處理器的時候系統會增加一個 ActionHandler() 處理器,然后把這些處理器,和用戶配置的處理器串聯起來了,形成了一個鏈式的結構。
// 最后 jfinal.getHandler(); 返回的是用戶配置的最后一個處理器,然后鏈接的下一個處理器是倒數第二個配置的,一直到 最后一個ActionHandler()
// 所以用戶在每個配置的Handler中都得調用一下 next.handler(...) 函數,如果不調用則最后處理到達不了Controller。
handler = jfinal.getHandler();
// 取出用戶配置的常量
constants = Config.getConstants();
// 編碼設置為用戶在常量中設置的編碼,如果用戶沒有設置,則使用默認的UTF-8編碼
encoding = constants.getEncoding();
// 調用 afterJFinalStart() 函數處理,用戶在配置前自定義處理。
jfinalConfig.afterJFinalStart();
// 設置 contextPath 到此,攔截器的初始化工作完畢,增加jfinal的初始化工作也結束了。
// 啰嗦一句如果項目在tomcat的webapps中不是以ROOT命名的目錄,則contextPath值為用戶的項目目錄名稱
// 否則 contextPath 的值為 /
String contextPath = filterConfig.getServletContext().getContextPath();
contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());
}
接下來,就是攔截器懶覺請求,并且處理請求。
攔截器攔截到的每個請求,都會執(zhí)行doFilter函數,這個函數是Filter接口中規(guī)定的必須實現的函數。
JFinalFilter 類中的 doFilter 函數實現代碼如下,一句一句的來看。
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
// 把 ServletRequest 和 ServletResponse 類型的請求與應答強制轉換為HttpServletRequest,和HttpServletResponse
// 這段代碼沒什么就是為了方便使用HttpServletRequest里的一些函數。基本上每個filter 都會這么做。
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
// 設置請求編碼,這個編碼就是在初始化函數中,用戶設置的或者系統默認的utf-8編碼。
request.setCharacterEncoding(encoding);
String target = request.getRequestURI(); // 獲取請求 uri
if (contextPathLength != 0)// contextPathLength 不為0則獲取真正的 uri
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);
}
}
// 如果 最后處理到達了。ActionHandler 并且成功處理過了,則isHandled[0]會被標記為true
// 則調用chain.doFilter(request, response); 放行請求,如果用戶在 web.xml 中還配置了其他的過濾器
// 則用戶還會繼續(xù)調用其他過濾器來過濾請求,直到最后返回請求內容給用戶,web容器關閉請求。
// 一個完整的請求就這樣結束了,下一篇內容著重講解 ActionHandler類中的 handle 函數(handler.handle(target, request, response, isHandled))
// 還有一個,isHandled使用數組類型,是因為數組類型使用的是引用傳遞,而boolean使用的是值傳遞。
if (isHandled[0] == false)
chain.doFilter(request, response);
}