论坛首页 Java企业应用论坛

使用嵌入式 Tomcat 简化程序调试

浏览 22811 次
该帖已经被评为精华帖
作者 正文
   发表时间:2004-11-13  
原文:http://www.blogcn.com/User8/flier_lu/blog/4740621.html

    在开发基于 Tomcat 的 Web 程序时,一个比较头痛的问题就是如何将以接口分离的后台服务与前台

页面进行联调。以 Tomcat 为中心的运行环境中虽然能够支持 IDE 直接进行跟踪调试,但配置麻烦、速

度较慢且限制很多,总不如直接对后台程序进行调试来的方便。
    一个较好的解决方法,是利用 Tomcat 的嵌入式版本,将 Tomcat 反过来嵌入到后台服务中,以后台

服务为主进行调试。这样一来 Tomcat 从整体容器变为后台服务的一种,在不改变行为的前提下,能够自

行定制调试环境。例如笔者开发的一个后台服务调试环境,支持基于命令行的简便移用的调试命令,直接

对各种后台服务进行控制,并通过前台界面验证结果,大大减轻了整合时的调试难度。

    虽然普通配置的 Tomcat 理论上也可以直接嵌入到后台程序,但推荐还是使用 Tomcat 定制的

Embeded 版本,这样集成度更高且性能较好。同时因为代码完全相同,不会存在调试环境内外的功能上的

差异问题。

    [url=http://apache.mirrors.versehost.com/jakarta/tomcat-5/v5.0.28/bin/jakarta-tomcat-

5.0.28-embed.tar.gz]Tomcat 5.0.28 Embed tar.gz[/url]

    在解压 Tomcat Embed 版本后,将其 lib 目录下所有 .jar 文件加入到 Java 项目的 classpath 中

,就可以着手在 Java 程序中启动 Tomcat 了。与普通的 Tomcat 配置类似,其运行需要创建如下组织的

结构:
<Server>
  <Service>
    <Connector />
    <Engine>
      <Host>
        <Context />
      </Host>
    </Engine>
  </Service>
</Server>

    只不过平时是配置 web.xml,而在嵌入版本中直接以程序方式完成。

    首先是建立 Tomcat 服务器,并指定其运行目录,此目录最好与 Tomcat Embed 版本路径相同。
  Embedded tomcat = new Embedded();;

  tomcat.setCatalinaHome(path);;
  tomcat.addEngine(engine);;
  tomcat.setDebug(Logger.WARNING);;

    然后创建缺省 Engine 和 Host,并将 Host 加入到 Engine 中。这里的名字只是起到标记作用,但

Host 的路径最好与 tomcat 路径保持一致。同一 Engine 实际上是可以有多个虚拟 Host 的,对大型站

点的自动测试可以将之分离进行。
  Engine engine = tomcat.createEngine();;
  engine.setName("EspServer");;

  Host host = tomcat.createHost("localhost", tomcat.getCatalinaHome(); + "/webapps");;

  engine.addChild(host);;
  engine.setDefaultHost(host.getName(););;

    对 Host 的内容填充,实际上就是具体 Web 应用程序的环境的建立过程。首先应该有一个缺省的

Context,在 URL 路径不匹配的时候会被使用。缺省 Context 的虚拟路径可以被设置为 "",内部实现时

自动转换为 "/";而其物理路径可以直接使用 Tomcat 自带的 /webapps/ROOT 内容,或者使用自定义内

容。
  Context ctxtRoot = tomcat.createContext("", host.getAppBase(); + "/ROOT");;
  ctxtRoot.setPrivileged(true);;

  host.addChild(ctxtRoot);;

    值得注意的是这里设置 ROOT 为特权程序,其区别主要在于 Context 容器的 ClassLoader 等。具体

细节有兴趣的朋友可以参考 Tomcat 中[url=http://jakarta.apache.org/tomcat/tomcat-5.0-

doc/class-loader-howto.html]关于 classloading 的文档[/url]
     Bootstrap
          |
       System
          |
       Common
      /      \
 Catalina   Shared
             /   \
        Webapp1  Webapp2 ...

    而对用户自己的 WebApp 实际上并不限于相同目录,完全可以任意设置,使用与创建 ROOT 程序类似

的方式即可。

    最后需要创建合适的 Connector 接受 http/https 请求。推荐将 web 服务绑定在本地 loopback 地

址上,限制只能本机访问。
  try
  {
    tomcat.addConnector(tomcat.createConnector(
        InetAddress.getByName("127.0.0.1");, 8080, false););;
  }
  catch (UnknownHostException e);
  {
    System.err.println("Bind tomcat server to 127.0.0.1:8080 failed.");;

    e.printStackTrace();;

    tomcat = null;
  }

    完整的嵌入式 Tomcat 创建代码示例如下:
private Embedded createTomcat(String path);
{
  Embedded tomcat = new Embedded();;

  tomcat.setCatalinaHome(path);;

  Engine engine = tomcat.createEngine();;
  engine.setName("EspServer");;

  Host host = tomcat.createHost("localhost", tomcat.getCatalinaHome(); + "/webapps");;

  engine.addChild(host);;
  engine.setDefaultHost(host.getName(););;

  Context ctxtRoot = tomcat.createContext("", host.getAppBase(); + "/ROOT");;
  ctxtRoot.setPrivileged(true);;

  host.addChild(ctxtRoot);;

  String espPath = ConfigManager.getProperty("ESP_ROOTDIR");;

  if(espPath == null || !new File(espPath);.exists(););
  {
    espPath = host.getAppBase(); + "/esp";

    if(!new File(espPath);.exists(););
    {
      System.err.println("You should set ESP_ROOTDIR in esp.config.");;

      return null;
    }
  }

  Context ctxtEsp = tomcat.createContext("/esp", espPath);;

  host.addChild(ctxtEsp);;

  tomcat.addEngine(engine);;
  tomcat.setDebug(Logger.WARNING);;

  try
  {
    tomcat.addConnector(tomcat.createConnector(
        InetAddress.getByName("127.0.0.1");, 8080, false););;
  }
  catch (UnknownHostException e);
  {
    System.err.println("Bind tomcat server to 127.0.0.1:8080 failed.");;

    e.printStackTrace();;

    tomcat = null;
  }

  return tomcat;
}

    然后就可以在合适的时候调用其 start/stop 方法启动或停止服务,感觉比标准配置的 tomcat 反映

迅速许多。
    此外可以通过一个辅助类的方法 ServerInfo.getServerInfo() 获取当前 Tomcat 版本信息用于显式

状态

    在此过程中有一些需要注意的细节问题。
    1.运行此程序时需要使用 JDK 而非 JRE,因为 Tomcat 需要动态编译 JSP 页面,可能还需要手工把

JDK 的 /lib/tools.jar 加入到项目 classpath 中。
    2.因为嵌入式版本 Tomcat 没有 common/lib 目录,如果碰到 JAXP 的 Provider 没有找到的 bug,

可能需要直接将 xercesImpl.jar 等实现包复制到 JDK 的 /jre/lib/endorsed 目录下。
    3.注意 classpath 中不要有其他版本 tomcat 的包,否则可能会出现冲突。

    如果需要进一步了解相关信息,可以参考 Tomcat 自带 JavaDoc 文档,或者 O'Reilly 的

Embedding Tomcat Into Java Applications 一文。
   发表时间:2004-11-23  
如果速度比启动单个快,还是值得试试。
0 请登录后投票
   发表时间:2004-11-24  
:D

开源怎么样?
0 请登录后投票
   发表时间:2004-11-24  
个人觉得用jetty比较方便, 不用Tomcat那么多的jar和配置信息.
0 请登录后投票
   发表时间:2004-12-06  
肯定比单个快。tomcat的默认web app好几个,还带war要解压,view一下还要编译好几大坨jsp,内存超过30、40兆很正常。。

btw,jetty用自己定义的xml启动很快,内存用得少。。。见
http://forum.iteye.com/files/op.jpg
0 请登录后投票
   发表时间:2005-01-22  
标记上了
回去试试
0 请登录后投票
   发表时间:2005-01-24  
test controller
0 请登录后投票
   发表时间:2005-04-11  
我faint,jetty5.1.3里面etc下的几个jasper要换成tomcat下的,把tomcat下的commons-el,etc下的ant.jar,jdk tools.jar才可以支持jstl1.1
0 请登录后投票
   发表时间:2005-06-05  
jetty4.*不支持jsp2.0,jetty5.*不支持jdk1.4,偏偏我要用jdk1.4支持jsp2.0的.昏了...
0 请登录后投票
   发表时间:2005-07-01  
其实 Eclipse 中启动 Tomcat 就是这么做的
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics