不管是Stuct2还是Spring MVC,都是通过在Web.xml里面加入filter,使得Web服务器启动时加载它。Jfinal也是。
filter本身是对Web所有请求的过滤。在 Web服务器启动的时候会加载Filter-class,利用这点Jfinal也就加载起来了。
<filter> <filter-name>jfinal</filter-name> <filter-class>com.jfinal.core.JFinalFilter</filter-class> <init-param> <param-name>configClass</param-name></init-param> </filter> <filter-mapping> <filter-name>jfinal</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
这里的Filter-class是com.jfinal.core.JFinalFilter,所以我们要从它开始看起。
public final class JFinalFilter implements Filter
从定义中可以看出,JFinal是实现了Filter接口
Filter接口里面有三个主要的方法:
public void init(FilterConfig filterConfig); public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain); public void destroy();
这是Java本身的东西,Jfinal是对他的实现。
在init方法中Jfinal完成了自身的初始化。
public void init(FilterConfig filterConfig) throws ServletException { //实例化 ConfigClass createJFinalConfig(filterConfig.getInitParameter("configClass")); //进行最主要的Jfinal初始化(疑问:为什么不把ConfigClass也放到Jfinal.init中来,这样代码更容易理解) if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false) throw new RuntimeException("JFinal init error!"); //获得Jfinal初始化后的对象。 handler = jfinal.getHandler(); //获得配置的编码信息,(疑问:应该直接默认UTF-8,此处真是多此一举) constants = Config.getConstants(); encoding = constants.getEncoding(); jfinalConfig.afterJFinalStart(); //解析路径的时候需要把前面的主机名,协议名去掉,比如 //此处contextPath 是http://127.0.0.1,那么以后得到http://127.0.0.1/helloworld时, //可以根据contextPathLength把http://127.0.0.1截掉,这样得到helloworld, //然后根据helloworld进行映射controller方法 String contextPath = filterConfig.getServletContext().getContextPath(); contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length()); }
在doFilter中Jfinal调用真正的处理。
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { //传过来的ServletRequest和 ServletResponse 进行类型转换HttpServletRequest,HttpServletResponse //为什么进行类型转换: HttpServletRequest和ServletRequest都是接口 //HttpServletRequest继承自ServletRequest //HttpServletRequest比ServletRequest多了一些针对于Http协议的方法。 //如getHeader(String name),getMethod(),getSession() 等等。 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); }
在destroy只是留下了扩展接口,没有实际内容。
在整个JFinalFilter类中,还有两个方法
private void createJFinalConfig(String configClass) static void initLogger()
createJFinalConfig使用了反射,实例化了ConfigClass,
ConfigClass就是在<param-value>com.demo.common.DemoConfig</param-value>配置的类。
createJFinalConfig里面的方法是比较common的方法,为什么没有放在util里面,很奇怪。
总结:
JFinalFilter是直接和Web server耦合的类,是Jfinal的入口。从代码层面说,还有几点需要改进
去掉 createJFinalConfig,放入Jfinal主类中感觉比较好,并在init中调用
initLogger在Config类中被调用,Config被Jfinal调用,而JFinalFilter本身又调用Jfinal中的方法,
形成的相互依赖,感觉不太好
init方法内容是几个不相关的内容,最好分出来。
下面的代码段,放在init中没有意义,本身Constants是静态类,而且仅使用一次,在使用的地方直接
Config.getConstants().getEncoding()即可,或者在使用该变量的方法开始的时候
encoding=Config.getConstants().getEncoding();
constants = Config.getConstants(); encoding = constants.getEncoding();
原文地址:http://my.oschina.net/u/52956/blog/290138