【问题标题】:Create a war with boot-clj使用 boot-clj 创建战争
【发布时间】:2015-12-06 17:42:14
【问题描述】:

我想创建一个可以使用 tomcat 部署的战争。使用lein uberwar 可以很好地完成这项工作,但是对 boot 执行相同操作似乎不起作用。我可以构建一个 jar 并运行它,但是战争失败了

2015 年 12 月 9 日上午 12:15:31 org.apache.catalina.loader.WebappClassLoader validateJarFile 信息: validateJarFile(/var/lib/tomcat7/sites/geeknow.guru/DEBUG##0.1.7/WEB-INF/lib/javax.servlet-api-3.1.0.jar) - jar 未加载。请参阅 Servlet 规范 3.0,第 10.7.2 节。违规类:javax/servlet/Servlet.class

我正在使用以下 build.boot

(set-env!
 :source-paths #{"src/clj"}
 :resource-paths #{"resources" "src/clj"}
 :dependencies '[[org.clojure/clojure "1.7.0"]
                 [clj-time "0.9.0"]
                 [org.clojure/java.jdbc "0.3.7"]
                 [org.postgresql/postgresql "9.4-1202-jdbc41"]
                 [yesql "0.5.1"]
                 [migratus "0.8.6"]
                 [markdown-clj "0.9.67"]
                 [jarohen/nomad "0.7.2"]
                 [com.draines/postal "1.11.3"]
                 [compojure "1.4.0"]
                 [ring/ring-core "1.4.0"]
                 [ring/ring-devel "1.4.0"]
                 [ring/ring-defaults "0.1.5"] 
                 [ring/ring-jetty-adapter "1.4.0"]
                 [ring-refresh "0.1.1"]
                 [ring-logger-timbre "0.7.5"]
                 [com.taoensso/timbre "4.1.4"]
                 [hiccup "1.0.5"]
                 [garden "1.3.0"]
                 [danlentz/clj-uuid "0.1.6"]
                 [speclj "3.3.1" :scope "test"]
                 [pandeiro/boot-http "0.7.1-SNAPSHOT"]])

(require '[pandeiro.boot-http :as http])
(require '[ring.middleware.reload :refer [wrap-reload]])
(require '[ring.adapter.jetty :as jetty])
(require '[ring.middleware.refresh :refer [wrap-refresh]])
(require '[blog.handler])

;;;;taken from boot-http.util
(defn resolve-sym [sym]
  (require (symbol (namespace sym)) :reload)
  (resolve sym))

(deftask ring-server
  []
  (comp (jetty/run-jetty (wrap-refresh (wrap-reload (resolve-sym 'blog.handler/app))) {:port 3000}) (wait)))

(deftask uberwar
  []
  (comp (aot) (pom) (web) (uber) (war)))

(deftask uberjar
  []
  (comp (aot) (pom) (uber) (jar)))

(task-options!
 pom {:project 'geeknow
      :version "0.1.7"}
 ;uber {:as-jars true}
 aot {:all true}
 jar {:main 'blog.core
      :manifest {"Description" "blog"}}
 web {:serve 'blog.handler/app}
 war {:main 'blog.core
      :manifest {"Description" "blog"}}
 repl {:init-ns 'blog.core})

【问题讨论】:

  • 您正在使用 jdk
  • 我知道。这就是为什么我尝试自己构建 clojure-adapter-servlet,但它没有帮助。如果有帮助,我使用以下命令构建和安装它boot -s src -d tailrecursion/clojure-adapter-servlet:0.2.1 -- pom -p clojure-adapter-servlet -v 0.2.1 -- jar -- install
  • 我在服务器上更新了 Java。现在我得到一个新的错误。我相应地更新了问题
  • 您在依赖项中包含了码头适配器,这将与您对 Tomcat 的部署发生冲突。不确定这是错误消息的原因。
  • 我需要码头适配器来运行本地服务器。我试图移除它来构建战争,但它没有帮助。

标签: clojure war boot-clj


【解决方案1】:

Tomcat 抱怨是因为您的 war 文件中包含的一个 jar 包含一个只有容器环境才能提供的类。战争中的违规罐子是WEB-INF/lib/javax.servlet-api-3.1.0.jar

默认情况下,uber 任务会在 --as-jars 设置为 true 时将所有依赖项(直接和传递)添加到 WEB-INF/lib 的战争中。 --as-jars 是捆绑依赖项以部署到 servlet 容器的首选方式。

问题似乎是您的直接依赖项之一是引入 javax.servlet-api 并且 uber 正在打包它,导致 Tomcat 问题。

首先我们需要弄清楚是哪个依赖项引入了javax.servlet-apiboot show 包含许多用于诊断此类依赖问题的选项。您可以通过boot show -h 了解所有这些信息。我们现在想要的是boot show -d,它会打印依赖树。

以下是相关输出的片段:

[ring/ring-jetty-adapter "1.4.0"]
├── [org.eclipse.jetty/jetty-server "9.2.10.v20150310"]
│   ├── [javax.servlet/javax.servlet-api "3.1.0"]
│   ├── [org.eclipse.jetty/jetty-http "9.2.10.v20150310"]
│   │   └── [org.eclipse.jetty/jetty-util "9.2.10.v20150310"]
│   └── [org.eclipse.jetty/jetty-io "9.2.10.v20150310"]
└── [ring/ring-servlet "1.4.0"]

从这个输出中,我们知道我们对ring/ring-jetty-adapter 的依赖是导致javax.servlet/javax.servlet-api 被引入的原因。

因为这个依赖对于本地开发是必要的,我们不想完全忽略它。相反,我们可以使用"test" 范围添加依赖:

[ring/ring-jetty-adapter "1.4.0" :scope "test"]

作用域是一个Maven concept,用于限制此类场景中依赖项的传递性。 Boot 使用 Maven 作为其底层依赖解析机制。 uber 对 Maven 作用域很敏感,可以根据需要配置包括或排除各种作用域。请参阅boot uber -h 了解更多信息。

默认情况下,uber 任务不会在"test" 范围内打包依赖项。通过以这种方式标记ring/ring-jetty-adapter,我们已将其排除在我们的超级战争之外。

"test" 范围对于您可能在测试中使用的依赖项(当然!)、部署或其他需要依赖项但不想与工件一起分发的任务也很有用,无论是库 jar 还是 uberwar 网络应用程序。

【讨论】:

  • 感谢您的详细回复。它真的帮助我理解了这个问题。不幸的是,ring-defaults 也带来了javax.servlet/servlet-api。我认为我在项目中使用的ring.middleware.defaults 需要ring-defaults。你知道如何解决这个问题吗?
  • @Held 您可以使用[ring/ring-defaults "0.1.5" :exclusions [javax.servlet/servlet-api]]ring-defaults 中排除servlet-api。然后,分别引入servlet-api仅在开发中[javax.servlet/servlet-api "2.5" :scope "test"]
  • 忽略我所说的再次引入 servlet-api,它已经由 ring-jetty-adapter 在本地提供。
  • 我试过了,但又遇到了一个错误。然而,由于我已经放弃了我的网络项目,这帮助我摆脱了一个错误并包含一些有用的信息,我将其标记为完成。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2022-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-23
  • 1970-01-01
相关资源
最近更新 更多