Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / JFinal 的初始化

浅析初始化过程

首先要从 web 容器进行初始化<?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.fw.config.MppConfig</param-value></init-param></filter><filter-mapping><filter-name>jfinal</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app> 从 web.xml 可以看出,容器初始化的时候会加载 JFinalFilter 这个类并且调用其 init 方法。public final class JFinalFilter implements Filter {private Handler handler;private String encoding;private JFinalConfig jfinalConfig;private Constants constants;private static final JFinal jfinal = JFinal.me();private static Log log;private int contextPathLength;public void init(FilterConfig filterConfig) throws ServletException {createJFinalConfig(filterConfig.getInitParameter("configClass"));if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false)throw new RuntimeException("JFinal init error!");handler = jfinal.getHandler();constants = Config.getConstants();encoding = constants.getEncoding();jfinalConfig.afterJFinalStart();String contextPath = filterConfig.getServletContext().getContextPath();contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());}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;elsethrow new RuntimeException("Can not create instance of class: " + configClass + ". Please check the config in web.xml");}// ...} init 方法中的参数正是 web.xml 中的 JFinalFilter 的初始化参数,即 com.fw.config.MppConfig,它继承于 JFinalConfig,在 createJFinalConfig 中利用该参数使用反射机制得到 JFinalConfig 的实例。jfinal.initboolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {this.servletContext = servletContext;this.contextPath = servletContext.getContextPath();initPathUtil();Config.configJFinal(jfinalConfig);constants = Config.getConstants();initActionMapping();initHandler();initRender();initOreillyCos();initTokenManager();return true;}第一、initPathUtil,初始化 Path工具类的 webRootPath(即项目根路径)。private void initPathUtil() {String path = servletContext.getRealPath("/");PathKit.setWebRootPath(path);}第二、Config.configJFinal 加载 JFinalConfig 实例,进行一些配置。static void configJFinal(JFinalConfig jfinalConfig) {jfinalConfig.configConstant(constants);initLogFactory();jfinalConfig.configRoute(routes);jfinalConfig.configPlugin(plugins);startPlugins();// very important!!!jfinalConfig.configInterceptor(interceptors);jfinalConfig.configHandler(handlers);}配置常量,初始化 Log 工具类,配置路由,配置插件,开启插件,配置拦截器,配置 handler。下面看看我项目中的 JFinalConfig 实例。 public class MppConfig extends JFinalConfig {
   
   //配置常量
    public void configConstant(Constants me) {
        PropKit.use("jdbc.properties");
        me.setDevMode(PropKit.getBoolean("devMode", false));
    }
   
   //配置路由
    public void configRoute(Routes me) {
        me.add(new RoutesMapping());       
    }
   
   public static C3p0Plugin createC3p0Plugin() {
       return new C3p0Plugin(PropKit.get("jdbcUrl"), PropKit.get("user"), PropKit.get("password").trim());
    }
   
   //配置插件
    public void configPlugin(Plugins me) {
       // 配置C3p0数据库连接池插件
        C3p0Plugin C3p0Plugin = createC3p0Plugin();
        me.add(C3p0Plugin);
       
       // 配置ActiveRecord插件
        ActiveRecordPlugin arp = new ActiveRecordPlugin(C3p0Plugin);
        me.add(arp);
       
       // 配置属性名(字段名)大小写不敏感容器工厂 Oracle
        arp.setContainerFactory(new CaseInsensitiveContainerFactory());
       
       //缓存插件
        me.add(new EhCachePlugin());
       
       // 所有配置在 MappingKit 中搞定
        ModelMapping.mapping(arp);
    }
   
   //配置全局拦截器
    public void configInterceptor(Interceptors me) {
          me.add(new SessionInViewInterceptor());//session拦截器,用于在View模板中取出session值
    }
   
   //配置处理器,接管所有 web 请求
    public void configHandler(Handlers me) {
        me.add(new ContextPathHandler("contextPath"));//设置上下文路径
    }
   
   //系统启动完成后回调,如创建调度线程
    public void afterJFinalStart(){}
   
   //系统关闭前回调,如写回缓存
    public void beforeJFinalStop(){}
}View Code第三、初始化 ActionMapping、Handler、Render等。initActionMapping();initHandler();initRender();initOreillyCos();initTokenManager();

Init ActionMapping

private void initActionMapping() {actionMapping = new ActionMapping(Config.getRoutes(), Config.getInterceptors());actionMapping.buildActionMapping();Config.getRoutes().clear();}第一、创建 ActionMapping,映射所有访问路径和其对应的Action,填充得到一个 HashMap。下面是创建 ActionMapping 代码和注释,涉及到其他类的源码请自行查看。final class ActionMapping {private static final String SLASH = "/";private Routes routes;// ActionMapping 映射private final Map<String, Action> mapping = new HashMap<String, Action>();// 构造方法,routes 参数传进来ActionMapping(Routes routes, Interceptors interceptors) {this.routes = routes;}private Set<String> buildExcludedMethodName() {Set<String> excludedMethodName = new HashSet<String>();Method[] methods = Controller.class.getMethods();for (Method m : methods) {if (m.getParameterTypes().length == 0)excludedMethodName.add(m.getName());}return excludedMethodName;}void buildActionMapping() {// 初始化,我将要向里面塞东西了,要清空一下mapping.clear();// 这个方法返回的是 Controller接口的所有方法集合。Set<String> excludedMethodName = buildExcludedMethodName();// 得到 InterceptorManager 的实例InterceptorManager interMan = InterceptorManager.me();// 遍历一个 Entry 集合。Entry 的 key 为访问路径,value 为其对应的 Controller。for (Entry<String, Class<? extends Controller>> entry : routes.getEntrySet()) {// 得到访问路径对应的 Controller classClass<? extends Controller> controllerClass = entry.getValue();// 如果 Controller class没有拦截器注解,则返回一个空数组。反之返回这个类所有拦截器组成的数组Interceptor[] controllerInters = interMan.createControllerInterceptor(controllerClass);boolean sonOfController = (controllerClass.getSuperclass() == Controller.class); // 这里必定为 true// getDeclaredMethods 得到这个类的所有方法以及其接口的所有方法,不包括继承的方法Method[] methods = (sonOfController ? controllerClass.getDeclaredMethods() : controllerClass.getMethods());for (Method method : methods) {String methodName = method.getName();//若这个方法是继承自 Controller的方法 或 该方法有参数,过滤掉if (excludedMethodName.contains(methodName) || method.getParameterTypes().length != 0)continue ;// 若这个方法不是 public 方法,过滤掉if (sonOfController && !Modifier.isPublic(method.getModifiers()))continue ;// 想进行到这里,这个方法必须满足:不是继承自 Controller、不能有参数、必须是 public 方法// 得到包含所有拦截器的数组(包括全局的拦截器,类级别的拦截器、方法级别的拦截器)Interceptor[] actionInters = interMan.buildControllerActionInterceptor(controllerInters, controllerClass, method);String controllerKey = entry.getKey();ActionKey ak = method.getAnnotation(ActionKey.class);String actionKey;// ActionKey 不为空的话为设置自定义的访问路径(说明有方法被注有 @ActionKey 注解)if (ak != null) {actionKey = ak.value().trim();if ("".equals(actionKey))throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank.");if (!actionKey.startsWith(SLASH))actionKey = SLASH + actionKey;}// ActionKey为空,methodName 为 index的情况下:actionKey = controllerKeyelse if (methodName.equals("index")) {actionKey = controllerKey;}// ActionKey为空,methodName 不为 index的情况下:actionKey = controllerKey +"/" + methodNameelse {actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName;}// 组合装配成一个 ActionAction action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey));// 填充 HashMap(访问路径为 key,Action 为 value)if (mapping.put(actionKey, action) != null)throw new RuntimeException(buildMsg(actionKey, controllerClass, method));}}// support url = controllerKey + urlParas with "/" of controllerKeyAction action = mapping.get("/");if (action != null)mapping.put("", action);}// ...}View Code第二、Config.routes 已经用过了,以后也不会再用上了,清空路由的所有信息。

Init Handler

private void initHandler() {Handler actionHandler = new ActionHandler(actionMapping, constants);handler = HandlerFactory.getHandler(Config.getHandlers().getHandlerList(), actionHandler);}第一、创建一个 ActionHandler 实例 actionHandler。第二、HandlerFactory.getHandler 创建一个 Handler 链,链尾是 actionHandler,并且返回链首。public class HandlerFactory {private HandlerFactory() {}/** * 创建一个 handler 链条,最后返回的 result 是 handler 链的头部,链尾是 ActionHandler */@SuppressWarnings("deprecation")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.next = result;temp.nextHandler = result;result = temp;}return result;}} 

Init Render

private void initRender() {RenderFactory.me().init(constants, servletContext);}继续跟~ public class RenderFactory {
   
    public void init(Constants constants, ServletContext servletContext) {
        this.constants = constants;
        this.servletContext = servletContext;
       
        // 初始化 Render
        Render.init(constants.getEncoding(), constants.getDevMode());    // 初始化编码和开发模式
        initFreeMarkerRender(servletContext);        // 初始化 FreeMarkerRender
        initVelocityRender(servletContext);
        initJspRender(servletContext);
        initFileRender(servletContext);
       
        // 创建 mainRenderFactory
        if (mainRenderFactory == null) {
            ViewType defaultViewType = constants.getViewType();
            if (defaultViewType == ViewType.FREE_MARKER) {
                mainRenderFactory = new FreeMarkerRenderFactory();
            } else if (defaultViewType == ViewType.JSP) {
                mainRenderFactory = new JspRenderFactory();
            } else if (defaultViewType == ViewType.VELOCITY) {
                mainRenderFactory = new VelocityRenderFactory();
            } else {
                throw new RuntimeException("View Type can not be null.");
            }
        }
       
        // 创建 errorRenderFactory
        if (errorRenderFactory == null) {
            errorRenderFactory = new ErrorRenderFactory();
        }
       
        if (xmlRenderFactory == null) {
            xmlRenderFactory = new XmlRenderFactory();
        }
    }
   
    private void initFreeMarkerRender(ServletContext servletContext) {
        try {
            Class.forName("freemarker.template.Template");    // 加载 freemarker 模板
            FreeMarkerRender.init(servletContext, Locale.getDefault(), constants.getFreeMarkerTemplateUpdateDelay());
        } catch (ClassNotFoundException e) {
            // 若加载模板失败,比如没有引入 jar 包
            LogKit.logNothing(e);
        }
    }
   
    // ...
}

public class FreeMarkerRender extends Render {
   
    private static final String contentType = "text/html; charset=" + getEncoding();
    private static final Configuration config = new Configuration();
   
   
    static void init(ServletContext servletContext, Locale locale, int template_update_delay) {
        // 初始化 freemarker 配置:config = new Configuration();
        // 设置 freemarker 页面的存放位置为项目根路径
        config.setServletContextForTemplateLoading(servletContext, "/");
       
        // 设置开发模式下更新延迟时间
        if (getDevMode()) {
            config.setTemplateUpdateDelay(0);
         }
        else {
            config.setTemplateUpdateDelay(template_update_delay);
        }
       
        // - Set an error handler that prints errors so they are readable with
        // a HTML browser.
        // config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
        config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
       
        // - Use beans wrapper (recommmended for most applications)
        config.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
        config.setDefaultEncoding(getEncoding());        // 设置默认编码
        config.setOutputEncoding(getEncoding());            // 设置输出编码
        // - Set the default locale
        config.setLocale(locale /* Locale.CHINA */ );        // 设置时区
        config.setLocalizedLookup(false);
       
        // 去掉int型输出时的逗号, 例如: 123,456
        // config.setNumberFormat("#");        // config.setNumberFormat("0"); 也可以
        config.setNumberFormat("#0.#####");
        config.setDateFormat("yyyy-MM-dd");
        config.setTimeFormat("HH:mm:ss");
        config.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");
    }
   
    // ...
}

Init 上传组件

private void initOreillyCos() {OreillyCos.init(constants.getBaseUploadPath(), constants.getMaxPostSize(), constants.getEncoding());}很简单,附上相关代码:public class OreillyCos {
   
   // 先加载上传组件
    public static void init(String uploadPath, int maxPostSize, String encoding) {
       if (StrKit.isBlank(uploadPath)) {
           throw new IllegalArgumentException("uploadPath can not be blank.");
        }
       try {
            Class.forName("com.oreilly.servlet.MultipartRequest");
            doInit(uploadPath, maxPostSize, encoding);
        }catch (ClassNotFoundException e) {
            LogKit.logNothing(e);
        }
    }
   
   private static void doInit(String uploadPath, int maxPostSize, String encoding) {
        uploadPath= uploadPath.trim();
        uploadPath= uploadPath.replaceAll("\\", "/");
       
        String baseUploadPath;
       
       // 判断上传路径是否是绝对路径,如果不是把它加工成绝对路径
        if (PathKit.isAbsolutelyPath(uploadPath)) {
            baseUploadPath= uploadPath;
        }else {
            baseUploadPath= PathKit.getWebRootPath() + File.separator + uploadPath;
        }
       
       // remove "/" postfix
        if (baseUploadPath.equals("/") == false) {
           if (baseUploadPath.endsWith("/")) {
                baseUploadPath= baseUploadPath.substring(0, baseUploadPath.length() - 1);
            }
        }
       
        MultipartRequest.init(baseUploadPath, maxPostSize, encoding);
    }
   
   // ...
}

public class MultipartRequest extends HttpServletRequestWrapper {
   
   private static String baseUploadPath;
   private static int maxPostSize;
   private static String encoding;
   
   static void init(String baseUploadPath, int maxPostSize, String encoding) {
        MultipartRequest.baseUploadPath= baseUploadPath;
        MultipartRequest.maxPostSize= maxPostSize;
        MultipartRequest.encoding= encoding;
    }
   
   // ...
}View Code 

Init Token令牌

private void initTokenManager() {ITokenCache tokenCache = constants.getTokenCache();if (tokenCache != null)TokenManager.init(tokenCache);}先给个代码吧:public class TokenManager {private static ITokenCache tokenCache;private static Random random = new Random();private TokenManager() {}public static void init(ITokenCache tokenCache) {if (tokenCache == null)return;TokenManager.tokenCache = tokenCache;long halfTimeOut = Const.MIN_SECONDS_OF_TOKEN_TIME_OUT * 1000 / 2;// Token最小过期时间的一半时间作为任务运行的间隔时间new Timer().schedule(new TimerTask() {public void run() {removeTimeOutToken();}}, halfTimeOut, halfTimeOut);}// ...} ----- End -----Jfinal学习之路---Controller使用 http://www.linuxidc.com/Linux/2014-07/104323.htmJFinal开发8个常见问题 http://www.linuxidc.com/Linux/2015-02/113421.htmJFinal的详细介绍:请点这里
JFinal的下载地址:请点这里本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-09/135258.htm