如何嵌入Tomcat 6?

Posted

技术标签:

【中文标题】如何嵌入Tomcat 6?【英文标题】:How to embed Tomcat 6? 【发布时间】:2010-10-13 00:08:40 【问题描述】:

我目前正在生产环境中的 Tomcat 6 上运行我的 web 应用程序,并且想评估在嵌入式模式下运行 Tomcat。

除了api documentation 中的内容之外,还有什么好的教程或其他资源吗?

【问题讨论】:

有什么理由使用 Tomcat 而不是 Jetty,Jetty 对此用例有很好的记录并且常用的嵌入式?如果您只是在寻找可以嵌入的 Servlet 容器,Jetty 很容易做到这一点。 嵌入 Jetty。但是,有tomcat-embed。 感谢您的指点。但是,这看起来并不完整、未积极开发或维护。所有提交的日期为 2008 年 5 月 11 日,其中一条日志消息称其“远未完成”。 这篇博文值得一看:Embedding Tomcat 7 【参考方案1】:

代码不言自明。查看 pom.xml sn -p 和运行 tomcat 的类。

    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>catalina</artifactId>
        <version>6.0.18</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>coyote</artifactId>
        <version>6.0.18</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>jasper</artifactId>
        <version>6.0.18</version>
        <scope>test</scope>
    </dependency>


public class RunWebApplicationTomcat 

    private String path = null;
    private Embedded container = null;
    private Log logger = LogFactory.getLog(getClass());

    /**
     * The directory to create the Tomcat server configuration under.
     */
    private String catalinaHome = "tomcat";

    /**
     * The port to run the Tomcat server on.
     */
    private int port = 8089;

    /**
     * The classes directory for the web application being run.
     */
    private String classesDir = "target/classes";

    /**
     * The web resources directory for the web application being run.
     */
    private String webappDir = "mywebapp";

    /**
     * Creates a single-webapp configuration to be run in Tomcat on port 8089. If module name does
     * not conform to the 'contextname-webapp' convention, use the two-args constructor.
     * 
     * @param contextName without leading slash, for example, "mywebapp"
     * @throws IOException
     */
    public RunWebApplicationTomcat(String contextName) 
        Assert.isTrue(!contextName.startsWith("/"));
        path = "/" + contextName;
    

    /**
     * Starts the embedded Tomcat server.
     * 
     * @throws LifecycleException
     * @throws MalformedURLException if the server could not be configured
     * @throws LifecycleException if the server could not be started
     * @throws MalformedURLException
     */
    public void run(int port) throws LifecycleException, MalformedURLException 
        this.port = port;
        // create server
        container = new Embedded();
        container.setCatalinaHome(catalinaHome);
        container.setRealm(new MemoryRealm());

        // create webapp loader
        WebappLoader loader = new WebappLoader(this.getClass().getClassLoader());

        if (classesDir != null) 
            loader.addRepository(new File(classesDir).toURI().toURL().toString());
        

        // create context
        // TODO: Context rootContext = container.createContext(path, webappDir);
        Context rootContext = container.createContext(path, webappDir);
        rootContext.setLoader(loader);
        rootContext.setReloadable(true);

        // create host
        // String appBase = new File(catalinaHome, "webapps").getAbsolutePath();
        Host localHost = container.createHost("localHost", new File("target").getAbsolutePath());
        localHost.addChild(rootContext);

        // create engine
        Engine engine = container.createEngine();
        engine.setName("localEngine");
        engine.addChild(localHost);
        engine.setDefaultHost(localHost.getName());
        container.addEngine(engine);

        // create http connector
        Connector httpConnector = container.createConnector((InetAddress) null, port, false);
        container.addConnector(httpConnector);

        container.setAwait(true);

        // start server
        container.start();

        // add shutdown hook to stop server
        Runtime.getRuntime().addShutdownHook(new Thread() 
            public void run() 
                stopContainer();
            
        );
    
    /**
     * Stops the embedded Tomcat server.
     */
    public void stopContainer() 
        try 
            if (container != null) 
                container.stop();
            
         catch (LifecycleException exception) 
            logger.warn("Cannot Stop Tomcat" + exception.getMessage());
        
    

    public String getPath() 
        return path;
    

    public void setPath(String path) 
        this.path = path;
    

    public static void main(String[] args) throws Exception 
        RunWebApplicationTomcat inst = new RunWebApplicationTomcat("mywebapp");
        inst.run(8089);
    

    public int getPort() 
        return port;
    


【讨论】:

我无法让这个运行,只能得到 404s.. 我错过了什么吗? 你是否相应地更改了 catalinaHome、port、classesDir、webappDir 的属性?【参考方案2】:

虽然这篇文章有些陈旧,但我正在回答我自己的答案,因为它可以节省一些其他时间

package com.creativefella;

import org.apache.catalina.Engine;
import org.apache.catalina.Host;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Embedded;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TomcatServer 
    private Embedded server;
    private int port;
    private boolean isRunning;

    private static final Logger LOG = LoggerFactory.getLogger(TomcatServer.class);
    private static final boolean isInfo = LOG.isInfoEnabled();


/**
 * Create a new Tomcat embedded server instance. Setup looks like:
 * <pre><Server>
 *    <Service>
 *        <Connector />
 *        <Engine&gt
 *            <Host>
 *                <Context />
 *            </Host>
 *        </Engine>
 *    </Service>
 *</Server></pre>
 * <Server> & <Service> will be created automcatically. We need to hook the remaining to an @link Embedded instnace
 * @param contextPath Context path for the application
 * @param port Port number to be used for the embedded Tomcat server
 * @param appBase Path to the Application files (for Maven based web apps, in general: <code>/src/main/</code>)
 * @param shutdownHook If true, registers a server' shutdown hook with JVM. This is useful to shutdown the server
 *                      in erroneous cases.
 * @throws Exception
 */
    public TomcatServer(String contextPath, int port, String appBase, boolean shutdownHook) 
        if(contextPath == null || appBase == null || appBase.length() == 0) 
            throw new IllegalArgumentException("Context path or appbase should not be null");
        
        if(!contextPath.startsWith("/")) 
            contextPath = "/" + contextPath;
        

        this.port = port;

        server  = new Embedded();
        server.setName("TomcatEmbeddedServer");

        Host localHost = server.createHost("localhost", appBase);
        localHost.setAutoDeploy(false);

        StandardContext rootContext = (StandardContext) server.createContext(contextPath, "webapp");
        rootContext.setDefaultWebXml("web.xml");
        localHost.addChild(rootContext);

        Engine engine = server.createEngine();
        engine.setDefaultHost(localHost.getName());
        engine.setName("TomcatEngine");
        engine.addChild(localHost);

        server.addEngine(engine);

        Connector connector = server.createConnector(localHost.getName(), port, false);
        server.addConnector(connector);

        // register shutdown hook
        if(shutdownHook) 
            Runtime.getRuntime().addShutdownHook(new Thread() 
                public void run() 
                    if(isRunning) 
                        if(isInfo) LOG.info("Stopping the Tomcat server, through shutdown hook");
                        try 
                            if (server != null) 
                                server.stop();
                            
                         catch (LifecycleException e) 
                            LOG.error("Error while stopping the Tomcat server, through shutdown hook", e);
                        
                    
                
            );
        

    

    /**
     * Start the tomcat embedded server
     */
    public void start() throws LifecycleException 
        if(isRunning) 
            LOG.warn("Tomcat server is already running @ port=; ignoring the start", port);
            return;
        

        if(isInfo) LOG.info("Starting the Tomcat server @ port=", port);

        server.setAwait(true);
        server.start();
        isRunning = true;
    

    /**
     * Stop the tomcat embedded server
     */
    public void stop() throws LifecycleException 
        if(!isRunning) 
            LOG.warn("Tomcat server is not running @ port=", port);
            return;
        

        if(isInfo) LOG.info("Stopping the Tomcat server");

        server.stop();
        isRunning = false;
    

    public boolean isRunning() 
        return isRunning;
    


我也遇到了 404 错误并挣扎了一段时间。通过查看日志“INFO: No default web.xml”,我怀疑它(如果这是一个警告,那么很容易发现)。诀窍是使用 Tomcat 提供的web.xml ( rootContext.setDefaultWebXml("web.xml") ) (conf/web.xml)。原因是,它包括 DefaultServlet,它为 html、JS 等静态文件提供服务。使用 web.xml 或在您的代码中手动注册 servlet。

用法

// start the server at http://localhost:8080/myapp
TomcatServer server = new TomcatServer("myapp", 8080, "/src/main/", true);
server.start();
// .....
server.stop();

不要忘记将默认的web.xml 放在该程序的同一目录中或指向正确的位置。

需要注意的是,shutdown hook的灵感来自Antonio's answer。

【讨论】:

我尝试了您的示例,我的应用程序启动了,我看到 spring 正在初始化,但是当我尝试访问我的应用程序时,我收到 spring 错误消息,提示找不到我的 jsps 的映射。 小更新:org.apache.catalina.startup.Embedded 已弃用,建议改用org.apache.catalina.startup.Tomcat。进行此更改后,将进行许多链更改以使代码可运行。【参考方案3】:

使用 Tomcat 而非 Jetty 的原因有很多:

    已经熟悉 Tomcat 其中一个正在开发需要轻松传输到 Tomcat 安装的 Web 应用程序 Jetty 开发人员文档实际上比 Tomcat 的文档更精彩(太棒了!) 在 Jetty 社区中获得答案有时可能需要数年时间,例如 2007 年。请参阅 Embedding Jetty 重要提示:在 Jetty 6.1.* 之后,每个 Web 应用程序都会打开到自己的 JVM,因此如果您尝试在独立访问和 Web 应用程序之间获得编程访问,您唯一的希望是通过 Web API。 如果您有问题,Tomcat 是一个开源项目,其知识产权归 Apache 基金会所有,Jetty 是开源项目,但归一家小型私营公司(Mortbay Consulting)所有

第 5 点对我的工作很重要。例如,我可以通过 Tomcat 直接访问 JSPWiki 实例,但使用 Jetty 时完全无法访问。我在 2007 年要求解决这个问题,但还没有听到答案。所以我最终放弃并开始使用 Tomcat 6。我研究过 Glassfish 和 Grizzly,但到目前为止,Tomcat 是(令人惊讶的)最稳定和有据可查的 Web 容器(实际上并没有说太多)。

【讨论】:

"每个 Web 应用程序都打开到它自己的 JVM":您从哪里得到这些信息?我怀疑这是否准确。 听起来更像是一个类加载器。很难说。 我很确定 webapps 在它们自己的 JVM 中打开。他们默认使用单独的类加载器。要获得您想要的类加载器行为,只需使用 webapp.setParentLoaderPriority(true); - 我认为这是在 Jetty 文档中。 我在生产中使用过 Tomcat、Jetty 和 Grizzly,并且非常同意这个答案中所说的一切【参考方案4】:

这可能会有所帮助。

如果你下载Tomcat6.x的源码包,你会得到这个类:

http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/startup/Catalina.html#main(java.lang.String[])

这是一个如何使用 Embedd 类的示例:它是一个用于停止|启动特定 Tomcat 安装的 shell。 (我的意思是你可以设置 CATALINA_BASE 指向现有的 Tomcat 安装)。

如果你编译这个,你可以这样运行:

java -D"catalina.base=%CATALINA_BASE%" -D"catalina.home=%CATALINA_HOME%" org.apache.catalina.startup.Catalina start

我不确定如何更改此代码以关闭服务器!

【讨论】:

【参考方案5】:

几个月前读完这个帖子后,我写了这个项目:spring-embedded-tomcat。 它可以用来将tomcat6嵌入到基于Spring的应用程序中。

【讨论】:

【参考方案6】:

我认为使用 Tomcat 7 或 Jetty 9 嵌入更容易。在这里你会发现一个很好的介绍:http://www.hascode.com/2013/07/embedding-jetty-or-tomcat-in-your-java-application/

【讨论】:

以上是关于如何嵌入Tomcat 6?的主要内容,如果未能解决你的问题,请参考以下文章

如何在嵌入式 tomcat 中使用 digest.sh

如何在嵌入式tomcat中禁用http方法[重复]

如何使用嵌入式 tomcat 会话集群设置 Spring Boot 应用程序?

如何知道spring boot中嵌入了哪个tomcat版本

如何在 Spring Boot 应用程序中将用户添加到嵌入式 tomcat?

如何在带有嵌入式 tomcat 的 Spring Boot App 中设置域名