首页 > 代码库 > JFinal初始化分析-常量初始化-1

JFinal初始化分析-常量初始化-1

spring自己基本不熟悉,因为超多的xml配置太繁琐,就放弃了。自己也不是专做开发的,主要工作是运维。jfianl的出现,无xml配置,令人惊喜。

当时就想学一下这个框架的设计,就找博文来读,但是发现很多博主一遍赞叹jfinal的强大,一边说jfinal的设计很简单,好像每个博主自己都可以设计一套jfinal一样,但基本每个博主也都是蜻蜓点水的分析一下启动或某一块,然后及基本不再写了。

我自己觉得jfinal很强大,体量虽然很小,但是设计却不简单,相反却很精巧。可以看出波哥不是因为设计而设计。而是以简单、快速开发为设计核心的。

要自己设计写一套jfianl框架,没有较高的水平,很难。自己觉得jfianl框架不像大家认为的这么简单,要设计一套这样的框架绝非容易的事情。

反之自己抱着学习的态度,希望能搞明白里面的原理,需要时,也能自己造轮子。

这个算是开始吧,希望能坚持,遇到问题时,也希望能得到波哥的指点。

中间件部署web应用时,会加载web.xml配置文件,并依次listener -> filter -> servlet加载。

1、jfinal的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"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">

    <filter>
        <filter-name>jfinal</filter-name>
        <filter-class>com.jfinal.core.JFinalFilter</filter-class>
        <init-param>
            <param-name>configClass</param-name>
            <param-value>app.TestConfig</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>jfinal</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

可以看出web.xml配置文件没有配置监听、和serlvet,只有一个全局过滤器com.jfinal.core.JFinalFilter,可以说,这个过滤器是第一个被加载的class。

过滤器的生命周期是init()->doFilter()->destroy(),init()放一些初始化的信息,doFilter拦截所有请求,并进行处理。

jfinal号称无xml配置,只要通过一个class就可以完成所有配置,这个class如下:

public class TestConfig extends JFinalConfig{
    public void configConstant(Constants constants) {
        constants.setDevMode(true);
    }

    public void configRoute(Routes me) {
        me.add("/test",TestController.class);
    }

    public void configEngine(Engine engine) {

    }

    public void configPlugin(Plugins plugins) {

    }
    public void configInterceptor(Interceptors interceptors) {

    }
    public void configHandler(Handlers handlers) {}

    public static void main(String[] args){
        JFinal.start("src/main/webapp",8000,"/j");
    }
}

可以看出,用时继承JFinalConfig, 实现以下方法,就可以完成配置,如JFinalConfig源码:

//配置常量
public abstract void configConstant(Constants var1);
//配置路由
public abstract void configRoute(Routes var1);
//未知
public abstract void configEngine(Engine var1);
//配置插件
public abstract void configPlugin(Plugins var1);
//自定义拦截器,
public abstract void configInterceptor(Interceptors var1);
//过滤链,就是全局过滤器的过滤链
public abstract void
configHandler(Handlers var1);

从上可以看出,只要继承JFinalConfig,就可以完成自己的配置,这些配置我们先称为全局环境配置对象(Constants、Routes、Engine、Interceptors、Handlers等),那这些环境配置是什么时候被实例化的?

2、JFinal配置的加载 在web.xml配置中,过滤器有个参数,ConfigClass,值是app.TestConfig,就是JFconfigClass的子类,也就是自己的配置class.这说明,我们的配置的class是通过web.xml传递给了JFinalFilter过滤器的init()方法。

JFinalFilter的基础代码,简化后的:

public class JFinalFilter implements Filter {
private JFinalConfig jfinalConfig;//TestConfig将会赋值给它。
public void init(FilterConfig filterConfig) {
    createJFinalConfig(filterConfig.getInitParameter("configClass"));
}
}

createJFinalConfig的内部实现就是

jfinalConfig =(jfinalConfig)Class.forName("app.TestConfig").newInstance();

这样就new 了一个app.TestConfig的实例,但是只是实例,并没有调用里面的几个方法,所以方法中的传递的环境配置对象还是空的。比如TestConfig:

public void configConstant(Constants constants) {
        constants.setDevMode(true);
}

并没有被执行,所以constants还是空的。这里涉及两个问题:

1、谁调用configConstant()方法,并传递了Constants 实例对象?

2、Constants 实例化后,如何使用Constants 实例对象?

我们基本可以考虑,这些相关配置对象应该只会被初始化一次,不可能被反复new 出新的对象。那么可以猜测这些配置的对象应该是单实例,或者static final的来初始化的。

继续往下看,可以看到是JFinal.init完成了对这些configConstant()方法的调用。

public class JFinalFilter implements Filter {
private JFinalConfig jfinalConfig;//TestConfig将会赋值给它。
public void init(FilterConfig filterConfig) {
    //反射生成TestConfig对象实例(<a href="http://www.mamicode.com/ypj5.com">羊皮卷网</a>)
    createJFinalConfig(filterConfig.getInitParameter("configClass"));
    //通过调用TestConfig中的方法,完成环境对象的设置,
    if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false) {
			throw new RuntimeException("JFinal init error!");
	}
}
}

可以看到,jfinalConfig对象传递给了jfinal.init()方法,这个方法返回一个boolean值,如果是false表示初始化失败了。同时还将ServletContext传递给了jfinal.init()方法。下面就需要分析jfinal.init()方法了。可以猜测代码是这么样写的:

public class JFinal(){
    public static final Constants =new Constants();
    public static init(JFinalConfig testConfig,ServletContext context){
        testConfig.configConstant(Constants);
    }
}

这样就完成了TestConfig.configConstant方法调用,就完成了Constants里面字段的set()。

JFinal初始化分析-常量初始化-1