继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

源码有毒:Jfinal源码解析(一)

Coley_5
关注TA
已关注
手记 86
粉丝 8548
获赞 6550

先从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>com.demo.MainConfig</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>jfinal</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

进入com.jfinal.core.JFinalFilter中的init方法

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

第一行代买调用了createJFinalConfig方法

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

createJFinalConfig里面逻辑很简单,取出配置在web.xml中我们自己写MianConfig类进行实例化。
接着看init方法

if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false)
            throw new RuntimeException("JFinal init error!");

这里又有一个init方法

boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {
        this.servletContext = servletContext;
        this.contextPath = servletContext.getContextPath();

        initPathUtil();

        Config.configJFinal(jfinalConfig);  // start plugin and init log factory in this method
        constants = Config.getConstants();

        initActionMapping();
        initHandler();
        initRender();
        initOreillyCos();
        initTokenManager();

        return true;
    }

这里才是整个框架真正初始化的地方

private void initPathUtil() {
        String path = servletContext.getRealPath("/");
        PathKit.setWebRootPath(path);
    }

这行代码没什么营养,看看即可
Config.configJFinal(jfinalConfig);

private static final Constants constants = new Constants();
    private static final Routes routes = new Routes(){public void config() {}};
    private static final Plugins plugins = new Plugins();
    private static final Interceptors interceptors = new Interceptors();
    private static final Handlers handlers = new Handlers();
    private static Log log;

    // prevent new Config();
    private Config() {
    }

    /*
     * Config order: constant, route, plugin, interceptor, handler
     */
    static void configJFinal(JFinalConfig jfinalConfig) {
        jfinalConfig.configConstant(constants);             initLogFactory();
        jfinalConfig.configRoute(routes);
        jfinalConfig.configPlugin(plugins);                 startPlugins(); // very important!!!
        jfinalConfig.configInterceptor(interceptors);
        jfinalConfig.configHandler(handlers);
    }

这里的逻辑也简单,在Config类中创建了五个单例对象,把我们自己写MianConfig中的路径信息、拦截器、数据库关系映射等信息写到了对应的单例对象中。
接下来看下我们自己的MianConfig类

@Override
    public void configConstant(Constants me) {
        loadPropertyFile("sysconfig.txt");
        me.setDevMode(getPropertyToBoolean("devMode", false));
    }

configConstant一般用来加载我们的配置文件(配置文件中一般放置一些数据库连接信息,初始化信息等)loadPropertyFile中的逻辑也很简单

public Properties loadPropertyFile(File file) {
        return loadPropertyFile(file, Const.DEFAULT_ENCODING);
    }

    public Properties loadPropertyFile(File file, String encoding) {
        prop = new Prop(file, encoding);
        return prop.getProperties();
    }

其中提供了getProperty方法,方便我们从配置文件中获取相应的值
继续看

@Override
    public void configRoute(Routes me) {
        me.add(new AppRoute());
    }

看下Routes的add方法

public Routes add(Routes routes) {
        if (routes != null) {
            routes.config();    // very important!!!

            for (Entry<String, Class<? extends Controller>> e : routes.map.entrySet()) {
                String controllerKey = e.getKey();
                if (this.map.containsKey(controllerKey)) {
                    throw new IllegalArgumentException("The controllerKey already exists: " + controllerKey); 
                }

                this.map.put(controllerKey, e.getValue());
                this.viewPathMap.put(controllerKey, routes.getViewPath(controllerKey));
            }
        }
        return this;
    }

第一行代码 routes.config(); // very important!!!
作者写了行注释very important!!!

/**
     * you must implement config method and use add method to config route
     */
    public abstract void config();

一个抽象方法,子类实现,添加相应的Controller到Routes中。看一个实例

public final class AppRoute extends Routes {

    @Override
    public void config() {
        this.add("/user", UserAction.class);
    }
}

在config中又调用了Routes中的add方法

public Routes add(String controllerKey, Class<? extends Controller> controllerClass) {
        return add(controllerKey, controllerClass, controllerKey);
    }
public Routes add(String controllerKey, Class<? extends Controller> controllerClass, String viewPath) {
        if (controllerKey == null)
            throw new IllegalArgumentException("The controllerKey can not be null");
        // if (controllerKey.indexOf(".") != -1)
            // throw new IllegalArgumentException("The controllerKey can not contain dot character: \".\"");
        controllerKey = controllerKey.trim();
        if ("".equals(controllerKey))
            throw new IllegalArgumentException("The controllerKey can not be blank");
        if (controllerClass == null)
            throw new IllegalArgumentException("The controllerClass can not be null");
        if (!controllerKey.startsWith("/"))
            controllerKey = "/" + controllerKey;
        if (map.containsKey(controllerKey))
            throw new IllegalArgumentException("The controllerKey already exists: " + controllerKey);

        map.put(controllerKey, controllerClass);

        if (viewPath == null  "".equals(viewPath.trim()))   // view path is controllerKey by default
            viewPath = controllerKey;

        viewPath = viewPath.trim();
        if (!viewPath.startsWith("/"))                  // "/" added to prefix
            viewPath = "/" + viewPath;

        if (!viewPath.endsWith("/"))                    // "/" added to postfix
            viewPath = viewPath + "/";

        if (baseViewPath != null)                       // support baseViewPath
            viewPath = baseViewPath + viewPath;

        viewPathMap.put(controllerKey, viewPath);
        return this;
    }
打开App,阅读手记
13人推荐
发表评论
随时随地看视频慕课网APP