简体   繁体   English

在webapp-runner中运行的对Heroku Web-app的API调用最终失败,并出现google.common中的NoSuchMethodError和NoClassDefFoundError

[英]API calls to Heroku web-app running in webapp-runner eventually fail with NoSuchMethodError then NoClassDefFoundError in google.common

I am running a war on Heroku using webapp-runner . 我正在使用webapp-runner在Heroku上进行战争。 I deploy the application using the heroku-maven-plugin version 1.2 via the following command: mvn heroku:deploy-war . 我通过以下命令使用heroku-maven-plugin 1.2版部署该应用程序: mvn heroku:deploy-war Initially, the app works and all endpoints return valid responses. 最初,该应用正常运行,并且所有端点都返回有效响应。 However, if I allow the app to idle long enough for Heroku to put it to sleep and then invoke an endpoint which calls into guava I receive a NoSuchMethodError : 但是,如果我允许该应用程序空闲足够长的时间以让Heroku进入睡眠状态,然后调用一个调用番石榴的终结点,则会收到NoSuchMethodError

2017-09-23T19:19:45.388865+00:00 app[web.1]: SEVERE: Servlet.service() for servlet [jersey-serlvet] in context with path [] threw exception [org.glassfish.jersey.server.ContainerException: java.lang.NoSuchMethodError: com.google.common.base.CharMatcher.ascii()Lcom/google/common/base/CharMatcher;] with root cause
2017-09-23T19:19:45.388866+00:00 app[web.1]: java.lang.NoSuchMethodError: com.google.common.base.CharMatcher.ascii()Lcom/google/common/base/CharMatcher;
2017-09-23T19:19:45.388867+00:00 app[web.1]:    at com.google.common.io.BaseEncoding$Alphabet.<init>(BaseEncoding.java:453)
2017-09-23T19:19:45.388868+00:00 app[web.1]:    at com.google.common.io.BaseEncoding$Base64Encoding.<init>(BaseEncoding.java:892)
2017-09-23T19:19:45.388869+00:00 app[web.1]:    at com.google.common.io.BaseEncoding.<clinit>(BaseEncoding.java:317)
...application specific stack trace

All subsequent calls to the same API produce a NoClassDefFoundError at the same point 随后对同一API的所有调用均在同一点产生NoClassDefFoundError

2017-09-23T19:22:24.454901+00:00 app[web.1]: SEVERE: Servlet.service() for servlet [jersey-serlvet] in context with path [] threw exception [org.glassfish.jersey.server.ContainerException: java.lang.NoClassDefFoundError: Could not initialize class com.google.common.io.BaseEncoding] with root cause
2017-09-23T19:22:24.454903+00:00 app[web.1]: java.lang.NoClassDefFoundError: Could not initialize class com.google.common.io.BaseEncoding 
...application specific stack trace

These issues seem to suggest that the guava jar is present at compile time but not present at runtime. 这些问题似乎表明,番石榴罐在编译时存在,但在运行时不存在。 However, I logged-in to the web dyno and verified that the guava jar was included in my warfile 但是,我登录了Web dyno,并验证了我的warfile包含了番石榴罐。

my-mbp:TrickServer me$ heroku ps:exec
Establishing credentials... done
Connecting to web.1 on ⬢ myapp...
~ $ cd target/
~/target $ ls
MyApp.war  dependency  mvn-dependency-list.log  tomcat.52079
~/target $ jar -tf MyApp.war
...lots of dependencies...
WEB-INF/lib/google-oauth-client-1.20.0.jar
WEB-INF/lib/gson-2.2.4.jar
WEB-INF/lib/guava-23.0.jar      <---guava
WEB-INF/lib/guava-jdk5-13.0.jar
...lots more dependencies...

I am struggling to explain why the endpoints work immediately after the app is deployed but later produce these errors. 我正在努力解释为什么端点在部署应用程序后立即工作,但后来又产生这些错误。 To me this behavior seems to suggest that Heroku is potentially supplying a different classpath when my app wakes up from sleep than when it is initially run or that Heroku is moving/cleaning up the guava jarfile. 对我而言,这种行为似乎表明,当我的应用从睡眠状态唤醒时,Heroku可能会提供与最初运行时不同的类路径,或者Heroku正在移动/清理番石榴jarfile。

Contents of my Procfile : 我的Procfile内容:

web:    java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --port $PORT --expand-war target/MyApp.war

Java Processes runnning on my web dyno: 我的Web dyno上运行的Java进程:

~/target $ ps -ef | grep java
u30439       4     1  0 18:50 ?        00:00:44 java -Xmx300m -Xss512k -Dfile.encoding=UTF-8 -Duser.timezone=UTC -jar target/dependency/webapp-runner.jar --port 52079 target/MyApp.war
u30439      27     4  0 18:50 ?        00:00:00 bash --login -c java $JAVA_OPTS -jar target/dependency/webapp-runner.jar $WEBAPP_RUNNER_OPTS --port 52079 target/MyApp.war

Update 1 更新1

Since I am invoking my webapp with the --expand-war argument I also checked the jarfiles in the expanded directory to verify that guava was present. 由于我使用--expand-war参数调用webapp,因此我还检查了扩展目录中的jarfiles以验证是否存在番石榴。 It is: 它是:

~/target/tomcat.55320/webapps/expanded/WEB-INF/lib $ ls
...dependencies...
google-oauth-client-1.20.0.jar
gson-2.2.4.jar
guava-23.0.jar
guava-jdk5-13.0.jar
...more dependencies...

Update 2 更新2

I added the following logic to the problematic web service to printout the classpath and the resources on it: 我向有问题的Web服务中添加了以下逻辑,以打印出类路径及其上的资源:

logger.info("System Classpath: " + System.getProperty("java.class.path"));
logger.info("Runtime Classes...");
    ClassLoader cl = UserService.class.getClassLoader();
    URL[] urls = ((URLClassLoader) cl).getURLs();
    for(URL url: urls){
        logger.info(url.getFile());
    }

The next time the error occurred I examined the logs and to my surprise found that the guava jar was present on the runtime classpath! 下次发生错误时,我检查了日志,令我惊讶的是,运行时类路径中存在番石榴罐!

2017-09-24T12:07:40.843438+00:00 app[web.1]: [heroku-exec] ERROR: Could not connect to proxy:
2017-09-24T12:07:40.844145+00:00 app[web.1]: [heroku-exec] ERROR: Too many reconnect attempts. Waiting 30 seconds...
2017-09-24T12:07:52.671620+00:00 app[web.1]: Sep 24, 2017 12:07:52 PM org.myorg.server.web.services.MyService authenticate
2017-09-24T12:07:52.671631+00:00 app[web.1]: INFO: System Classpath: target/dependency/webapp-runner.jar
2017-09-24T12:07:52.671931+00:00 app[web.1]: Sep 24, 2017 12:07:52 PM org.myorg.server.web.services.MyService authenticate
2017-09-24T12:07:52.671932+00:00 app[web.1]: INFO: Runtime Classes...
2017-09-24T12:07:52.672277+00:00 app[web.1]: Sep 24, 2017 12:07:52 PM org.myorg.server.web.services.MyService authenticate
2017-09-24T12:07:52.672279+00:00 app[web.1]: INFO: /app/target/tomcat.28304/webapps/expanded/WEB-INF/classes/
....
2017-09-24T12:07:52.690304+00:00 app[web.1]: Sep 24, 2017 12:07:52 PM org.myorg.server.web.services.MyService authenticate
2017-09-24T12:07:52.690306+00:00 app[web.1]: INFO: /app/target/tomcat.28304/webapps/expanded/WEB-INF/lib/google-oauth-client-1.20.0.jar
2017-09-24T12:07:52.690501+00:00 app[web.1]: Sep 24, 2017 12:07:52 PM org.myorg.server.web.services.MyService authenticate
2017-09-24T12:07:52.690503+00:00 app[web.1]: INFO: /app/target/tomcat.28304/webapps/expanded/WEB-INF/lib/guava-23.0.jar <--- Guava!!!
....

What is going on here? 这里发生了什么? How do I debug this? 我该如何调试?

You probably have two versions of guava or its related jars on your classpath. 您的类路径中可能有两个版本的番石榴或其相关的jar。 See NoSuchMethodError exception when using com.google.common.base.Splitter 使用com.google.common.base.Splitter时,请参阅NoSuchMethodError异常

After some debugging, I discovered that my program had two different versions of Guava on the classpath ( guava-23.0.jar & guava-jdk5-13.0.jar ). 经过一些调试后,我发现我的程序在类路径上具有两个不同的Guava版本( guava-23.0.jarguava-jdk5-13.0.jar )。 The debugging tip suggested here was necessary but not sufficient for me to get to the bottom of this. 此处建议的调试技巧是必要的,但不足以使我深入了解此问题。

When working with ClassLoaders it's important to remember that the getClassLoader method defined in the .class object returns a reference to the ClassLoader that originally loaded the class. 使用ClassLoaders时,请务必记住, .class对象中定义的getClassLoader方法返回对最初加载该类的ClassLoader的引用。 To find the duplicate jar, it was crucial to invoke classLoader.getResource("/com/google/common/base/CharMatcher.class") on the same ClassLoader which loaded the class that later failed with the NoSuchMethodError . 要找到重复的jar,至关重要的是,在加载了后来因NoSuchMethodError失败的类的同一ClassLoader上调用classLoader.getResource("/com/google/common/base/CharMatcher.class")

For posterity, the specific dependency which caused the conflict was com.google.api-client . 为了后代,引起冲突的特定依赖项是com.google.api-client I resolved it by adding the following exclusion to the dependency in my pom.xml 我通过在pom.xml的依赖项中添加以下exclusion来解决它

<dependency>
    <groupId>com.google.api-client</groupId>
    <artifactId>google-api-client</artifactId>
    <version>1.22.0</version>
    <exclusions>
        <exclusion>
            <groupId>com.google.guava</groupId>
            <artifactId>guava-jdk5</artifactId>
        </exclusion>
    </exclusions>
</dependency>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java Web App在带有webapp-runner的Heroku上崩溃 - Java Web App Crashes on Heroku with webapp-runner 需要帮助Java Web App(webapp运行程序,tomcat)heroku(应用程序崩溃) - Need Help Java Web App (webapp-runner, tomcat) heroku (app crashed) Heroku Webapp运行程序-启用命名 - Heroku webapp-runner --enable-naming Heroku Webapp运行程序JNDI命名,资源不可用 - Heroku webapp-runner JNDI naming, resource not available webapp运行程序错误(NoInitialContextException) - webapp-runner error (NoInitialContextException) 使用&#39;webapp-runner&#39;运行Spring Boot应用后,它在“ INFO:Starting ProtocolHandler [“ http-nio-8080”]”行中停止 - After running Spring boot app with 'webapp-runner' it's stoping on a line “INFO: Starting ProtocolHandler [”http-nio-8080“]” 在heroku上部署的Web应用程序中使用Java Sound API - Using the Java Sound API in a web-app deployed on heroku 上下文路径与 webapp-runner 中的 Spring UrlTag 冲突? - Context path conflict with Spring UrlTag in webapp-runner? Spymemcached与hibernate-memcached和webapp-runner发生冲突 - Spymemcached conflict with hibernate-memcached and webapp-runner 运行Spring MVC Web应用程序时出现Java ClassNotFoundException - Java ClassNotFoundException while running spring mvc web-app
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM