Tomcat 在使用 WebappRunner 时卡在“Starting ProtocolHandler”

Posted

技术标签:

【中文标题】Tomcat 在使用 WebappRunner 时卡在“Starting ProtocolHandler”【英文标题】:Tomcat stuck at "Starting ProtocolHandler" when using WebappRunner 【发布时间】:2017-10-05 05:00:04 【问题描述】:

我有一个 Spring Boot 项目,我正在尝试使用 WebappRunner 和 Tomcat 运行该项目。当我运行它时,它挂在“Starting ProtocolHandler”处。

重要提示:当我在没有 Webapp-runner(Heroku 声明是必需的)的情况下运行我的应用程序时,它可以完美运行,连接到数据库并响应请求。当我使用 webapp-runner 运行它时,tomcat 如下所示挂起。

4:41:44 PM web.1 |  Expanding NewsItemWeb-0.0.1-SNAPSHOT.war into .../target/tomcat.5000/webapps/expanded
4:41:44 PM web.1 |  Adding Context  for .../target/tomcat.5000/webapps/expanded
4:41:45 PM web.1 |  May 06, 2017 4:41:45 PM org.apache.coyote.AbstractProtocol init
4:41:45 PM web.1 |  INFO: Initializing ProtocolHandler ["http-nio-5000"]
4:41:45 PM web.1 |  May 06, 2017 4:41:45 PM org.apache.tomcat.util.net.NioselectorPool getSharedSelector
4:41:45 PM web.1 |  INFO: Using a shared selector for servlet write/read
4:41:45 PM web.1 |  May 06, 2017 4:41:45 PM org.apache.catalina.core.StandardService startInternal
4:41:45 PM web.1 |  INFO: Starting service Tomcat
4:41:45 PM web.1 |  May 06, 2017 4:41:45 PM org.apache.catalina.core.StandardEngine startInternal
4:41:45 PM web.1 |  INFO: Starting Servlet Engine: Apache Tomcat/8.5.11
4:41:45 PM web.1 |  May 06, 2017 4:41:45 PM org.apache.catalina.startup.ContextConfig getDefaultWebXmlFragment
4:41:45 PM web.1 |  INFO: No global web.xml found
4:41:48 PM web.1 |  May 06, 2017 4:41:48 PM org.apache.jasper.servlet.TldScanner scanJars
4:41:48 PM web.1 |  INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
4:41:48 PM web.1 |  May 06, 2017 4:41:48 PM org.apache.catalina.core.ApplicationContext log
4:41:48 PM web.1 |  INFO: 1 Spring WebApplicationInitializers detected on classpath
4:41:48 PM web.1 |  May 06, 2017 4:41:48 PM org.apache.coyote.AbstractProtocol start
4:41:48 PM web.1 |  INFO: Starting ProtocolHandler [http-nio-5000]

当我的 .war 应用程序仍在运行时在 pid 上运行 jstack 时,这是堆栈跟踪:

"Attach Listener" #20 daemon prio=9 os_prio=31 tid=0x00007f8e67811000 nid=0x5b07 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"http-nio-5000-AsyncTimeout" #19 daemon prio=5 os_prio=31 tid=0x00007f8e618bf800 nid=0x6503 waiting on condition [0x000070000414f000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at org.apache.coyote.AbstractProtocol$AsyncTimeout.run(AbstractProtocol.java:1138)
    at java.lang.Thread.run(Thread.java:745)

"http-nio-5000-Acceptor-0" #18 daemon prio=5 os_prio=31 tid=0x00007f8e61d77800 nid=0x6303 runnable [0x000070000404c000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
    at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)
    at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)
    - locked <0x00000006c155db50> (a java.lang.Object)
    at org.apache.tomcat.util.net.NioEndpoint$Acceptor.run(NioEndpoint.java:443)
    at java.lang.Thread.run(Thread.java:745)

"http-nio-5000-ClientPoller-1" #17 daemon prio=5 os_prio=31 tid=0x00007f8e65072800 nid=0x6103 runnable [0x0000700003f49000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.KQueueArrayWrapper.kevent0(Native Method)
    at sun.nio.ch.KQueueArrayWrapper.poll(KQueueArrayWrapper.java:198)
    at sun.nio.ch.KQueueSelectorImpl.doSelect(KQueueSelectorImpl.java:117)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    - locked <0x000000076e2078a8> (a sun.nio.ch.Util$3)
    - locked <0x000000076e207898> (a java.util.Collections$UnmodifiableSet)
    - locked <0x000000076e207778> (a sun.nio.ch.KQueueSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:775)
    at java.lang.Thread.run(Thread.java:745)

"http-nio-5000-ClientPoller-0" #16 daemon prio=5 os_prio=31 tid=0x00007f8e625d9800 nid=0x5f03 runnable [0x0000700003e46000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.KQueueArrayWrapper.kevent0(Native Method)
    at sun.nio.ch.KQueueArrayWrapper.poll(KQueueArrayWrapper.java:198)
    at sun.nio.ch.KQueueSelectorImpl.doSelect(KQueueSelectorImpl.java:117)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    - locked <0x000000076e207138> (a sun.nio.ch.Util$3)
    - locked <0x000000076e207128> (a java.util.Collections$UnmodifiableSet)
    - locked <0x000000076e207008> (a sun.nio.ch.KQueueSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:775)
    at java.lang.Thread.run(Thread.java:745)

"ContainerBackgroundProcessor[StandardEngine[Tomcat]]" #15 daemon prio=5 os_prio=31 tid=0x00007f8e6268d000 nid=0x5d03 waiting on condition [0x0000700003d43000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1355)
    at java.lang.Thread.run(Thread.java:745)

"NioBlockingSelector.BlockPoller-1" #12 daemon prio=5 os_prio=31 tid=0x00007f8e619cd000 nid=0x5703 runnable [0x0000700003a3a000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.KQueueArrayWrapper.kevent0(Native Method)
    at sun.nio.ch.KQueueArrayWrapper.poll(KQueueArrayWrapper.java:198)
    at sun.nio.ch.KQueueSelectorImpl.doSelect(KQueueSelectorImpl.java:117)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    - locked <0x00000006c1540de0> (a sun.nio.ch.Util$3)
    - locked <0x00000006c1540df0> (a java.util.Collections$UnmodifiableSet)
    - locked <0x00000006c1540d90> (a sun.nio.ch.KQueueSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    at org.apache.tomcat.util.net.NioBlockingSelector$BlockPoller.run(NioBlockingSelector.java:339)

"Service Thread" #9 daemon prio=9 os_prio=31 tid=0x00007f8e6081a000 nid=0x5303 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #8 daemon prio=9 os_prio=31 tid=0x00007f8e60808800 nid=0x5103 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #7 daemon prio=9 os_prio=31 tid=0x00007f8e6103a800 nid=0x4f03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #6 daemon prio=9 os_prio=31 tid=0x00007f8e61852000 nid=0x4d03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=31 tid=0x00007f8e6200c000 nid=0x4b03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007f8e62008800 nid=0x4903 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007f8e6106c800 nid=0x3903 in Object.wait() [0x0000700003222000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000006c1515098> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x00000006c1515098> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007f8e6106a000 nid=0x3703 in Object.wait() [0x000070000311f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000006c15152c8> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x00000006c15152c8> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 prio=5 os_prio=31 tid=0x00007f8e61007000 nid=0x1c03 waiting on condition [0x0000700002701000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at org.apache.catalina.core.StandardServer.await(StandardServer.java:427)
    at webapp.runner.launch.Main.main(Main.java:288)

"VM Thread" os_prio=31 tid=0x00007f8e61065800 nid=0x3503 runnable 

"GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007f8e61013000 nid=0x2503 runnable 

"GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007f8e61013800 nid=0x2703 runnable 

"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007f8e61014800 nid=0x2903 runnable 

"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007f8e61015000 nid=0x2b03 runnable 

"GC task thread#4 (ParallelGC)" os_prio=31 tid=0x00007f8e61015800 nid=0x2d03 runnable 

"GC task thread#5 (ParallelGC)" os_prio=31 tid=0x00007f8e61801000 nid=0x2f03 runnable 

"GC task thread#6 (ParallelGC)" os_prio=31 tid=0x00007f8e61802000 nid=0x3103 runnable 

"GC task thread#7 (ParallelGC)" os_prio=31 tid=0x00007f8e61802800 nid=0x3303 runnable 

"VM Periodic Task Thread" os_prio=31 tid=0x00007f8e6081b000 nid=0x5503 waiting on condition 

【问题讨论】:

【参考方案1】:

不需要将 Webapp Runner 与 Spring Boot 一起使用,因为它包含嵌入式 Tomcat 服务器。

另外,需要以 Heroku 可以动态设置的方式为 Tomcat 指定端口。

所以Procfile 应该是这样的:

web: java $JAVA_OPTS -Dserver.port=$PORT -jar target/*.jar

【讨论】:

以上是关于Tomcat 在使用 WebappRunner 时卡在“Starting ProtocolHandler”的主要内容,如果未能解决你的问题,请参考以下文章

如何让 Tomcat 在启动时预编译 JSP?

在后台使用 Netty 与 Tomcat 时 Spring webFlux 的差异

Tomcat服务器维护时的几点建议

在 XAMPP 中配置 tomcat 时出错

Apache Tomcat 在使用 websocket 时返回 404

为啥在jsp更改时tomcat不需要重启