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);
    
    }

    启动时,从WebRoot-->Web-INF-->web.xml开始
    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 子类的方法,配置用户自定义controller
            jfinalConfig.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

时间: 2024-10-23 19:25:03

Jfinal启动源码解读的相关文章

struct2源码解读(1)之struts2启动

struct2源码解读(1)之struts启动 之前用struct2.spring.hibernate在开发一个电子商城,每天都在重复敲代码,感觉对struct2.spring.hibernate的理解都在使用层面上,虽然敲了几个月代码,但是技术水平还是得不到显著提高.于是就想着研究下struct2.spring.hibernate的源码,研究完后不仅对struct2.spring.hibernate加深了了解,同时也加强了java的学习,例如xml的解析,字符操作,线程等等,受益匪浅.想着当初

swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?

date: 2018-8-01 14:22:17title: swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?description: 阅读 sowft 框架源码, 了解 sowft 启动阶段的那些事儿 小伙伴刚接触 swoft 的时候会感觉 压力有点大, 更直观的说法是 难. 开发组是不赞成 难 这个说法的, swoft 的代码都是 php 实现的, 而 php 又是 世界上最好的语言, swoft 的代码阅读起来是很轻松的. 之后开发组会用 系列源码 解读文章, 深入解析

struct2源码解读(8)之container原理

struct2源码解读之container原理 container翻译成中文的意思是容器,通俗地来说,就是struct2的运行环境.这个所谓的运行环境,有点类似于一个容器,里面装着各种对象,当struct2处理aciton请求的,就会容器中取相应的对象.下面探讨下container的实现原理.container是一个接口,主要有两个方法,一个是inject() 一个是getInstance():getInstance()是从容器取出对象,inject()是依赖注入.struts在启动的时候,就把

【Spark】SparkContext源码解读

SparkContext的初始化 SparkContext是应用启动时创建的Spark上下文对象,是进行Spark应用开发的主要接口,是Spark上层应用与底层实现的中转站(SparkContext负责给executors发送task). SparkContext在初始化过程中,主要涉及一下内容: SparkEnv DAGScheduler TaskScheduler SchedulerBackend SparkUI 生成SparkConf SparkContext的构造函数中最重要的入参是Sp

Tomcat源码解读:我们发起的HTTP请求如何到达Servlet的

在上一节中,了解了Tomcat服务器启动的整个过程,现在来了解一下Tomcat如何接收到HTTP请求,并将请求送达至Servlet,Servlet处理后,响应信息又是如何返回给浏览器的呢?这两个问题是接下来要研究的课题,本节先研究第一个问题. 了解一点点网络知识的人,都会知道TCP连接通信是基于Socket的,上一节也有提到这点.通过上一节的说明,可以了解到Tomcat服务器在内部已经使用Endpoint类封装了Socket. 本篇会包含大量的源码解读说,由于篇幅原因,就将源码折叠起来,如果想了

(转)go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin

转自:http://www.baiyuxiong.com/?p=886 ----------------------------------------------------------------------- 上一篇go语言nsq源码解读-基本介绍  介绍了最基本的nsq环境搭建及使用.在最后使用时,我们用到了几个命令:nsqlookupd.nsqd.nsqadmin.curl及 nsq_to_file,并看到用curl命令写入的几个”hello world”被nsq_to_file命令保

Spark发行版笔记10:Spark Streaming源码解读之流数据不断接收和全生命周期彻底研究和思考

本节的主要内容: 一.数据接受架构和设计模式 二.接受数据的源码解读 Spark Streaming不断持续的接收数据,具有Receiver的Spark 应用程序的考虑. Receiver和Driver在不同进程,Receiver接收数据后要不断给Deriver汇报. 因为Driver负责调度,Receiver接收的数据如果不汇报给Deriver,Deriver调度时不会把接收的数据计算入调度系统中(如:数据ID,Block分片). 思考Spark Streaming接收数据: 不断有循环器接收

dotNet源码解读--HashTable目录扩展的奥秘

摘要:为了探索dotnet中hashtable的目录结构及与目录扩展相关的算法,本文通过对相关源码的阅读与分析,得出如下结论,hashtable的目录是由数组组织,目录元素代表一个数据节点,不是数据桶.目录扩展是扩展当前目录长度2倍往1遍历过程中遇到的第一个素数.目录扩展触发条件:装载因子式的触发,同时考虑到"杂乱程度"需要进行重新散列.目录扩展时需要遍历原有目录中所有的元素.查询过程与探测再散列类似. 关键词:dotnet,hashmap,目录扩展方法,目录扩展触发条件 一.目录结构

自动化WiFI钓鱼工具——WiFiPhisher源码解读

工具介绍 开源无线安全工具Wifiphisher是基于MIT许可模式的开源软件,运行于Kali Linux之上. github.com/sophron/wifiphisher 它能够对WPA加密的AP无线热点实施自动化钓鱼攻击,获取密码账户.由于利用了社工原理实施中间人攻击,Wifiphisher在实施攻击时无需进行暴力破解. 此外安利一个我们正在开发的项目,基于wifiphisher的校园网钓鱼工具,希望有小伙伴来一起玩耍:-P github.com/noScripts/Campus-Fake