tomcat - Tomcat 嵌入式项目在 Eclipse 中工作,但作为可运行 Jar 失败
问题描述
目标是一个包含 Tomcat Embedded 的独立可执行 jar 中的 webapp。
它可以完美地构建和运行,在 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 的 jars 在 Classpath (Java Build Path) 中
- Eclipse Oxygen.3a 4.7.3a
- 作为动态 Web 项目创建的 Webapp
- 不使用 maven/gradle 等,也没有 Spring 等框架。手动进行。
- Java 1.8.201
- Win7/x64
在对 stackoverflow/google 上的类似问题及其建议/答案进行研究后,以下是一些未能(或排除)解决此问题 的和解尝试:
- 导出前清理/重建项目..
- 经过验证的 Tomcat jar 包含在我的 jar 中。
- 确保端口是空闲的。
- 重新下载罐子
- 在 Eclipse 可执行 jar 对话框中尝试三个库处理选项中的每一个
- 将项目重新创建为 Java 项目而不是动态 Web 应用程序(这实际上使项目无法在 Eclipse 中运行)。
解决方案
好吧,我自己解决了这个问题,所以我会保留这个问题并自己回答,因为这是一个非常简单且很好的代码示例,适用于最新的工作 Webapp,截至目前,Tomcat 嵌入,可以很容易地打包成一个 self包含和可执行的 jar 以及所有没有任何 3rd 方 jar/fat jar 打包工具或包自动化工具的东西。我希望有人为我留下了这个解决方案。会节省很多时间和精力。
所以这里出了什么问题:
第一步
从原始问题的控制台输出中可以看出,类和方法之间存在一些冲突。发生这种情况是因为 Eclipse 将项目导出到可运行的 jar 文件时选择了错误的选项。
有 3 个选项:
- 将所需的库提取到生成的 JAR 中
- 将所需的库打包到生成的 JAR 中
- 将所需的库复制到生成的 JAR 旁边的子文件夹中
选择了第二个,但随后发生了这些冲突。选择第一个选项时,不会发生这些冲突。
第二步
但由于缺少预期与 jar 路径相同的 WebContent 目录,它仍然无法运行。所以快速解决方案,只是为了证明它可以与那里的目录一起工作(当然不是用于生产),是在程序第一次启动时创建它
new File("./WebContent").mkdirs();
例如,在 main 方法中或在其使用之前的任何地方。
编辑
唯一需要注意的是,由于此选项提取依赖 jar 并将它们与原始依赖 jar 重新打包,相同供应商 + 项目的依赖 jar 具有相同的域并且会混合,这也可能在将来添加许多时导致文件名冲突罐子。因此,我仍然愿意接受没有过多依赖第三方工具的更好答案的人。如果主 jar 可以将其他依赖项保存为 jar 而不是提取,那就太好了。尽管路径相同,但不允许依赖文件混合的另一种方法也很好。
推荐阅读
- node.js - 使用 NodeJS 在不知道索引的情况下更新 MongoDB 中数组中的单个元素
- architecture - 像 Kafka 这样的系统如何确保分区内的排序
- fortran - 在 FORTRAN 中将数字定义为参数是否有性能优势
- oracle-apex - Oracle APEX4.2.6 交互式报告电子邮件选项
- azure - 如何导出完整结果 Databricks Azure
- python - Python - 解压缩两个索引数据框
- javascript - 聚焦时更改 div 的 css
- google-cloud-platform - YAML 文件到 Google BigQuery。我在 Google Cloud Platform 上的架构应该是什么?
- javascript - Js类扩展返回太快
- node.js - 错误:找不到模块“babel-register”