JForum源码分析

JForum 是一个功能强大 ,易于管理的论坛。它的设计完全遵从MVC设计模式,可以轻松的定制与扩展,本文主要分析以下内容: web.xml,初始化流程,处理请求流程(mvc) ,文件监控 ,缓存实现,数据库访问实现,权限控制

JForum 是一个功能强大 ,易于管理的论坛。它的设计完全遵从MVC设计模式,能够在任何Servlet容器与EJB服务器上运行。而且可以轻松的定制与扩展JForum论坛。

Web.xml
ForumSessionListener监听器类
实现了HttpSessionListener接口,但是只是对session destory做了处理,在这个过程中,保存session的历史记录到DB,并清除用户信息和相关的security信息
ClickstreamFilter *.page的过滤器
实现了Filter接口,主要的任务交给BotChecker,是用来检测client是不是一个robot
JForum 一个servlet类
JForum的init流程:JForumBaseServlet.init -> JForumBaseServlet.startApplication -> 启动数据库 -> 预加载一些数据到缓存中(ForumRepository[Categories,Forums,同时在线最大人数,最后登录用户,注册用户数等等,用户等级,表情数据,屏蔽列表) -> 结束;
InstallServlet 一个servlet类  系统安装调用该类

初始化流程
JForum和InstallServlet都继承了JForumBaseServlet这个HttpServlet,而JForumBaseServlet包括2个重要的方法init和startApplication
int流程:
调用父类的init(正常情况这是必须调用的) -> 配置log4j -> startSystemglobals(加载全局参数配置SystemGlobals.properties -> 加载数据库配置database.driver.config(如mysql就是WEB-INF/config/database/mysql/mysql.properties) -> 加载自定义配置(默认的是jforum-custom.conf)) -> 配置缓存引擎 -> 配置freemarker模板引擎 -> 加载模块配置modulesMapping.properties -> 加载url映射配置urlPattern.properties -> 加载I18n配置(languages/*) -> 加载页面映射配置(templatesMapping.properties) -> 加载BBcode配置bb_config.xml -> 结束;

startApplication流程:   加载通用sql文件sql.queries.driver(就是/database/generic/generic_queries.sql) -> 加载特 定sql文件(如mysql就是/database/mysql/mysql.sql) -> 加载Quartz定时任务配置 -> 加载登录验证器(验证方式) -> 加载Dao实现方式 -> 加载文件修改监听器 -> 加载查询索引管理器 -> 加载定时统计任务。

处理请求流程(mvc)
MVC:
整个mvc的脉络就是client request -> 解析url(urlPattern.properties),获取module/action/param -> 通过module获取相应的module class,并通过action识别并调用相应的方法(modulesMapping.properties) -> 使用dao完成业务逻辑 -> 调用template进行渲染(templatesMapping.properties);

ORM:
jforum实现了自己的orm,当然不是hibernate那种,是类似ibatis的那种sql mapping,并提供了多套的sql文件来实现数据库无关的特性,整个流程也是比较清晰的,加载数据库配置 -> 加载sql mapping file -> 设置DAO实现 -> 通过named sql找到对应的sql(在*.sql里边对应着) -> 运行出数据

文件监控
在使用jforum的过程中,修改了某些文件如*.sql,jforum就会重新加载修改后的配置。是jdk的TimerTask类来实现的。请看ConfigLoader的listenForChanges方法:  FileMonitor.getInstance().addFileChangeListener(new QueriesFileListener(),                  SystemGlobals.getValue(ConfigKeys.SQL_QUERIES_GENERIC), fileChangesDelay);
FileMonitor是大管家,负责管理所有的文件监听器;FileChangeListener是一个监听器接口,只有一个方法,就是fileChanged(String filename),意思就是对某个filename的修改作出怎样的反应。使用的方法也很简单,就是实现一个FileChangeListener,并和监控的文件名,检查间隔作为参数传入就可以生效了。FileMonitor里边的实现原理就是,通过一个map(timerEntries)来保存(文件名/timertask),每次加入一个监听器的时候,会根据文件名先移出原来的文件监听器(缺点是只能能对一个文件添加一个监听器),然后构建一个TimerTask并加入到timerEntries中去。

缓存实现
jforum提供了数种缓存实现(JForumBaseServlet的init流程),分别是DefaultCacheEngine(简单的内存实现),JBossCacheEngine,EhCacheEngine。,请看ConfigLoader的startCacheEngine方法,流程大概就是得到cacheEngine的实现配置(SystemGlobals.properties中配置cache.engine.implementation),然后产生CacheEngine的实例,调用它的init方法进行初始化,然后找到所有的可缓存类(实现了Cacheable接口,并在SystemGlobals.properties中配置cacheable.objects),最后把cacheEngine注入进去获得cache的能力。

数据库访问实现
通过配置dao.driver(在特定的数据库配置里边如mysql.properties)获取到DataAccessDriver的实现 -> 初始化DataAccessDriver -> 获取到所有的Dao实现
如何获取connection?
查看JForumExecutionContext的  getConnection()c = DBConnection.getImplementation().getConnection();
在每次请求的过程中,connection只会获取一次,并在第一次获取到以后放到ThreadLocal里边去,这样在每个线程中保留一份数据(正确理解TheradLocal ),在请求请求结束以后才释放connection(service流程中的handleFinally方法)。

权限控制
流程 (详细看SecurityRepository的load方法):获取用户信息 -> 获取用户的所有groupid并组成一个用逗号隔开的字符串groupids -> 根据groupids获取所有的name/role_value -> 组装成RoleValueCollection -> 生成RoleCollection -> 最后生成PermissionControl

授权
后台管理实现了授权功能

认证
SecurityRepository的canAccess(int userId, String roleName, String value)方法:
根据userid获取PermissionControl-> 如果value参数为空的话,就判断是否拥有该roleName(通过内部的RoleCollection对象的keys),就是是否含有该权限 -> 如果value参数不为空的话,除了需要含有该权限,还要拥有相应的rolevalue(通过内部的RoleCollection对象的values)。参数中的value指数可以为论坛分类id,论坛id之类,随业务而定。

类UML图

标签: jforum


评论: