Jive 源代码探索
jive源代码的探索一直是很多朋友所在从事的,虽然有很多人对jive本身也提出了不同的批评意见,但是个人认为
学习jive的源代码是走向java编程成熟的一条捷径,由于本人水平有限加上对jive研究不久,所以其中的拙见
也希望各位朋友提出不同的意见.
这里只是本人对其中的一部分代码的分析,但是其中包括了java的三种常见的设计模式: factory proxy 和singlton
希望以下的分析对您的学习有一定的帮助.
篇一、首先需要了解其中的全局配置页:global.jsp
<jsp:useBean id="myEnv" scope="application" class="com.jdon.web.UserEnvFront"/> -------------------------(1)
<jsp:setProperty name="myEnv" property="*"/>
<%@ page import="java.util.*,
com.jivesoftware.util.*,
com.jivesoftware.forum.*,
com.jivesoftware.forum.util.*"
%>
<% // Check to see if a Jive authorization token exists
boolean isGuest = false;
Authorization authToken = SkinUtils.getUserAuthorization(request, response); --------------------------------(2)
if (authToken == null) {
authToken = AuthorizationFactory.getAnonymousAuthorization(); --------------------------------(3)
isGuest=true;
}
//init forumfactory and pageUser
myEnv.registeUserInit(authToken); ---------------------------------(4)
User pageUser = myEnv.getPageUser();
// The last time the user visited this page
Date lastVisited = new Date(SkinUtils.getLastVisited(request,response)); ----------------------------------(5)
// The number of messages a user wants to show per page
int userMessageRange = myEnv.du.getMessageRange(request,response,pageUser); --------------------------(6)
%>
(1)这里的javabean:myEnv在整个论坛运行期间的各页面都将调用之,因此在这里将其范围定义在application。
(2)这里用到了SkinUtils中的getUserAuthorization方法,如果你进入其源代码会发现,首先它获取
session中的用户信息,若用户是刚进入论坛的则通过用户的cookie来验证用户。
(3)若返回的authToken为空说明此用户是访客,则通过getAnonymousAuthorization方法来给用户分配
相应的验证级别,并将isGuest标志为true。
(4)在registeUserInit()方法中将会初始化其中的forumFactory,得到一个ForumFactoryProxy的实例对象,
public void registeUserInit(Authorization authToken){
try{
this.forumFactory = ForumFactory.getInstance(authToken);--->此处返回的其实是ForumFactoryProxy对象
this.pageUser=this.forumFactory.getUserManager().getUser(authToken.getUserID());
}catch(Exception ex){
}
}
可以看到在registeUserInit方法里面通过getInstance方法来得到一个ForumFactoryProxy对象,其实传入
ForumFactoryProxy中的factory参数在缺省下是com.jivesoftware.forum.database.DbForumFactory类型。
因此在ForumFacrotyProxy中的getUserManager()所操作的factory就是那个缺省的DbForumFactory的对象。
getUserManager()方法将返回一个UserManagerProxy的对象,然后通过其getUser()方法返回一个UserProxy
对象给pageUser,最后通过myEnv.getPageUser()将此pageUser传给了global.jsp中的pageUser。
(5)在SkinUtils.getLastVisited(request,response)中通过保存在cookie中的信息可以获取最后一次访问的时间。
(6)在myEnv.du.getMessageRange(request,response,pageUser)中可以自定义每页显示的message的数量。
分析:在对这部分的学习中我们会发现其中的三种设计模式在这里得到应用:1、工厂模式 2、代理模式 3、单态模式
这里提到的工厂模式是一个笼统的概念(把抽象工厂和工厂方法归为一类)。为了条理清晰我们将从注释(4)的 myEnv.registeUserInit(authToken)作为入口来进行剖析。在registeUserInit方法里我们看到了用于返回一个
forumFactory的ForumFactory.getInstance(authToken)方法,所以接下来我们要对其进行分析:
我们知道ForumFactory是一个abstract类,而其中唯一给一个方法做具体实现的只有其中的静态getInstance方法。
public static ForumFactory getInstance(Authorization authorization) {
//If no valid authorization passed in, return null.
if (authorization == null) {
return null;
}
if (factory == null) {
synchronized(initLock) {
if (factory == null) {
// Note, the software license expressely forbids
// tampering with this check.
//LicenseManager.validateLicense("Jive Forums Basic", "2.0");
String classNameProp =
JiveGlobals.getJiveProperty("ForumFactory.className");
if (classNameProp != null) {
className = classNameProp;
}
try {
//Load the class and create an instance.
Class c = Class.forName(className);
factory = (ForumFactory)c.newInstance();
}
catch (Exception e) {
System.err.println("Failed to load ForumFactory class "
+ className + ". Jive cannot function normally.");
e.printStackTrace();
return null;
}
}
}
}
//Now, create a forum factory proxy.
return new ForumFactoryProxy(authorization, factory,
factory.getPermissions(authorization));
}
上面的getInstance方法中可以引出上面提到的3种模式,首先getInstance方法本身是包容在工厂模式里面的,
ForumFactory类正是通过这个getInstance方法来得到一个代理工厂的。而在方法中我们还发现了同步对象initlock
由于它的存在使得下面的创建factory实例过程变成了同一时间只允许一个人访问的同步访问模式,单态模式也就
在这里得到了体现。接下去我们进入这个同步模块里面看看,首先我们看到 JiveGlobals.getJiveProperty("ForumFactory.className")
为了能够探个究竟我们只好进入JiveGlobals看看getJiveProperty方法究竟是如何get这些jive的property的。
首先我们看到在getJiveProperty方法里面主要有一个loadProperties()的方法:
private synchronized static void loadProperties() {
// If jiveHome is still null, no outside process has set it and
// we have to attempt to load the value from jive_init.properties,
// which must be in the classpath.
if (jiveHome == null) {
jiveHome = new InitPropLoader().getJiveHome();
}
//Create a manager with the full path to the xml config file.
properties = new XMLProperties(jiveHome + File.separator +
JIVE_CONFIG_FILENAME);
}
在loadProperties方法里首先通过getJiveHome()来得到相应的配置文件的路径,然后通过创建XMLProperties类
的对象来得到相应的配置文件内的属性。(在XMLProperties类里面提供了对XML文档内所存在属性的各种set、
get和delete的方法)。
回到同步模块!接下去的事情就比较清晰了,首先通过Class.forName()得到刚才从配置中取来的相应的类的Class
形式,然后将其造型为ForumFactory,最后跳出同步模块,看到了return一个ForumFactoryProxy的带参的对象。注意
其中的第2个参数factory,其实这个factory在上面的第(4)点已经提到了在其缺省情况下其实是DbForumFactory类型
的对象。在ForumFactoryProxy类里面需要制造产品forum的时候会调用方法createForum(),在这个方法里面我们现在
只关注:if (permissions.get(ForumPermissions.SYSTEM_ADMIN)) {
Forum newForum = factory.createForum(name, description);
return new ForumProxy(newForum, authorization, permissions);
}
发现在制造forum以前首先需要做一个permissions的授权,以检验相应的人员提供相应的permission。在这个if里面
使用了factory.createForum(name,description)返回一个制造出的forum。注意:我们在这里又发现了这个熟悉的factory
yes!这个factory就是刚刚在上面提到的那个传入ForumFactoryProxy对象里面的那个factory,而缺省情况下它就是屡屡
提到的DbForumFactory类型的对象。这个时候我们惊奇的发现原来我们现在操作的ForumFactory对象竟然是DbForumFactory。
(DbForumFactory类是继承自abstract ForumFactory类而可以对论坛里各种数据相对于数据库进行直接操作的类,里面包括
了创建forum、message等各种方法)。
ok!在代码里面游弋感觉总是找不到方向,昏头昏脑。现在我们跳出来从设计模式的角度来看看这一块:
工厂模式:
我们发现其间有很多的factory,包括ForumFactory、ForumFactoryProxy、DbForumFactory;在这里ForumFactory作为
一个抽象的父类被ForumFactoryProxy和DbForumFactory所继承,所以ForumFactory其实是一个抽象工厂,在这里ForumFactory
其实就起两个作用:1、声明方法 2、通过里面唯一的实现方法getInstance()来获得一个实工厂;在产生的实工厂中提供了
继承下来的方法的具体实现,最后的产品(如Forum、message)就将在这些实工厂中被生产出来。其实在jive的设计中运用
工厂模式的不只这里,象AuthorizationFactory、DbAuthorizationFactory这些也都是工厂模式在jive中的运用。
代理模式:
除了这么多的factory外我们还可以看很多的Proxy,代理模式在这里主要是被用于身份验证这一块。我们记得在工厂模式
的中ForumFactory.getInstance()产生的实工厂是ForumFactoryProxy(代理工厂),而不是直接产生DbForumFactory来生产
相关的产品。要了解里面的原因还是分析一下ForumFactoryProxy类中的一个典型的方法:
if (permissions.get(ForumPermissions.SYSTEM_ADMIN)) {
Forum newForum = factory.createForum(name, description);
return new ForumProxy(newForum, authorization, permissions);
}
else {
throw new UnauthorizedException();
}
我们还是拿熟悉的createForum()方法中一段代码来分析吧,我们看到在产生出一个产品forum前首先做了一个if的条件判断,
里面涉及到了类ForumPermissions,在这个类里面定义了9种访问权限和每种权限所能做的事情。因此这个if语句的判断也就
是为了检验其是否符合相关的操作,在这里我们看到能够做createForum()操作的只有SYSTEM_ADMIN这个权限。通过这个检验
的过程我们就能够控制论坛各种访问对象的权限了,这就是为什么ForumFactory.getInstance()要先产生ForumFactoryProxy
再通过ForumFactoryProxy去操作DbForumFactory的各种方法。其实在这里我们同样看到用createForum()方法产生出来的对象
也并不是Forum而是它的代理ForumProxy的对象,其中的道理也是雷同的。
至于单态模式由于在ForumFactory的getInstance方法中有所体现所以在这里也不再多讲。