簡體   English   中英

在類路徑上有多個 servlet-api 庫時出錯

[英]Error while having multiple servlet-api libs on classpath

我有 Spring 啟動應用程序運行嵌入式 Tomcat。 我在 docker 容器中運行它。 當我嘗試關注有關 spring 在容器中啟動並構建分層映像的頁面時,當我嘗試啟動容器時收到下面提到的錯誤。 我知道最好的方法是從我的依賴項中排除舊版本的 servlet-api,但這是不可能的,因為在我這樣做時這種依賴項停止工作。 不幸的是,我也無法擺脫這種依賴。 有沒有辦法強制 Spring Boot 使用類路徑中的特定實現? 我已經嘗試過 Jetty 和 Undertow 以及 docker 成功啟動,但是使用舊版本的 lib 無法正常工作。

另一個問題是為什么當我只復制 jar 並啟動它時它會起作用?

我正在嘗試構建的 Dockerfile :

FROM adoptopenjdk:11-jre-hotspot

ARG DEPENDENCY=target/dep 
COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib 
COPY ${DEPENDENCY}/META-INF /app/META-INF
COPY ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","com.test.App"]

Dockerfile 有效:

FROM adoptopenjdk:11-jre-hotspot

COPY /target/application.jar /app/application.jar
COPY /target/lib /app/lib

ENTRYPOINT ["java", "-jar", "app/application.jar"]

可行的方法需要 pom.xml 中的其他插件才能實現:

                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <executions>
                            <execution>
                                <id>build-info</id>
                                <goals>
                                    <goal>build-info</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-jar-plugin</artifactId>
                        <version>3.1.0</version>
                        <configuration>
                            <finalName>ttom-osm-converter</finalName>
                            <archive>
                                <manifest>
                                    <addClasspath>true</addClasspath>
                                    <classpathPrefix>lib/</classpathPrefix>
                                    <mainClass>com.tomtom.mep.App</mainClass>
                                </manifest>
                            </archive>
                        </configuration>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-dependency-plugin</artifactId>
                        <executions>
                            <execution>
                                <id>copy-dependencies</id>
                                <phase>prepare-package</phase>
                                <goals>
                                    <goal>copy-dependencies</goal>
                                </goals>
                                <configuration>
                                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>

來自 POM 的依賴項:

        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>  <!-- lib contains servlet-api-2.5 -->
        <groupId>com.test.lib</groupId> 
        <artifactId>client</artifactId>
        <version>${model.client.version}</version>
    </dependency>

錯誤:

java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [NonLoginAuthenticator[StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[/path]

***************************
APPLICATION FAILED TO START
***************************

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

org.apache.catalina.authenticator.AuthenticatorBase.startInternal(AuthenticatorBase.java:1220)

The following method did not exist:

'java.lang.String javax.servlet.ServletContext.getVirtualServerName()'

The method's class, javax.servlet.ServletContext, is available from the following locations:

jar:file:/app/lib/servlet-api-2.5.jar!/javax/servlet/ServletContext.class
jar:file:/app/lib/javax.servlet-api-4.0.1.jar!/javax/servlet/ServletContext.class
jar:file:/app/lib/tomcat-embed-core-9.0.29.jar!/javax/servlet/ServletContext.class

  It was loaded from the following location:

file:/app/lib/servlet-api-2.5.jar


Action:

Correct the classpath of your application so that it contains a single, compatible version of javax.servlet.ServletContext

從有關“java.lang.String javax.servlet.ServletContext.getVirtualServerName()”的錯誤中,我們可以看到它是在Servlet 3.1中添加的:您應該排除 servlet-api:2.5。

使用以下命令:

mvn dependency:tree -Dincludes='*:servlet-api' 

這將列出所有模塊/依賴項,包括servlet-api

然后從依賴項中排除壞版本: com.test.lib客戶端甚至不應該首先包含它,這意味着也應該在其中提供依賴項。

<dependency>  <!-- lib contains servlet-api-2.5 -->
  <groupId>com.test.lib</groupId> 
  <artifactId>client</artifactId>
  <version>${model.client.version}</version>
  <exclusions> <exclusion> <groupId>...</groupId> <artifactId>servlet-api</artifactId> </exclusion> </exclusions>
</dependency>

請注意servlet-api groupId 隨着時間的推移發生了變化:這可能是 Maven 不 select “好” servlet-api的原因之一。

我建議您使用 maven-enforcer-plugin 來鎖定這些不良依賴項:

          <rules>
            <bannedDependencies>
              <excludes>
                <exclude>*:servlet-api:2.5</exclude>
              </excludes>
            </bannedDependencies>
          </rules>
          <fail>true</fail>

有關詳細信息,請參閱http://maven.apache.org/enforcer/enforcer-rules/bannedDependencies.html

現在您提到您的庫( com.test.lib )在沒有 servlet-api 2.5 的情況下似乎無法工作,這意味着它使用的代碼可能在 Servlet 2.5 和 3.1 之間被刪除:您唯一的做法是將您的庫升級為不依賴於所述代碼:

  • 第一個 servlet-api (2.5) 被加載
  • Tomcat 和 Spring Boot 針對更高版本編譯
  • Tomcat/Spring Boot 可能會嘗試使用更高版本中添加的方法
  • 您將遇到另一個錯誤,依此類推。

您可以訪問路徑:

~/.m2/repository/javax/servlet/servlet-api

並清除文件夾 serverlet。 例如:

rm -rf 2.5

最后你重新運行應用程序,一切正常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM