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

JFinal学习笔记

一切都从web.xml开始说起:

当服务器初始化的时候会初始化web.xml里面的相关配置信息。下面我们来看一个重要的过滤器配置:JFinalFilter。下面是相关的配置信息

<filter>

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

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

<init-param>

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

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

</init-param>

</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());

}

//request和response的作用不用过多介绍了。这个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是由HandlerFactory的getHandler方法得来的。

让我们再次看看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中对应的ControllerKey与Controller.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的实现原理。

转载于:https://my.oschina.net/u/2288283/blog/400693

JFinal实现原理相关推荐

  1. jfinal整合shiro回顾

    2019独角兽企业重金招聘Python工程师标准>>> 目前jfinal使用shiro进行身份验证和授权的后台实现已完成,现在我再来总结下学习过程及代码实现过程.最近半年多项目开发都 ...

  2. Android10.0 BroadcastCast广播机制原理

    原文地址:https://skytoby.github.io/2019/BroadcastCast%E5%B9%BF%E6%92%AD%E6%9C%BA%E5%88%B6%E5%8E%9F%E7%90 ...

  3. jfinal restful.java_JFinal RESTful

    在阅读之前, 先参考 当看完这些之后, 大概应该就能理解, RESTful 的规范, 以及 JFinal 的路由实现方式. 首先, 先看下 JFinal 目前的 RESTful 风格路由实现. 翻开 ...

  4. 极速Web开发框架JFinal

    JFinal是一个基于Java的极速Web开发框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restful,在拥有Java语言所有优势的同时再拥有Ruby.Python ...

  5. 很多小伙伴不太了解ORM框架的底层原理,这不,冰河带你10分钟手撸一个极简版ORM框架(赶快收藏吧)

    大家好,我是冰河~~ 最近很多小伙伴对ORM框架的实现很感兴趣,不少读者在冰河的微信上问:冰河,你知道ORM框架是如何实现的吗?比如像MyBatis和Hibernate这种ORM框架,它们是如何实现的 ...

  6. jfinal ajax传值,JFINAL+Ajax传参 array 数组方法 获取request中数组操作

    前台代码js var _list =[]; for (var i = 0; i < array.length; i++) { _list[i] = array[i]; } $.ajax({ ty ...

  7. Jfinal插入oracle的blod字段

    最近在用jfianl做一个手机端的后台,jfinal不用多说,非常简单而且好用,比struct这个框架简单多了,配置c3p0连接池,配置oracle数据库等都很简单. 但是封装了,如果我想在oracl ...

  8. UUID的使用及其原理

    今天敲项目要用UUID,想起之前老师告诉UUID的使用,但没说具体的生成逻辑,于是我进行了百度 首先,UUID的使用: //生成随机的UUID String uuid = UUID.randomUUI ...

  9. etcd 笔记(01)— etcd 简介、特点、应用场景、常用术语、分布式 CAP 理论、分布式原理

    1. etcd 简介 etcd 官网定义: A highly-available key value store for shared configuration and service discov ...

  10. git原理及常见使用方法

    Git 原理入门-来自阮一峰 Git 是最流行的版本管理工具,也是程序员的必备技能之一. 即使天天使用它,很多人也未必了解它的原理.Git 为什么可以管理版本?git add.git commit这些 ...

最新文章

  1. 月薪30K+的程序员都会啥,通过3000字告诉你……
  2. 容器删除元素后迭代器失效_使用迭代器遍历容器元素
  3. Property ‘configuration‘ and ‘configLocation‘ can not specified with together
  4. 分享一套基于SpringBoot和Vue的企业级中后台开源项目,这个项目有点哇塞!
  5. C#中提示:可访问性不一致:参数类型XXX比方法XXX的可访问性低
  6. win7(64)与samba不兼容
  7. 数据结构 | 如何一文搞定链表问题?(附20本书获奖名单)
  8. C#复习笔记(3)--C#2:解决C#1的问题(可空值类型)
  9. 转:程序员每天该做的事
  10. VirtualBox虚拟机配置CentOS7网络图文详解教程
  11. P1421 小玉买文具【入门题】
  12. myeclipse新建JSP中DOCTYPE问题
  13. 玩转Eclipse1--基本知识与配置
  14. 【MFC开发(4)】按钮控件BUTTON
  15. 常用的分析方法论及分析框架
  16. 流程图常用符号及其代表含义
  17. 3.26 文字工具的使用 [原创Ps教程]
  18. mysql的填充因子_数据库索引中的填充因子
  19. ppt画深度学习网络图-立体网络模块
  20. 网页设计之CSS3精要

热门文章

  1. python中的struct
  2. C语言Register关键字:利用寄存器提升访问效率
  3. python如何调用阿里云接口_Python调用阿里云API接口实现自定义功能【二】——DescribeInstance窗口操作...
  4. 提取rosbag中的图像话题存为本地图像
  5. C语言结构体定义 typedef struct
  6. java testwhileidle,springboot使用druid时报错:testWhileIdle is true, validationQuery not set
  7. L1-008 求整数段和 (10 分)—团体程序设计天梯赛
  8. 终端/Shell 快捷键
  9. jQuery学习之路(1)-选择器
  10. 太赞了!超炫的页面切换动画效果【附源码下载】