<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><strong>废话</strong></span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">:</span>
前段时间粗略看了一下jfinal的源码,然后今天在群里突然有人问jfinal的IOC实现原理是什么,竟然没有一点印象,丢人的节奏啊。然后一查,原来jfinal支持IOC要集成ioc插件,自己并没有实现IOC,意识到自己应该总结一下了,不然脸都丢完了。哈哈
可能是废话:
所有的容器都是从初始化开始的。所以看源码的初始化肯定也是从它的web.xml的那个filter钻进去的。
<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>这是jfinal在web.xml中的配置。在servlet容器初始化的时候会加载JFinalFilter,当然JFinalFilter肯定是实现了Servlet的Filter接口的。我们ctrl+鼠标左键跟进去看一下JFinalFilter里边都干了什么。
上图是JFinalFilter的属性和方法列表。可以看到这几个属性Handler,encoding,JFinalConfig,Constants,JFinal。为什么在初始化的Filter里定义这几个属性呢,等一会儿我们自然会分析。我们先看JFinalFilter的init方法。
<span style="white-space: pre;">第一句</span>createJFinalConfig(filterConfig.getInitParameter("configClass"));filterConfig.getInitParameter("configClass")
继承JFinalConfig要实现以下方法,这些方法的作用我写了注释。
/** * 此方法用来配置常量值,如devMode(开发模式),viewType(视图类型)等 */ @Override public void configConstant(Constants me) { me.setDevMode(true); } /** * 此方法用来配置访问路由 */ @Override public void configRoute(Routes me) { me.add("/hello", HelloController.class); me.add(new FrontRoute()); } /** * 此方法用来配置plugin */ @Override public void configPlugin(Plugins me) { loadPropertyFile("jdbc.txt"); C3p0Plugin c3p0Plugin = new C3p0Plugin(getProperty("url"), getProperty("username"),getProperty("password")); me.add(c3p0Plugin); ActiveRecordPlugin active = new ActiveRecordPlugin(c3p0Plugin); me.add(active); active.addMapping("user", User.class); } /** * 此方法用来配置intercept,在此处配置的拦截器将会对所有的请求进行拦截,除非使用@ClearInterceptor在Controller里清楚 */ @Override public void configInterceptor(Interceptors me) { } /** * 此方法用来配置Handle,handle可以接管所有web请求,并对应用拥有完全的控制权,可以很方便的实现更高层的功能性扩展 */ @Override public void configHandler(Handlers me) { }
我们继续回到createJFinalConfig(filterConfig.getInitParameter("configClass"));跟进去看它都做了什么
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); } }通过反射初始化一个JFinalConfig对象。
然后init方法中的第二句jfinal.init(jfinalConfig, filterConfig.getServletContext())
看一下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; }
第一、初始化 path,既初始化path工具类中的webRootPath(项目根路径)
private void initPathUtil() { String path = servletContext.getRealPath("/"); PathKit.setWebRootPath(path); }
第二、一些基本配置
/* * Config order: constant, route, plugin, interceptor, handler */ static void configJFinal(JFinalConfig jfinalConfig) { jfinalConfig.configConstant(constants); initLoggerFactory(); jfinalConfig.configRoute(routes); jfinalConfig.configPlugin(plugins); startPlugins(); // very important!!! jfinalConfig.configInterceptor(interceptors); jfinalConfig.configHandler(handlers); }
这里就是调用我们我们继承自JfinalConfig的那个类的方法了,configConstant就没有什么说了,就是加载配置文件,然后读取里边的值设置给Constant相应的属性。
initLoggerFactory就是初始化日志工厂,这里可以自定义使用喜欢的日志工具,如果没有自定义的话则会默认使用Log4j。自定义我也不知道在哪儿自定义,不过在configConstant中加上这句代码Logger.setLoggerFactory((ILogerFactory) 初始化)应该就ok了吧。如果不多希望您指正一下
configRoute配置路由
配置路由主要是干什么用的呢?就是映射URL地址和controller中的具体的方法。看我们自己定义的DemoConfig中的me.add("/hello", HelloController.class);。跟进去往下看
public Routes add(String controllerkey, Class<? extends Controller> controllerClass) { return add(controllerkey, controllerClass, controllerkey); }继续往里边跟,代码太长就不贴了,主要就是判断参数的合法性维护参数的正确性,然后将controllerKey作为键和controllerClass值放进一个map里,将controllerKey作为键和处理后的controllerKey作为值放进一个map里。有什么用?我现在还不知道,不过肯定是后边要用的。
configPlugin配置插件,没有什么好说的将你需要的插件统一放进一个list里,然后就startPlugins()了。
configInterceptor和configHandle也没有什么,和plugin一样将你自定义的interceptor和handle放进各自的list以备后边使用。
接下来几个动作才是重头戏,代码如下
initActionMapping(); initHandler(); initRender(); initActiveRecord(); initOreillyCos(); initI18n(); initTokenManager();
一、先是actionMapping
private void initActionMapping() { actionMapping = new ActionMapping(Config.getRoutes(), Config.getInterceptors()); actionMapping.buildActionMapping(); }Config.getRoutes(),Config.getInterceptors()就是拿到我们刚刚在上边说的那个configJfinal里初始化的routes和interceptors。然后buildActionMapping()
跟进去老长一个方法了。哈哈不过做的事情还是很清晰的,我们看看它做了什么吧
这个方法还真是蛋疼,看了半天才看懂。收回上边说的那句话!分析代码吧!
mapping.clear();准备工作要做好,把箱子给我腾空了,我要装东西了。buildExcludedMethodName();将不需要处理的方法给列出来。这里要讲一下,因为我们自己的controller是继承自Controller类的,但是我们自己定义的interceptor只需要拦截自己的方法(url可能请求的资源)就ok了。但是通过反射怎么过滤掉父类的方法呢?这里好像有点问题哎,我再看看。。。
看上边两张图片,第一个图片中红框内,拿到“不包括的方法名”。这个方法内容就是第二张图片里的,将所有参数长度为0的方法返回。再看第二个红框:不包含在excludedMethodName中并且参数长度为0的进入if语句块。这个判断的最终目的也就是因为DemoController是继承自Controller,而自定义Interceptor只需要加在DemoController的方法上,所以这里过滤掉它继承自Controller的方法。但是为什么不直接拿到Controller的所有方法,if判断里做过滤呢?还要这么绕。不知道是不是自己的理解不到位,大家给指正一下。
扯了这么多继续说代码吧 。这两句是重要的
Interceptor[] methodInters = interceptorBuilder.buildMethodInterceptors(method); Interceptor[] actionInters = interceptorBuilder.buildActionInterceptors(defaultInters, controllerInters, controllerClass, methodInters, method);
二、initHandler
private void initHandler() { Handler actionHandler = new ActionHandler(actionMapping, constants); handler = HandlerFactory.getHandler(Config.getHandlers().getHandlerList(), actionHandler); }
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; }将你自己定义的handler一个一个的加到系统定义的Handler后边,对,就是这么简单。
下边的步骤先大致说一下是干什么的吧,写博客还是有点累。下次再把下面几个步骤分析一下,然后再分析一下一次请求所做的操作。
三、initRender
这里初始化视图类型
四、初始化上传组件
五、国际化
六、初始化令牌管理