Конфликт между игрой! Framework 2.5 и gRPC 0,13
Play 2.5.0 использует Netty 4.0.33, а gRPC требует Netty 4.1.0 (для поддержки http2), что вызывает следующее исключение:
[error] p.c.s.n.PlayRequestHandler - Exception caught in Netty
java.lang.AbstractMethodError: null
at io.netty.util.ReferenceCountUtil.touch(ReferenceCountUtil.java:73)
at io.netty.channel.DefaultChannelPipeline.touch(DefaultChannelPipeline.java:84)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:154)
at com.typesafe.netty.http.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:131)
at com.typesafe.netty.http.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:96)
at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
at io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:154)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
[error] p.c.s.n.PlayRequestHandler - Exception caught in Netty
java.util.NoSuchElementException: http-handler-body-publisher
at io.netty.channel.DefaultChannelPipeline.getContextOrDie(DefaultChannelPipeline.java:1050)
at io.netty.channel.DefaultChannelPipeline.remove(DefaultChannelPipeline.java:379)
at com.typesafe.netty.http.HttpStreamsHandler.handleReadHttpContent(HttpStreamsHandler.java:191)
at com.typesafe.netty.http.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:167)
at com.typesafe.netty.http.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:96)
at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
at io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:154)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
После того, как я удаляю все коды gRPC, он снова работает.
Есть ли какое-нибудь быстрое решение, которое я могу попробовать сейчас? Спасибо!
3 ответа
Редактировать:
Play 2.6.0 был выпущен и использует Netty 4.1.
ТЛ; др
Play 2.5.0 и gRPC несовместимы из-за двоичной несовместимости между Netty 4 и Netty 4.1.
Вот почему он не работает с Play 2.5.0, но работает с Play 2.4.0:
Play 2.5.0 использует версию Netty 4.0.33.Final
, который объявлен (транзитивно через netty-реактивный поток версии 1.0.2) следующим образом:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.0.33.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>4.0.33.Final</version>
</dependency>
Версия 4.0.33.Final
выселено версией 4.0.34.Final
который был транзитивно добавлен async-http-client, и это зависимости netty, используемые Play 2.5.0:
io.netty:netty-buffer:4.0.34.Final
io.netty:netty-codec-http:4.0.34.Final
io.netty:netty-codec:4.0.34.Final
io.netty:netty-common:4.0.34.Final
io.netty:netty-handler:4.0.34.Final
io.netty:netty-transport:4.0.34.Final
Для игры 2.4.6 с другой стороны требуется только следующая зависимость от netty:
io.netty:netty:3.8.0.Final
Таким образом, в то время как Play 2.5.0 зависит от множества небольших пакетов нетти, Play 2.4.6 зависит только от одного пакета нетти. Это связано с тем, что Netty 4 изменила структуру проекта, чтобы разделить проект на несколько подпроектов, чтобы пользователь мог добавить только необходимые функции из Netty. И что еще более важно, "имя пакета Netty было изменено с org.jboss.netty на io.netty".
Почему эти изменения важны здесь:
- Нет конфликта зависимостей между gRPC с 2.4.6, потому что gRPC не требует зависимости
io.netty:netty
Даже транзитивно. Из-за этого нет выселения. - На уровне классов нет конфликта, потому что у классов были разные имена пакетов (
org.jboss.netty
а такжеio.netty
), а затем иметь разные полные имена. Они рассматриваются как разные классы.
Существуют конфликты с Play 2.5.0, потому что Netty 4 и Netty 4.1 имеют одинаковые зависимости (тогда 4.0.34 вытесняется с помощью 4.1) и потому что - поскольку теперь у нас одинаковые полные квалифицированные имена классов между этими двумя версиями, возникает несовместимость двоичных файлов,
Это длинное объяснение того, что сейчас нет способа заставить gRPC и Play 2.5.0 работать вместе с Netty. Даже если вы решите использовать серверную часть Akka HTTP, существует вероятность конфликта с Play WS.
Вы также можете использовать maven-shade-plugin для перемещения имен пакетов netty, чтобы они не конфликтовали с более ранней версией.
Посмотрите библиотеку ядра couchbase jvm для примера https://github.com/couchbase/couchbase-jvm-core.
Я также сталкивался с этим в Play с использованием Java. Используете ли вы клиентский или серверный интерфейс gRPC с сервером Play? Если вы просто используете только клиента, вы можете преодолеть это, используя версию клиента OKHTTP вместо той, которая основана на Netty.
https://mvnrepository.com/artifact/io.grpc/grpc-okhttp
Если вы используете сервер, я думаю, вам не повезло. Вы можете попытаться исключить Netty из gRPC и надеяться, что версии Play достаточно. Просто добавьте excludeAll ExclusionRule(organization = "io.netty") в импорт gRPC.
Вот тема в списке рассылки play по этой теме, но пока нет никаких изменений в теме: https://groups.google.com/forum/