调试开源项目:mvnForum论坛

    最近在读一个开源论坛的源码,也就是mvnForum,发现源码是很难读懂的,应该对其进行调试,了解其运行时信息,这样有助于对源码的理解。但是我遗憾的发现,mvnForum的源码是基于ant脚本的,并不是一个eclipse工程,因此并不能直接借助eclipse对其进行调试。我试图将其转变为一个eclipse工程,但是配置方面有点问题,始终无法在eclipse中运行。于是我只能想一些其他的笨办法来调试。如果哪位朋友能够将mvnForum源码成功转化为一个可调试的Eclipse工程,麻烦教一教我,非常感激!!!
    我能够想到的调试思路就是:在正常的环境下运行论坛,并将感兴趣的信息打印出来。
    这个思路说起来简单,但是做起来还是有一些麻烦的,比如:
    1、正常运行论坛,是没有控制台界面的,System.out.print方法并不能打印出相应的信息。
    2、要想打印感兴趣的信息,就要修改源码,然后编译,最后把类放到适当的位置,这个操作是及其繁琐的,很讨厌人的。
    3、对于有一些类,比如OnlineUser类,他的信息有很多,如果都打印出来看,要写好长的代码,非常麻烦,这个问题也是需要解决的。
    面对上述三个问题,我采取了如下的解决办法:
    1、采用Logger,将调试信息记录到文本文件中。Logger默认情况下是将信息输出到控制台,因此需要对其进行配置。为了实现一次配置,多次使用,我只使用系统默认的Logger。那么该在哪里对这个Logger进行配置呢?当然是在ContextListener中,它监听服务器的启动,是进行初始化配置的好地方。具体配置代码如下:
  1. Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
  2. Handler h = new FileHandler("d:/aa.txt");  //将输出信息定位到D盘的文件
  3. logger.addHandler(h);  
  4. logger.setUseParentHandlers(false);  //屏蔽控制台信息
  5. h.setFormatter(new SimpleFormatter());  //输出信息格式为简单格式
当然,上述代码是需要处理异常的,在这里简化了。在上下文监听器中进行配置之后,就可以在任何一个源文件中,简单的使用下面这条语句,进行信息的输出:
  1. Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("调试信息");
    2、写一个ant脚本来负责类的打包和转移。我虽然无法让论坛在Eclipse中运行起来,但是我还是使用Eclipse来查看和修改源码的。我们无需关心修改了哪个类,只需要将所有的类一起打包转移就好了。这个脚本代码最好写在源码自带的build.xml文件中,因为一些路径信息已经在该文件中配置好了。在mvnforum文件夹下就有一个build.xml文档,我就将脚本写在这个文档里了:
  1. <target name="my-deploy" description="将我修改后的代码打包并复制到C盘相应目录">
  2.   <delete file="C:/Tomcat/webapps/mvnforum/WEB-INF/lib/mvn.jar"/>
  3.   <jar destfile="C:/Tomcat/webapps/mvnforum/WEB-INF/lib/mvn.jar" basedir="${basedir}/../bin"/>
  4. </target>
需要简单的说明一下,上述路径是我的mvnForum的安装路径,每个人要根据实际情况进行修改。另外,论坛的源码一共有3个顶级包,分别是com包、net包、java包,而在原版的可执行代码中,这3个包是放在2个jar文档中的,即com包放在mvnforum.jar中,net包和java包放在mvncore.jar中。但事实上,包是可以放在任意一个jar文档中的,不会影响程序的执行。因此,为了简化起见,我的上述ant脚本是将所有的包都放在mvn.jar中,这样也是正确的。当然,既然有了mvn.jar,另外两个(mvnforum.jar和mvncore.jar)就应该被删除掉。
    3、利用java的反射功能,写一个万能的类,能够打印出任何一个对象的信息。具体思路就是:定义一个类,写一个static的方法,这个方法接收一个对象的引用,利用反射机制对这个对象进行分析,得到其一个方法列表,这个列表中的方法都有如下特征:无参数、以is开头、或者以get开头。因为根据一般的命名规范,具有上述特征的方法才是返回信息的。同时,我们还要对异常进行及时的处理,尤其是“空指针异常”,因为在我们的调试阶段,并不是所有的信息都是可用的,出现空指针是很正常的。如果不能及时处理,会影响到信息的打印。具体代码如下:
  1. import java.lang.reflect.Method;
  2. public class GetAllInfo {
  3.     public static String get(Object o) {
  4.         StringBuilder sb = new StringBuilder();
  5.         try {
  6.             Class<?> c = Class.forName(o.getClass().getName());
  7.             Method[] methods = c.getMethods();
  8.             String s = null;
  9.             for(Method m:methods) {
  10.                 if(m.getGenericParameterTypes().length == 0 && (m.getName().startsWith("is") || m.getName().startsWith("get"))) {
  11.                     try{
  12.                     s = m.invoke(o, new Object[0]).toString();
  13.                     sb.append(m.getName() + ": " + s + System.getProperty("line.separator"));
  14.                     } catch (Exception e) {
  15.                         sb.append(m.getName() + ": null" + System.getProperty("line.separator"));
  16.                     }
  17.                 }
  18.             }
  19.         } catch (Exception e) {
  20.             e.printStackTrace();
  21.         }
  22.         return sb.toString();
  23.     }
  24. }
在使用上述代码的时候,有一个需要注意的地方:在mvnforum中,大量运用了工厂模式,也就是并不直接调用某个类的构造函数,而是通过工厂来产生对象,将对象赋值给一个接口,通过接口来使用对象。这就出现一个问题,接口是public的,但是实际的对象不一定是public的。例如OnlineUser是一个public的接口,但具体的实现类OnlineUserImpl却不是public的,而是缺省的包作用域。这时,通过上述方法打印这个类的信息就会失败,因为你的方法和这个类不是同一个包,不能访问这个类的方法。所以,为了调试的需要,我们还应该将相应的类改为public属性,才能自由的得到该类的信息。

你可能感兴趣的:(调试开源项目:mvnForum论坛)