Jfinal启动源码解读
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jfinal启动源码解读相关的知识,希望对你有一定的参考价值。
本文对Jfinal的启动源码做解释说明。
PS:Jfinal启动容器可基于Tomcat/Jetty等web容器启动,本文基于Jetty的启动方式做启动源码的解读和分析,tomcat类似。
- 入口
JFinalConfig的继承类的Main方法为入口,实例代码继承类为:DemoConfig,Main方法如下:
public static void main(String[] args) { /** * 特别注意:Eclipse 之下建议的启动方式 */ JFinal.start("WebRoot", 80, "/", 5); }
web.xml代码如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <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.common.DemoConfig</param-value> </init-param> </filter> <filter-mapping> <filter-name>jfinal</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
- JFinalFilter执行源码解读
web容器调用web.xml中的JFinalFilter过滤器,注入:com.demo.common.DemoConfig全路径,JFinalFilter中三个重要的方法分别是:init(FilterConfig filterConfig)、doFilter(ServletRequest req, ServletResponse res, FilterChain chain)、destroy()。
启动入口为init方法,方法截图如下
1 public void init(FilterConfig filterConfig) throws ServletException { 2 createJFinalConfig(filterConfig.getInitParameter("configClass"));//A.解析web.xml中configClass全路径类并初始化 3 4 if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false) {//B.基于Jfinal.init加载启动资源,包含控制器、拦截器等 5 throw new RuntimeException("JFinal init error!"); 6 } 7 8 handler = jfinal.getHandler();//C.获取处理器 9 constants = Config.getConstants();//D.获取常量 10 encoding = constants.getEncoding();//E.获取编解码器 11 jfinalConfig.afterJFinalStart();//F.启动web容器 12 13 String contextPath = filterConfig.getServletContext().getContextPath();//G.获取server路径 14 contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());//H.对路径特殊处理 15 }
A.解析web.xml中configClass全路径类
createJFinalConfig(filterConfig.getInitParameter("configClass"));
PS:上方法主要是为了实例化web.xml中configClass对象,JVM在装载class时候,基于类加载机制创建configClass对应的对象实例,代码分析如下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;//强制类型转换 } else { throw new RuntimeException("Can not create instance of class: " + configClass + ". Please check the config in web.xml"); }
//此类创建了一个对象JFinalConfig的继承类对象而已,不做深入追究 }B.基于Jfinal.init加载启动资源
jfinal.init(jfinalConfig, filterConfig.getServletContext())
boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {
this.servletContext = servletContext;
this.contextPath = servletContext.getContextPath();
//B1.获取web容器运行的跟目录,并存储到PathKit.webRootPath变量中
initPathUtil();//B2.初始化constant, route, engine, plugin, interceptor, handler等信息,实际是调用jfinalConfig
Config.configJFinal(jfinalConfig); // start plugin, init log factory and init engine in this method
constants = Config.getConstants();
//B3.初始化映射,包含controller和intercept
initActionMapping();//B4.初始化Handler
initHandler();//B5.初始化Render
initRender();//B6.初始化不知道
initOreillyCos();//初始化Token
initTokenManager();
return true;
}B1.获取web容器运行的跟目录,并存储到PathKit.webRootPath变量中
initPathUtil();/** * 初始化web根路径 */ private void initPathUtil() { String path = servletContext.getRealPath("/"); PathKit.setWebRootPath(path); }
B2.初始化constant, route, engine, plugin, interceptor, handler等信息
Config.configJFinal(jfinalConfig);
static void configJFinal(JFinalConfig jfinalConfig) { jfinalConfig.configConstant(constants);//调用 JFinalConfig 子类的 configConstant,自行跟踪
initLogFactory();//B21:初始化日志工厂 基于log4j封装class的getlog方法,不做解释
initEngine();//B22:初始化引擎 jfinalConfig.configRoute(routes);//调用 JFinalConfig 子类的方法,配置用户自定义controllerjfinalConfig.configEngine(engine);//调用 JFinalConfig 子类的方法,配置引擎
jfinalConfig.configPlugin(plugins);//调用 JFinalConfig 子类的方法,配置用户自定义的插件、redis插件、dbcp插件
startPlugins();B23:启动插件 very important!!! jfinalConfig.configInterceptor(interceptors);//调用 JFinalConfig 子类的方法,配置用户自定义的拦截器
jfinalConfig.configHandler(handlers);//调用 JFinalConfig 子类的方法,配置用户自定义hander
}B21.初始化log
/**
*初始化log的核心是创建logFactory对象,尝试创建log4j,如果创建失败,则使用JDK默认log工厂,详情省略
*/
static void init() { if (defaultLogFactory == null) { try { Class.forName("org.apache.log4j.Logger"); Class<?> log4jLogFactoryClass = Class.forName("com.jfinal.log.Log4jLogFactory"); defaultLogFactory = (ILogFactory)log4jLogFactoryClass.newInstance(); // return new Log4jLogFactory(); } catch (Exception e) { defaultLogFactory = new JdkLogFactory(); } } }B22:初始化引擎
initEngine()
/**
* 设置开发模式和模板文件跟目录,这个方法是Jfinal默认调用的,如果要更新engine里面的变量的话,则JFinalConfig继承类可重写configEngine(Engine engine);
*/
private static void initEngine() { engine.setDevMode(constants.getDevMode()); engine.setBaseTemplatePath(PathKit.getWebRootPath()); }B23:启动插件
PS:类似dbcp、redis等的初始化在jfinal中被定义成了插件的方式,startPlugins中我们重点强调什么是插件、插件能干啥?startPlugins()中并没有启动插件,仅仅是在jfinalConfig.configPlugin(plugins)后,设置插件的开发模式
private static void startPlugins() {
//获取插件列表 List<IPlugin> pluginList = plugins.getPluginList(); if (pluginList == null) { return ; } for (IPlugin plugin : pluginList) { try { // process ActiveRecordPlugin devMode if (plugin instanceof com.jfinal.plugin.activerecord.ActiveRecordPlugin) { com.jfinal.plugin.activerecord.ActiveRecordPlugin arp = (com.jfinal.plugin.activerecord.ActiveRecordPlugin)plugin; if (arp.getDevMode() == null) {
//基于用户定位设置插件的开发模式 arp.setDevMode(constants.getDevMode()); } } //启动插件,这步骤特别的重要,下个博客重点说明启动插件能干啥用。。。。[email protected]/[email protected] if (plugin.start() == false) { String message = "Plugin start error: " + plugin.getClass().getName(); log.error(message); throw new RuntimeException(message); } } catch (Exception e) { String message = "Plugin start error: " + plugin.getClass().getName() + ". \n" + e.getMessage(); log.error(message, e); throw new RuntimeException(message, e); } } }B3.初始化映射,包含controller和intercept
initActionMapping();PS:initActionMapping方法的本质将controller的映射和拦截器存储到ActionMapping,然后调用ActionMapping.buildActionMapping完成映射关系的初始化,下文对如何进行映射给予分析和说明
备注:未完待续明天继续2017-07-25 -
以上是关于Jfinal启动源码解读的主要内容,如果未能解决你的问题,请参考以下文章
ElasticSearchEs 源码之 PeerRecoverySourceService 源码解读