`

看Jive源代码研究

阅读更多
Jive源代码研究
作者:刘武东     来自:IBM

     地址:http://www.qqread.com/java/w820281060.html
  前言

  Jive是一个开放的Java源代码项目。其目标是建设一个开放结构的,强壮的,易于扩展的基于JSP的论坛。在其设计目标的指导下,其结构设计得非常得好,融合了很多新的观念,比如Design Pattern,可更换的Skin,可插入Plug等等。详细解读其源代码对于理解这些新的设计上的概念是很有裨益的。如果你对Design Pattern和Java语言有一定的了解,但是还是会时常迷惑于其中的话,不妨研究研究Jive源代码,一定会对其中的很多概念有更深入的理解。这篇文章源于我的Jive源代码研究笔记,希望能够提纲挈领,带领大家进入到这个美好的世界。当然,如果没有时间仔细地看源代码的话,看看这篇文章,我想也是会有一些帮助的。

  再开始之前,需要指出的是,Jive中对Design Pattern的应用,并没有拘礼与GOF书中所给出的实现方法,而是有许多变通的地方。一方面,我想是由于具体的实际需要,另一方面,我想这也是设计观念进化的结果吧。因而,这些变通的地方,将是我讲解的重点。

  整体结构概叙

  基于一个OO的设计原则:面向接口编程,而不是针对实现编程。Jive在设计的时候,把其大部分的基本对象都设计为接口或者抽象类。在Jive中,基本的接口有Forum,ForumMessage,ForumThread,Group,User,Authorization和Query。我们可以很容易的从这些接口的名字来知道他们的功用,下面的类图给出了这些类之间的一些静态关系:


图1:Jive整体关系

  你可能会有疑问,为什么会都是接口呢?这是基于扩展性考虑的。在Jive给出的实现中,所有的这些接口,Forum,ForumMessage,User等等,都使用数据库来实现的,一条消息,或者一个用户对应于数据库中的一条消息Jive使用了DbForum,DbForumMessage,DbUser等类来实现这些接口,通过JDBC来操作数据库,使之作为论坛的底层支撑。

  然而,有时候,或许我们并不想使用数据库,比如我们想只是使用文件系统来作为论坛的底层支撑,这时候,我们需要做的只是编码实现了Forum等等接口的诸如FileFroum,FileForumMessage等对象,然后嵌入Jive中即可,原有的任何代码都可以不用改变!!!这就是面向接口编程的威力了!

  下面来看看具体的设计和编码。

  AbstractFactory模式和可扩展性

  如果要实现较好的可扩展性,AbstractFactory模式确实是一件利器。如上面所说,如果要创建的Forum接口的不同实现,而又不想更改代码的话,就需要用到抽象工厂了。再Jive中,AuthorizationFactory类是一个抽象类,用来创建Authorization对象。这是一个抽象工厂,可以通过不同的子类来创建不同的Authorization对象。这个工厂的实现方法是:

  在AuthorizationFactory中使用一个private static变量factory,用来引用具体的抽象工厂的实例:

  private static AuthorizationFactory factory = null;

  用一个private static的String,来指明具体的抽象工厂的子类类名:

  private static String className ="com.coolservlets.forum.database.DbAuthorizationFactory";

  然后是用一个private static的loadAuthorizationFactory方法来给这个factory变量赋值,生成具体的抽象工厂类:

   private static void loadAuthorizationFactory() {
        if (factory == null) {
            synchronized(className) {
                if (factory == null) {
                    String classNameProp = PropertyManager.getProperty(
                        "AuthorizationFactory.className"
                    );
                    if (classNameProp != null) {
                        className = classNameProp;
                    }
                    try {
                        Class c = Class.forName(className);
                        factory = (AuthorizationFactory)c.newInstance();
                    }
                    catch (Exception e) {
                        System.err.println("Exception loading class: " + e);
                        e.printStackTrace();
                    }
                }
            }
        }
}

  在static的getAuthorization方法返回一个Authorization的过程中,先初始化工厂类factory变量,然后用factory的createAuthorization方法来创建:

   public static Authorization getAuthorization(String username,
            String password) throws UnauthorizedException
    {
        loadAuthorizationFactory();
        return factory.createAuthorization(username, password);
}

  不同的子类有不同的createAuthorization方法的实现。比如在DbAuthorizationFactory这个AuthorizationFactory的数据库实现子类中,createAuthorization方法是这样实现的:

   public Authorization createAuthorization(String username, String password)
            throws UnauthorizedException
    {
        if (username == null || password == null) {
            throw new UnauthorizedException();
        }
        password = StringUtils.hash(password);
        int userID = 0;
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(AUTHORIZE);
            pstmt.setString(1, username);
            pstmt.setString(2, password);

            ResultSet rs = pstmt.executeQuery();
            if (!rs.next()) {
                throw new UnauthorizedException();
            }
            userID = rs.getInt(1);
        }
        catch( SQLException sqle ) {
            System.err.println("Exception in DbAuthorizationFactory:" + sqle);
            sqle.printStackTrace();
            throw new UnauthorizedException();
        }
        finally {
            try {  pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try {  con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
        return new DbAuthorization(userID);
    }

  在这个类中,可以看到抽象类和具体的子类之间的关系,它们是如何协作的,又是如何划分抽象方法和非抽象方法的,这都是值得注意的地方。一般的,抽象方法需要子类来实现,而抽象类中的非抽象方法应该所有子类所能够共享的,或者可是说,是定义在抽象方法之上的较高层的方法。这确实是一个抽象工厂的好例子!虽然实现的方法已经和GOF中给出的实现相差较远了,但思想没变,这儿的实现,也确实是要巧妙的些。

  还有就是静态方法的使用,使得这个类看起来有些Singleton的意味。这使得对于AbstractFactory的创建变得简单。

  下面的类图给出了这个AbstractFactory的实现的总体情况:


图2:AbstractFactory模式的实现类图

  在AuthorizationFactory中定义的其它方法,涉及到具体的如何创建Authorization,都是作为abstract方法出现,具体实现留给子类来完成。

  这样,在需要生成一个Authorization的时候,只需要调用AuthorizationFactory的静态方法getAuthorization就可以了,由子类实现了具体的细节。

  其它的,如同上面讲到的,在创建Forum的时候用的ForumFactory,具有同上面一样的实现,这就是模式之所以称为模式的所在了。

  Proxy模式和权限控制

  Proxy模式的功能有很多,比如远程代理,用来给远程对象提供一个本地代表;虚代理,用来为创建开大开销的对象提供缓冲,等等。在Jive中使用的是保护代理,为被保护的对象提供权限控制。

  我们都知道在一个论坛中,权限的控制是必须的,否则论坛就很可能会被搞得一团糟。Jive中引入Proxy对象,Authorization接口以及权限描叙属类来提供对论坛的保护。

  以ForumFactory为例,一个额外的ForumFactoryProxy来处理权限认证的工作,它为某一个ForumFactory提供了一个代理,保证只有授权的用户才能够存取ForumFactory的某些操作。实际上ForumFactory在这儿不仅仅只是一个生成Forum的类的,它更像是一个Forum的管理类。提供了添加,删除,枚举等等一系列的功能,而有些功能不是什么样的人都可以使用的,因而引入了另外的一个代理类来处理权限的问题。

  当然,代理类需要继承ForumFactory,以使方法签名一致:

  ForumFactoryProxy extends ForumFactory

  在它的构造方法中,就提供了一个ForumFactory对象,这是需要被代理的对象;一个Authorization对象,提供用户信息;还有一个ForumPermissions,提供认证信息:

   public ForumFactoryProxy(ForumFactory factory, Authorization authorization,
            ForumPermissions permissions)
    {
        this.factory = factory;
        this.authorization = authorization;
        this.permissions = permissions;
    }

  一般的代理过程都是这样的,在访问某个方法之前,必须接受权限的检查,以createForum为例:

   public Forum createForum(String name, String description)
            throws UnauthorizedException, ForumAlreadyExistsException
    {
        if (permissions.get(ForumPermissions.SYSTEM_ADMIN)) {
            Forum newForum = factory.createForum(name, description);
            return new ForumProxy(newForum, authorization, permissions);
        }
        else {
            throw new UnauthorizedException();
        }
}

  下面给出这个模式的类图:


图3:Proxy模式的类图

  这个模式的实现基本上和GOF中所给出的实现一致。在Jive中,几乎所有的接口,Forum,ForumMessage,ForumThread等等,都会有一个相应的Proxy对象来进行权限控制。而在创建具体的对象的时候,都是用相应的Proxy对象来代替原有的对象返回的。例如在ForumFactory的getInstance()方法中需要返回一个Forum的时候,Jive是这样做的:

public static ForumFactory getInstance(Authorization authorization) {
......
        ForumFactoryProxy proxy = new ForumFactoryProxy(factory,authorization, factory.getPermissions(authorization));
        return proxy;
}

  因而,所有被创建的对象实际上都是Proxy对象,抽象工厂保证了没有权限验证的对象根本不会客户所得到,它们只会在Proxy的内部扮演角色,而永远不会被外部对象所存取,这样,就从根本上保证了论坛的安全。

  Decorator模式和过滤器

  一般的在OO设计中,而外功能的添加是通过继承来实现的,但是继承有的时候不够灵活,而且当功能的组合很多的时候,继承的子类就会成几何级数增长,使得类多的难以控制。正是基于这样的考虑,Decorator模式得以诞生。

  Decorator模式相当于封装了某个特定的操作,当某个对象需要这个操作的时候,加上这个Decorator即可。并且,多个Decorator还可以组合,以提供更多的功能。

  在Jive中,Decorator模式应用在一些过滤器(Filter)中。Filter提供对ForumMessage对象内容的重新构造。比如,当一个ForumMessage对象流过一个名为FilterCodeHighlight的过滤器后,存在于消息中的所有Java源代码文本,会被重新构造为具有语法高亮显示的消息。在比如,当经过了语法高亮修饰的消息再流过一个名为FilterHtml的过滤器后,消息中的HTML片断会被注释可以在HTML内部显示文本,这样就防止了用户输入了HTML控制标签后,使得页面显示不正常的问题。

  Jive中,所有的过滤器继承于一个抽象类ForumMessageFilter,而ForumMessageFilter又实现了ForumMessage接口。也就是说,每一个过滤器实际上也是一个ForumMessage对象。

  ForumMessageFilter中还封装一个ForumMessage对象。进行过滤的方法很简单,使用的是getBody(),比如在FilterCodeHighlight这个类中:

   public String getBody() {
        return highlightCode(message.getBody());
}

  highlightCode是一个private方法,实施具体的过滤的细节。getBody()方法实际上是定义在ForumMessage接口中的,当调用过滤器的getBody()方法时,就能够得到结构重整后的ForumMessage对象了。这个对象可以被其他客户引用,也可以在传递给另外的过滤器,实施进一步的操作。

  在实现一个具体的消息的过滤的时候,在Forum中有addForumMessageFilter(),applyFilters()方法,用来实现对过滤器的应用。

  对一个Forum,使用addForumMessageFilter()方法添加一个Filter的时候,并没有指定一个具体的Message,而只是一个规则(Filter中封装了过滤规则),然后applyFilter()方法中,实施这些规则:

   public ForumMessage applyFilters(ForumMessage message) {
        //Loop through filters and apply them
        for (int i=0; i < filters.length; i++) {
            message = filters[i].clone(message);
        }
        return message;
}

  过滤器的clone()方法,为过滤器复制消息体。这个方法的使用,分离了在过滤器中对于消息体和过滤规则的初始化过程,这也是一个值得借鉴的技巧!

  下面给出Decorator模式的类图:


图4:Decorator模式的类图

  我们可以看到Decorator模式实际上和Proxy模式是很相近的,但是它们代表两个不同的功能含义。Proxy模式提供一个对象的控制,而Decorator模式则是为对象提供额外的功能。

  Iterator模式和论坛的浏览

  Iterator模式用来分离数据结构和遍历算法,降低两者之间的耦合度,以使得同一个数据结构用不同的算法遍历时,仍能够具有相同的接口,另一方面,Iterator模式使得当改换遍历算法后,不需要更改程序的代码。

  在Java的JDK中本身就定义有一个Iterator接口,在Iterator接口中仅仅定义了三个方法,hasNext()判断是否遍历完最后一个元素,next()方法返回要遍历的数据结构中一个对象,remove()则删除当前对象。Jive中使用IteratorProxy抽象类继承了这一接口。这儿Proxy的含义和上面一样,也就是说,这个IteratorProxy出了会实现Iterator的遍历功能外,还会有代理权限控制的功能。

  对于论坛中的基本对象Forum,ForumThread,ForumMessage,Group,User都有相应的遍历器。比如对应于Forum接口有ForumIteratorProxy对象。这个ForumIteratorProxy遍历器就相当于一个封装了一系列Forum对象的集合类,通过定义好的接口hasNext()和next()可以方便的遍历这个集合,而并不需要知道是如何遍历这个集合的。遍历的算法可能很简单,也可能很复杂,但是对于外部的客户而言,这并没有任何的区别。

  而对于论坛中具体的遍历方法,这取决于具体的实现,在Jive中给出的是数据库的实现。

  我们就以MessageIteratorProxy为例,来讲解Iterator模式的用法。

  DbThreadIterator对象实现了Iterator接口,是对于一个Thread中所有Message的遍历器,我们来看看它是如何实现的。

  hasNext()判断在这个Thread中是不是还有下一条Message:

public boolean hasNext() {
     if (currentIndex+1 >= messages.length) {
            return false;
        }
        return true;
    }

  next()方法从数据库中取出与在这个Thread中的下一条Message:

   public Object next() throws java.util.NoSuchElementException {
        ForumMessage message = null;
        if (nextMessage != null) {
            message = nextMessage;
            nextMessage = null;
        }
        else {
            message = getNextMessage();
            if (message == null) {
                throw new java.util.NoSuchElementException();
            }
        }
        return message;
    }

  这样,通过对数据库的操作,DbThreadIterator实现了对一个Thread中所有Message遍历的方法。

  再ForumThread接口中有messages()方法,返回在这个Thread中的所有Message的一个遍历器(Iterator),实际上也就是返回了一个Message的集合:

  public Iterator messages();

  在DbForumThread中实现了这个方法:

  public Iterator messages() {return new DbThreadIterator(this);}

  从DbForumThread的messages()方法中所返回的就是这个Thread中所有Message的一个遍历器,通过这个遍历器,我们就可以访问Thread中的所有的Message了。当然,事情还没有完,由于权限的问题,我们还需要构造这个遍历器的Proxy对象,然后通过这个Proxy对象来访问遍历器。

  下面的类图给出了在Jive中Iterator模式的实现方法:


图5:Jive中Iterator模式的实现

  在Jive中,因为在一个Thread之下,Message是按树形结构组织的,因而,当需要层级表示一个Thread中的Message之间的关系的时候,仅仅用上面讲到的线性的Iterator是不够的。这时候,对Iterator的概念进行推广,就引入了TreeWalker接口。

  顾名思义,TreeWalker提供了遍历一个树和存取树上节点的方法:

public interface TreeWalker {
    public ForumMessage getRoot();
    public ForumMessage getChild(ForumMessage parent, int index);
    public int getChildCount(ForumMessage parent);
    public int getRecursiveChildCount(ForumMessage parent);
    public int getIndexOfChild(ForumMessage parent, ForumMessage child);
   public boolean isLeaf(ForumMessage node);
}

  TreeWalker只是Iterator的简单推广,并没有Iterator应用的那么广泛,而且,也可以很容易的在TreeWalker上面在套一层Iterator的借口,让它在某些情况下行使Iterator的职责。这儿就不再多讨论了。

  再此,Jive设计中所有涉及到的设计模式的地方,基本上都讲完了,看完了之后,是不是对设计模式有了更进一步的了解了呢?

分享到:
评论

相关推荐

    Jive源代码.zip

    《Jive源代码深度解析》 Jive源代码,作为一款知名的开源社交网络平台,其背后的编程艺术和设计理念,对于理解和构建大型企业级社交应用具有重要价值。本篇将深入探讨Jive源代码的核心概念、架构设计以及主要功能...

    jive2.1.1源代码,开源最彻底,拷贝到myeclipse直接可以跑起来

    jive2.1.1可以说是java进阶必须学习的一个...下载后只需自己稍微配置下初始化文件就可以,我敢保证网上基本上很难找到下载下来就可以跑的jive2.1.1源代码啦,好东西应该分享,希望大家自己研究,刚自己技术更上一层楼

    Jive Forum 系统完整分析

    开发过程中,Jive Forum 的团队可能使用了Git进行版本控制,Jenkins或Travis CI进行持续集成,确保代码质量和快速迭代。 通过分析JiveForum.html文件,我们可以更详细地了解这个论坛系统的具体实现细节,例如页面...

    jive源代码

    深入研究jive源代码,不仅可以学习到社交网络平台的构建技术,还可以了解大型分布式系统的架构设计,对于提升Java编程和企业级应用开发能力大有裨益。同时,参与开源项目也能锻炼协作和社区参与能力。

    Jive源代码研究

    Jive是一个开放的Java源代码项目。其目标是建设一个开放结构的,...这篇文章源于我的Jive源代码研究笔记,希望能够提纲挈领,带领大家进入到这个美好的世界。当然,如果没有时间仔细地看源代码的话,看看这篇文章,我

    jive 2.5 源代码

    《深入剖析Jive 2.5源代码:安装与研究指南》 Jive是一款功能强大的社交网络软件,它为企业提供了一个全面的协作平台,让用户能够进行沟通、分享知识和协同工作。在这里,我们重点关注的是Jive 2.5版本的源代码。源...

    jive的源代码

    以下是通过分析Jive源代码可以获得的一些关键知识点: 1. **JSP基础**:Jive的源代码大量使用了JSP技术,包括JSP脚本元素、EL(Expression Language)和JSTL(JavaServer Pages Standard Tag Library)。通过阅读...

    Jive源程序

    除了设计模式,Jive源代码还可能包含对Java核心库和框架的高级使用,如Spring框架的依赖注入,Hibernate的持久化操作,以及Servlet和JSP的Web开发技术。通过分析这些代码,你可以提升对Java Web开发的理解。 1. **...

    jive源代码、设计模式学习

    jive学习源码学习,前一阵下载别人的不能用,传一个好使的.希望对奋斗在IT前线的同志们能有所帮助...系统设计,设计模式,数据库设计,权限设计,缓存系统,源代码研究,扩展功能,国际化支持,全文搜索,安全认证……

    Jive论坛原代码.rar

    通过研究Jive论坛的源代码,我们可以深入了解JAVA在大型社区应用中的实际运用,以及如何运用设计模式来构建可扩展、易维护的系统。 首先,让我们关注“Jive论坛”的核心功能。Jive论坛主要由用户管理、论坛版块、...

    最早最经典的jive论坛源代码

    Jive论坛是一款基于Java开发的开源社区软件...通过研究这个最早的Jive论坛源代码,开发者不仅可以学习到Java Web开发的基础知识,还能掌握到社区应用的高级特性,对于提升个人技能和理解企业级应用开发有着深远的影响。

    jive2.1.1

    6. **source**:源代码的存放位置,开发者可以在这里查看和学习JSP页面、Java类以及其他编程资源的原始代码。 7. **javadoc**:JavaDoc是一个工具,用于自动生成关于Java源代码的API文档。在这个目录下,你可以找到...

    openfire源代码研究

    ### Openfire源代码研究 #### 一、Openfire源代码目录结构分析 ##### 1. build目录 - **概述**:此目录包含了构建Openfire安装文件所需的资源与配置,例如生成RPM包或其他类型的安装程序时所必需的脚本与文件。 -...

    jive.chm

    系统设计 1 jive设计思路 2 jive的工作内幕 3 Jive源代码研究 4 Jive中的设计模式 5 jive学习笔记 &lt;br&gt; 设计模式 1 大道至简-Java之23种模式一点就通 2 设计模式...

    Jive论坛分析_完整版

    源代码研究价值 - **学习价值**:对于那些希望深入了解设计模式和Java语言的开发者来说,研究Jive源代码是非常有益的。它不仅可以加深对设计模式的理解,还能学习到如何在实际项目中灵活运用这些模式。 #### 8. ...

    Jive资料集

    系统设计 1 jive设计思路 2 jive的工作内幕 3 Jive源代码研究 4 Jive中的设计模式 5 jive学习笔记 &lt;br&gt; &lt;br&gt; 数据库设计 1 Jive Forums数据库说明(英文) 2 Jive KB...

    jive2.6.rar_bbs论坛系统_jive_jive2._jive2.6

    对Jive 2.6的探索并不仅仅局限于源代码层面,"www.pudn.com.txt"这个文件可能是相关教程或资料的链接,提供了学习和研究的路径。开发者可以通过这些资源深入学习Jive的架构,了解如何部署、配置和优化论坛系统,甚至...

    Jive--SourceFile

    Jive是一款开源的企业社交网络平台,其源代码为Java开发者提供了深入理解企业级应用开发的宝贵资源。在本文中,我们将深入探讨Jive的源码,以及如何利用这些源码进行学习和开发。 首先,让我们关注一下Jive的核心...

Global site tag (gtag.js) - Google Analytics