Jfinal源码解析系列一

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

1 Jfinal的初始化入口

<filter><filter-name>jfinal</filter-name><filter-class>com.jfinal.core.JFinalFilter</filter-class><init-param><param-name>configClass</param-name><param-value>com.demo.DemoConfig</param-value></init-param>
</filter>
<filter-mapping><filter-name>jfinal</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

其中JFinalFilter是过滤器负责对所有的请求进行拦截。DemoConfig是系统的配置,在初始化进行加载。

当web容器启动时,JfinalFilter会启动init()进行系统初始化。

public void init(FilterConfig filterConfig) throws ServletException {createJFinalConfig(filterConfig.getInitParameter("configClass"));//1获取DemoConfigif (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false)//2JFinal初始化throw new RuntimeException("JFinal init error!");handler = jfinal.getHandler();//3获取handlerconstants = Config.getConstants();//4获取常量encoding = constants.getEncoding();//5获取编码jfinalConfig.afterJFinalStart();//6回调函数 默认为空String contextPath = filterConfig.getServletContext().getContextPath();//7ContextPath的路径contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());//
}

以下对jfinal初始化进行详细讲解。

1 createJfFinalConfig类的详细讲解

private void createJFinalConfig(String configClass) {if (configClass == null)throw new RuntimeException("Please set configClass parameter of JFinalFilter in web.xml");Object temp = null;try {temp = Class.forName(configClass).newInstance();//反射获取系统设置的实例} catch (Exception e) {throw new RuntimeException("Can not create instance of class: " + configClass, e);}if (temp instanceof JFinalConfig)jfinalConfig = (JFinalConfig)temp;//向上转成/jFinalConfigelsethrow new RuntimeException("Can not create instance of class: " + configClass + ". Please check the config in web.xml");
}

2 JFinal init()方法

boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {this.servletContext = servletContext;this.contextPath = servletContext.getContextPath();initPathUtil();//2.1初始化PathKit工具并获取WebRootConfig.configJFinal(jfinalConfig); //2.2 start plugin and init logger factory in this methodconstants = Config.getConstants();//2.3获取常量initActionMapping();//2.4 MappinginitHandler();//2.5 init handlerinitRender();//2.6 init renderinitOreillyCos();//2.7 init OreillyCosinitTokenManager();//2.8 init Tokenreturn true;
}

2.2 系统配置初始化。

static void configJFinal(JFinalConfig jfinalConfig) {jfinalConfig.configConstant(constants);	//2.2.1 配置自定义的constants			        initLoggerFactory();// 2.2.2配置日志工厂jfinalConfig.configRoute(routes);// 2.2.3配置自定义的RoutesjfinalConfig.configPlugin(plugins);// 2.2.4配置自定义的PluginsstartPlugins();	// very important!!!//2.2.5开启pluginsjfinalConfig.configInterceptor(interceptors);// 2.2.6配置自定义的拦截器jfinalConfig.configHandler(handlers);// 2.2.7配置自定义的handler}

2.2.5

() {List<IPlugin> pluginList = .getPluginList()(pluginList == )(IPlugin plugin : pluginList) {{(plugin com.jfinal.plugin.activerecord.ActiveRecordPlugin) {com.jfinal.plugin.activerecord.ActiveRecordPlugin arp = (com.jfinal.plugin.activerecord.ActiveRecordPlugin)plugin(arp.getDevMode() == )arp.setDevMode(.getDevMode())}(plugin.start() == ) {String message = + plugin.getClass().getName().error(message)RuntimeException(message)}}(Exception e) {String message = + plugin.getClass().getName() + + e.getMessage().error(messagee)RuntimeException(messagee)}}
}

2.4 ActionMappig 初始化

private void initActionMapping() {actionMapping = new ActionMapping(Config.getRoutes(), Config.getInterceptors());actionMapping.buildActionMapping();}

其中buildActionMapping函数

// 1.url到action映射的核心实现// Map的entrySet()方法返回一个实现Map.Entry接口的对象集合。集合中每个对象都是底层Map中一个特定的键/值对// 获取自定义配置的routs中的对象集合,key: String,value: ? extents Controller.class// 配置实例 me.add("/blog", BlogController.class);for (Entry<String, Class<? extends Controller>> entry : routes.getEntrySet()) {// 获取当前迭代的集合的valueClass<? extends Controller> controllerClass = entry.getValue();// 创建当前Controller的拦截器,处理@before注解Interceptor[] controllerInters = interceptorBuilder.buildControllerInterceptors(controllerClass);// 获取当前controller的所有方法Method[] methods = controllerClass.getMethods();// 迭代所有方法for (Method method : methods) {// 通过method对象获取当前method的nameString methodName = method.getName();// 判断当前method是否是父级Congtroller的通用方法且该方法不能含有参数if (!excludedMethodName.contains(methodName)&& method.getParameterTypes().length == 0) {// 创建当前Method的拦截器,处理@before注解Interceptor[] methodInters = interceptorBuilder.buildMethodInterceptors(method);// 创建此method对应的action的拦截器,此拦截器由全局、controller、method级别的拦截器依次拦截组成的拦截器栈Interceptor[] actionInters = interceptorBuilder.buildActionInterceptors(defaultInters,controllerInters, controllerClass,methodInters, method);// 定义 controllerKey 为 entry.getKey(),为添加路由时的第一个参数,如"/","/blog"String controllerKey = entry.getKey();// 获取当前方法的@ActionKey注解,demo项目没有ActionKey注解ActionKey ak = method.getAnnotation(ActionKey.class);// ak != null// 的情况暂时不考虑,作者相比也是不提倡这种做法的,actionkey应该是借鉴springmvc的注解的产物,有点使方法本身的命名失去描述的感觉if (ak != null) {String 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;if (mapping.containsKey(actionKey)) {warnning(actionKey, controllerClass, method);continue;}Action action = new Action(controllerKey, actionKey,controllerClass, method, methodName,actionInters, routes.getViewPath(controllerKey));mapping.put(actionKey, action);// 处理默认的访问方式,即url/的方式,单独处理index方法} else if (methodName.equals("index")) {// method为index时,actionKey为controllerKeyString actionKey = controllerKey;// action冒泡了,使用七个参数来实例化具体的action// routes.getViewPath(controllerKey) 返回的当前controller对应的视图路径,具体实现会在routs分析中探讨Action action = new Action(controllerKey, actionKey,controllerClass, method, methodName,actionInters, routes.getViewPath(controllerKey));// 添加一个映射进mapping,如actionKey对应的值不为空,那么将用新值替换旧值,且方法返回值为之前的旧值,否则返回nullaction = mapping.put(actionKey, action);// 如果action不为空,则需记录警告日志if (action != null) {warnning(action.getActionKey(),action.getControllerClass(),action.getMethod());}// 处理controller中的其他方法,如demo中的BlogController中的add save edit等} else {// 根据controllerkey的'/','/XX'的两种情况分别生成actionKeyString actionKey = controllerKey.equals(SLASH) ? SLASH+ methodName : controllerKey + SLASH+ methodName;// 判断mapping是否已拥有当前actionKey对应的映射,如有,记录警告日志,跳出本轮循环,防止后配置的覆盖先前配置的// 此处处理方式与对index的处理不同,何故?暂时不解if (mapping.containsKey(actionKey)) {warnning(actionKey, controllerClass, method);continue;}// 与处理index方法并无二致Action action = new Action(controllerKey, actionKey,controllerClass, method, methodName,actionInters, routes.getViewPath(controllerKey));mapping.put(actionKey, action);}}}}// 添加诸如http://localhost:20000/webappName 的支持,即末尾不加'/'的支持Action actoin = mapping.get("/");if (actoin != null) {mapping.put("", actoin);}

完成Action和url的对应映射

2.5 初始化handler

private void initHandler() {Handler actionHandler = new ActionHandler(actionMapping, constants);//根据2获得的actionMapping构造handlerhandler = HandlerFactory.getHandler(Config.getHandlers().getHandlerList(), actionHandler);}//构造handler chain ,依照定义的顺序依次链接,actionHandle在链的末端

2.6 initRender

private void initRender() {
RenderFactory renderFactory = RenderFactory.me();//2.6.1获取RenderFactory 单例被final修饰
renderFactory.init(constants, servletContext);//2.6.2
}

   2.6.2 renderFactory 初始化

public void init(Constants constants, ServletContext servletContext) {
this.constants = constants;
RenderFactory.servletContext = servletContext;
// init Render
Render.init(constants.getEncoding(), constants.getDevMode());
initFreeMarkerRender(servletContext);
initVelocityRender(servletContext);
initJspRender(servletContext);
initFileRender(servletContext);
// create mainRenderFactory
if (mainRenderFactory == null) {
ViewType defaultViewType = constants.getViewType();
if (defaultViewType == ViewType.FREE_MARKER)
mainRenderFactory = new FreeMarkerRenderFactory();
else if (defaultViewType == ViewType.JSP)
mainRenderFactory = new JspRenderFactory();
else if (defaultViewType == ViewType.VELOCITY)
mainRenderFactory = new VelocityRenderFactory();
else
throw new RuntimeException("View Type can not be null.");
}
// create errorRenderFactory
if (errorRenderFactory == null) {
errorRenderFactory = new ErrorRenderFactory();
}
}

2.7 uploda File init

private void initOreillyCos() {
OreillyCos.init(constants.getUploadedFileSaveDirectory(), constants.getMaxPostSize(), constants.getEncoding());//2.7.1 init 文件上传工具
}

2.7.1 

public static void init(String saveDirectory, int maxPostSize, String encoding) {
try {
Class.forName("com.oreilly.servlet.MultipartRequest");//获取MultiparRequest工具
doInit(saveDirectory, maxPostSize, encoding);//初始化上传的相关参数,具体实现以后再继续解剖
} catch (ClassNotFoundException e) {
}
}

2.8 init token

/*暂时不清楚token的作用*/
private void initTokenManager() {
ITokenCache tokenCache = constants.getTokenCache();
if (tokenCache != null)
TokenManager.init(tokenCache);
}

最后做个小结:在配置文件中配置app统一入口,获取app的相关配置后进行JFinal的各组件的初始化,初始化完成个组件后即可对外提供服务


转载于:https://my.oschina.net/cheeryzxh007/blog/479253

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MSP430G2553】图形化开发笔记(2) 系统时钟和低功耗模式

目录系统时钟概述BCS模块单元的基本构造时钟-概览介绍Basic User 模式Power User 模式1. 数控振荡器 DCO2. 出厂预校正频率3. 低频振荡器 VLO4. 内部匹配电容5. 延时启动6. 自动选择 MCLK 源7. 时钟输出8. 振荡器失效中断9. 中断事件处理函数10. 退出中断后的节能选项Registers…

alias命令

alias命令&#xff08;取别名之前先运行一下将要使用的别名&#xff0c;以免冲突&#xff09; alias语法&#xff1a;alias 自定义的命令真正的命令 1.使用which查看一个命令的完整命令&#xff0c;也可以查看绝对路径 2.‘alias’查看系统中所有别名&#xff1a; 3.应用 再使用…

奇怪的 加号

转载于:https://www.cnblogs.com/chuyu/p/3421237.html

Java反射机制:表单数据自动封装到JavaBean中【IT】

2019独角兽企业重金招聘Python工程师标准>>> (2010-07-09 19:50:18) 转载▼ 标签&#xff1a; it 分类&#xff1a; IT路人丁 利用Java的反射机制&#xff0c;模拟一个简单的Struts控制器ActionServlet时&#xff0c;为了将请求的表单数据自动封装到JavaBean中&…

eclipse启动tomcat不能正常访问问题

问题&#xff1a; 1、eclipse中配置好tomcat服务器后&#xff0c;启动tomcat查看控制台信息显示启动成功&#xff0c; 但访问tomcat首页报404异常 2、而从tomcat/bin目录中启动后&#xff0c;就能够正常访问首页&#xff0c;由此分析应该是eclipse配置错误 解决方案&#xff1a…

AD域

将网络中的计算机逻辑上组织到一起&#xff0c;将器视为一个整体进行集中管理&#xff0c;这种区别于工作组的逻辑环境叫做Windows域。windows管理模式有两种&#xff1a;工作组和与环境。活动目录的相关概念(1)域和域控制器(2)名称空间(3)对象和属性(4)容器(5)组策略活动目录的…

Python学习笔记19(算法)

1.二分查找 只能用二分查找查找有序列表 def bin_search(data,val): #data为被查找的列表&#xff0c;val是要查找的值low 0high len(data) - 1while low < high:mid (lowhigh)//2if data[mid] val:return mid #找到了&#xff0c;返回val所在的索引elif dat…

C#通过接口与线程通信(捕获线程状态)介绍

摘要&#xff1a;本文介绍C#通过接口与线程通信(捕获线程状态)&#xff0c;并提供简单的示例代码供参考。 提示&#xff1a;本文所提到的线程状态变化&#xff0c;并不是指线程启动、暂停、停止&#xff0c;而是说线程内部状态的迁移。随着软件技术不断发展&#xff0c;用户需求…

php 类文件加载 Autoloader

做习惯了编译语言&#xff0c;转到php 使用 php的面向对象开发时候遇见一个挺别扭的问题。在Php中引入对象 后 在调用过程中还需要将对象所在的php文件 require 到当前php文件 目前代码结构 index.php <?phpuse model\BookModel;include_once __DIR__./autoloader.php; Aut…

【MSP430G2553】图形化开发笔记(4) Timer_A 定时器

目录概述Timer_A 模块16 位主定时器连续计数模式增计数模式增减计数模式主定时器的一般设置捕获/比较模块 CCRx捕获模块比较模块小结Grace中配置Timer_ATimer0_A3 - Overview介绍用例&#xff1a;定时器的启动/停止用例&#xff1a;使用定时器比较模式产生周期性间隔用例&#…

前端UI框架《Angulr》入门

Angulr 项目的名称为 Angulr&#xff0c;对&#xff01;没错&#xff01;就是少个 a&#xff0c;少个 a 就是它正确的拼写。 是一个以 Bootstrap 和 AngularJS 为基础&#xff0c;并使用了大量前端开源组件合成的一个前端UI框架&#xff0c;是非常棒的UI框架。 今天就来和大家讲…

Flask使用Flask-SQLAlchemy操作MySQL数据库

https://www.jianshu.com/p/6ae0d30a5539 前言&#xff1a; Flask-SQLAlchemy是一个Flask扩展&#xff0c;简化了在Flask程序中使用SQLAlchemy的操作。SQLAlchemy是一个很强大的关系型数据库框架&#xff0c;支持多种数据库后台。SQLAlchemy提供了高层ORM&#xff0c;也提供了…

会计基础模拟练习一(3)

会计基础模拟练习一&#xff08;3&#xff09; 下周一18号会计从业资格考试就要报名了,本人重点看的是会计基础和会计电算化,做了一下测试题,五十多分,较之前有了一些长进.很多之前重点复习的章节有了明显的提升,像后面的几章没怎么看,出错的概率就大大的提升了. 我觉得这个考试…

MacOS中Dock栏的设置和使用技巧,新手必看

MacOS中Dock栏的设置和使用技巧&#xff0c;新手必看 Dock栏就是Mac放置常用应用程序和文件夹快捷方式的任务栏&#xff0c;为你访问这个应用和文件提供了非常方便的入口。 作为Mac用户最常使用的区域&#xff0c;要知道如何才能更高效的使用它&#xff0c;从而达到事半功倍的…

51Nod 1003 阶乘后面0的数量 | 思维

题意&#xff1a;n的阶乘后面0的个数&#xff0c;如果直接算出阶乘再数0的数量一定会超时的。因为102*5,所以求出5贡献的次数就行。#include "bits/stdc.h" using namespace std; #define LL long long #define INF 0x3f3f3f3f3f #define PI acos(-1) #define N 510 …

史上超详细的flask_sqlalchemy连接mysql数据库

https://www.jianshu.com/p/1ba45bd6c351 PythonFlask安装&#xff1a;https://www.jianshu.com/p/cd1925e90eda Flask路径参数以及请求参数讲解&#xff1a;https://www.jianshu.com/p/54057b4f0437 首先安装pymysql&#xff0c;命令如下&#xff1a;pip install pymysql 安装…

中国移动技术愿景2020+

2019独角兽企业重金招聘Python工程师标准>>> 中国移动技术愿景2020 本文档白皮书是中国移动提出的在2020年及其之后的若干年内对产业各方面技术发展的构想&#xff0c;包括行业发展趋势&#xff0c;面向万物的数字化服务和对技术发展的看法。希望产业各方面能够开展…

Zend Server更新至6.2版本——虚拟主机全方位管理

Zend Server自从发布6.0以来&#xff0c;并支持云服务&#xff0c;成为很多PHP程序所选择的Web服务器。 Zend Server 6.2版本从更新内容来看&#xff0c;解决了Web服务器与虚拟主机之间的协同管理。并在细节上&#xff0c;更注重性能控制。 具体更新如下&#xff1a; 虚拟主机管…

python基础-02

常见的数据类型 列表 在python中&#xff0c;列表的创建可以是由[]两个方括号组成的。在其他语言中&#xff0c;被称之为数组。 列表里可以存放一组值&#xff0c;并且系统默认的给列表里的每一个元素以索引值&#xff0c;方便查找和使用。 如下&#xff1a; #创建一个列表&…

自己如何获取ADO连接字符串

自己如何获取ADO连接字符串 摘自&#xff1a;http://blog.csdn.net/zyq5945/article/details/5586423 有时候我们参考网上的ADO连接字符串写未必就能连接上数据库。今天详细介绍下这个很流行的如何获取ADO字符串的方法&#xff0c;就能很容易直观看到这个连接字符串是否真能连接…