不管是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