Tomcat Embedded 项目在 Eclipse 中工作但作为可运行的 Jar 失败

标签 tomcat executable-jar

目标是在独立的可执行 jar 中集成 Tomcat Embedded。
它在 Eclipse 中构建和运行完美,没有任何问题。然后,在将项目导出为“可运行 Jar”文件并尝试使用 java -jar filename.jar 从 cmd 控制台运行它后失败,并出现许多错误。

只有一个文件。这是代码:

package test.example.tomcat;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;


public class Main {

    public static void main(String[] args) {

        // URL in browser would be:
        // localhost:8080/tce/
         try {
            new Main().start();
        } catch (MalformedURLException | ServletException | LifecycleException e) {
            System.out.println("Error: Setting up Tomcat failed.\n"+e.getMessage());
            e.printStackTrace();
        }
    }
    public void start() throws ServletException, LifecycleException, MalformedURLException {

    Tomcat tomcat = new Tomcat();
    // set port
    String webPort = System.getenv("PORT");
    if(webPort == null || webPort.isEmpty()) {
        webPort = "8080";
    }
    tomcat.setPort(Integer.valueOf(webPort));

    // detrmine webapp local path
    String webappDirLocation = "WebContent/";
    // detrmine context path
    String contextPath = "/tce";
    // detrmine base directory for files
    String docBase = new File(webappDirLocation).getAbsolutePath();
    // detrmine servlet name
    String servletName = "TcEEx";
    // detrmine root url path
    String urlPattern = "/";

    // create a very basic servlet
    HttpServlet servlet = new HttpServlet() {

        private static final long serialVersionUID = 1L;

        @Override
        public void init(ServletConfig config) throws ServletException {
            System.out.println("Gooooooooooooooooood Morning!");                
        }

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            PrintWriter writer = resp.getWriter();

            writer.println("<html><title>Welcome</title><body>");
            writer.println("<h1>Have a Great Day!</h1>");
            writer.println("</body></html>");
        }
    };

    // set server base directory
    tomcat.setBaseDir(System.getProperty("java.io.tmpdir"));
    // instantiate context
    Context ctx = tomcat.addContext(contextPath, docBase);
    // add regular servlet
    tomcat.addServlet(contextPath, servletName, servlet);
    // map servlet
    ctx.addServletMappingDecoded(urlPattern, servletName);
    // get the default HTTP connector
    tomcat.getConnector();

    // start server
    try {
        tomcat.start();
    } catch (LifecycleException e) {
        System.out.println("Error: Starting Tomcat failed."+e.getMessage());
        e.printStackTrace();
      }
    tomcat.getServer().await();
    }

}

控制台输出:

Feb 17, 2019 10:53:20 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-8080"]
Feb 17, 2019 10:53:20 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service [Tomcat]
Feb 17, 2019 10:53:20 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet engine: [Apache Tomcat/9.0.16]
Feb 17, 2019 10:53:20 AM org.apache.catalina.core.ContainerBase startInternal
SEVERE: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@4fb64261]
        at java.util.concurrent.FutureTask.report(Unknown Source)
        at java.util.concurrent.FutureTask.get(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
        at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:831)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1377)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1367)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:902)
        at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardService.startInternal(StandardService.java:423)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:928)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.startup.Tomcat.start(Tomcat.java:455)
        at test.example.tomcat.Main.start(Main.java:98)
        at test.example.tomcat.Main.main(Main.java:26)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@4fb64261]
        at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:441)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:139)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:173)
        at org.apache.catalina.core.StandardContext.resourcesStart(StandardContext.java:4783)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4918)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1377)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1367)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:902)
        ... 22 more
Caused by: java.lang.Error: factory already defined
        at java.net.URL.setURLStreamHandlerFactory(Unknown Source)
        at org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.<init>(TomcatURLStreamHandlerFactory.java:130)
        at org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.getInstanceInternal(TomcatURLStreamHandlerFactory.java:53)
        at org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.register(TomcatURLStreamHandlerFactory.java:77)
        at org.apache.catalina.webresources.StandardRoot.registerURLStreamHandlerFactory(StandardRoot.java:699)
        at org.apache.catalina.webresources.StandardRoot.initInternal(StandardRoot.java:682)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
        ... 32 more

Feb 17, 2019 10:53:20 AM org.apache.catalina.core.ContainerBase startInternal
SEVERE: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: A child container failed during start
        at java.util.concurrent.FutureTask.report(Unknown Source)
        at java.util.concurrent.FutureTask.get(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
        at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardService.startInternal(StandardService.java:423)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:928)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.startup.Tomcat.start(Tomcat.java:455)
        at test.example.tomcat.Main.start(Main.java:98)
        at test.example.tomcat.Main.main(Main.java:26)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:921)
        at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:831)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1377)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1367)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:902)
        ... 14 more
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@4fb64261]
        at java.util.concurrent.FutureTask.report(Unknown Source)
        at java.util.concurrent.FutureTask.get(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
        ... 22 more
Caused by: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@4fb64261]
        at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:441)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:139)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:173)
        at org.apache.catalina.core.StandardContext.resourcesStart(StandardContext.java:4783)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4918)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1377)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1367)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:902)
        ... 22 more
Caused by: java.lang.Error: factory already defined
        at java.net.URL.setURLStreamHandlerFactory(Unknown Source)
        at org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.<init>(TomcatURLStreamHandlerFactory.java:130)
        at org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.getInstanceInternal(TomcatURLStreamHandlerFactory.java:53)
        at org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.register(TomcatURLStreamHandlerFactory.java:77)
        at org.apache.catalina.webresources.StandardRoot.registerURLStreamHandlerFactory(StandardRoot.java:699)
        at org.apache.catalina.webresources.StandardRoot.initInternal(StandardRoot.java:682)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
        ... 32 more

Error: Starting Tomcat failed.A child container failed during start
org.apache.catalina.LifecycleException: A child container failed during start
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:921)
        at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardService.startInternal(StandardService.java:423)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:928)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.startup.Tomcat.start(Tomcat.java:455)
        at test.example.tomcat.Main.start(Main.java:98)
        at test.example.tomcat.Main.main(Main.java:26)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: A child container failed during start
        at java.util.concurrent.FutureTask.report(Unknown Source)
        at java.util.concurrent.FutureTask.get(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
        ... 14 more
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:921)
        at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:831)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1377)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1367)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:902)
        ... 14 more
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@4fb64261]
        at java.util.concurrent.FutureTask.report(Unknown Source)
        at java.util.concurrent.FutureTask.get(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
        ... 22 more
Caused by: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@4fb64261]
        at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:441)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:139)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:173)
        at org.apache.catalina.core.StandardContext.resourcesStart(StandardContext.java:4783)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4918)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1377)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1367)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(Unknown Source)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:902)
        ... 22 more
Caused by: java.lang.Error: factory already defined
        at java.net.URL.setURLStreamHandlerFactory(Unknown Source)
        at org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.<init>(TomcatURLStreamHandlerFactory.java:130)
        at org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.getInstanceInternal(TomcatURLStreamHandlerFactory.java:53)
        at org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.register(TomcatURLStreamHandlerFactory.java:77)
        at org.apache.catalina.webresources.StandardRoot.registerURLStreamHandlerFactory(StandardRoot.java:699)
        at org.apache.catalina.webresources.StandardRoot.initInternal(StandardRoot.java:682)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
        ... 32 more

相关详情:

  • Apache Tomcat 9.0.16 嵌入式
  • Tomcat 的 jar 在 Classpath(Java 构建路径)中
  • Eclipse Oxygen.3a 4.7.3a
  • 作为动态 Web 项目创建的 Webapp
  • 不使用 maven/gradle 等,也不使用 Spring 等框架。手动完成。
  • Java 1.8.201
  • Win7/x64

在研究了 stackoverflow/google 上的类似问题及其建议/答案后,这里有一些失败的协调尝试(或排除)来解决此问题:

  • 导出前清理/重建项目..
  • 我的 jar 中包含经过验证的 Tomcat jar。
  • 确保端口空闲。
  • 重新下载 Jar
  • 尝试 Eclipse 可执行 jar 对话框中的三个库处理选项中的每一个
  • 将项目重新创建为 Java 项目而不是动态 Web 应用程序(这实际上使项目无法在 Eclipse 中运行)。

最佳答案

好吧,我自己解决了这个问题,所以我会保留这个问题并自己回答,因为这是一个最小且很好的代码示例,用于一个工作的 Web 应用程序,具有最新的,截至目前,嵌入了 Tomcat,可以轻松打包进入一个自包含和可执行的 jar 以及所有没有任何第 3 方 jar/fat jar 打包工具或包自动化工具的东西。我希望有人为我留下了这个解决方案。会节省很多时间和精力。

所以这是错误的:
第一步
从原始问题的控制台输出中可以看出,类和方法之间存在一些冲突。发生这种情况是因为在 Eclipse 将项目导出到可运行的 jar 文件时选择了错误的选项。
有 3 个选项:

  • 将所需的库提取到生成的 JAR 中
  • 将所需的库打包到生成的 JAR 中
  • 将所需的库复制到生成的 JAR 旁边的子文件夹中

选择了第二个,但随后发生了碰撞。选择第一个选项时,不会发生这些冲突。

第二步
但是由于缺少预期与 jar 位于同一路径的 WebContent 目录,它仍然无法运行。所以快速的解决方案,只是为了证明它适用于那里的目录(当然不是用于生产),是在程序首次启动时创建它
新文件("./WebContent").mkdirs();
例如在 main 方法中或在使用它之前的任何地方。

编辑
唯一需要注意的是,由于此选项提取依赖项 jar 并将它们与同一供应商 + 项目的原始依赖项 jar 重新打包,具有相同的域并且会混合,这也可能在将来添加许多 jar 时导致文件名冲突.因此,我仍然对有更好答案的人持开放态度,但不会过多依赖第 3 方工具。如果主 jar 可以将其他依赖项作为 jar 而不是提取出来,那就太好了。尽管路径相同,但不允许依赖文件混合的另一种方法也不错。

关于Tomcat Embedded 项目在 Eclipse 中工作但作为可运行的 Jar 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54732145/

相关文章:

java - myjsp 在哪里从 eclipse 物理发布到 Tomcat?

tomcat - 运行时环境在 Spring Tool Suite (STS) 上被禁用

java - 锁定 Jar 文件,将源文件隐藏在 .jar 文件中

java - 可执行 jar 中 Class.getResource() 和 ClassLoader.getResource() 的奇怪行为

excel - 使用开放文档和网络服务

tomcat - 如何将自签名的 openssl x509 证书添加到 Tomcat

java - 无法编译 Java 类,因为找不到文件

java - %~dp0 在名称中带有空格的文件夹下使用时不起作用

java - 为什么 Eclipse Export -> Executable Jar 不提供要包含的类的选择?

Windows UAC 不弹出(拒绝访问)