spring自己基本不熟悉,因为超多的xml配置太繁琐,就放弃了。自己也不是专做开发的,主要工作是运维。jfinal的出现,无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 voidconfigHandler(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对象实例 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()。
转自ypj5.com