Вопрос или проблема
Google App Engine: встроенный Jetty с Jersey, Java 17
У меня есть приложение на Java11 на Google App Engine, и оно использует “встроенный сервис” Jetty с Jersey в качестве REST-сервера.
В консоли Google Cloud были предупреждения о необходимости перейти с Java1 на Java17 до 31 октября 2024 года.
Так что я изменил свой код с Java11 на Java17 и развернул приложение. Предупреждения в консоли исчезли. Пока что все хорошо.
Тем не менее, моё приложение всё еще использует “встроенный сервис” Jetty с Jersey в качестве REST-сервера. Но что, если я захочу запустить Java-приложение, а из этого Java-приложения запустить сервер Jetty и при запуске этого экземпляра Jetty указать “jersey.config.server.provider.packages”?
Другими словами, я хотел бы отказаться от “встроенного сервиса” в части Jetty.
Я попробовал несколько комбинаций версий Jetty и Jersey, и наконец эти записи в pom-файле сработали, как есть, Java-приложение запустилось и, в свою очередь, запустило сервер Jetty на порту 8080.
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.2.3.v20140905</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.2.3.v20140905</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>9.2.3.v20140905</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>9.2.3.v20140905</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>2.35</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>2.35</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.35</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.35</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.35</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.27</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jetty-http</artifactId>
<version>2.35</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.35</version>
</dependency>
Это код в методе public static void main…
srvtCtxtHdlr = new ServletContextHandler(ServletContextHandler.SESSIONS);
srvtCtxtHdlr.setContextPath("/");
wappCtxt = new WebAppContext();
wappCtxt.setContextPath("/");
wappCtxt.setWar(args[0]);
jttySrvr = new Server(8080);
jttySrvr.setHandler(wappCtxt);
try {
jttySrvr.start();
jttySrvr.join();
}
catch(Exception e) {
logger.severe("Исключение: " + e.getMessage());
e.printStackTrace();
}
Проблема в том, что когда я перехожу по адресу http://localhost:8080
, я получаю ошибку 503. Лог сервера говорит…
java.lang.IllegalArgumentException: org.glassfish.hk2.api.ProxyCtl, на который ссылается метод, недоступен из загрузчика классов: org.jvnet.hk2.internal.DelegatingClassLoader
java.lang.IllegalArgumentException: При попытке разрешить зависимости com.myCompany.myProd.serverApp.fltr.ResponseFilter были обнаружены ошибки
Есть ли у вас предложения, где я мог бы ошибиться?
Также отмечу следующее (можно найти в списке примеров кода от GAE)
В этом списке содержится “встроенный сервис appengine-java11”, “appengine-java11” и “встроенный сервис appengine-java17”. Но в нём нет “appengine-java17”.
Узел “appengine-java11” описывает, как запустить экземпляр Jetty изнутри public static void main.
Так значит, это означает, что это (пока) невозможно сделать с Java17, и, следовательно, я действую вслепую??
Ответ или решение
Конечно! Давайте разберем вашу проблему с запуском Jetty с Jersey на Java 17 в Google App Engine и решим её.
Проблема
Вы столкнулись с ошибкой java.lang.IllegalArgumentException: org.glassfish.hk2.api.ProxyCtl referenced from a method is not visible from class loader: org.jvnet.hk2.internal.DelegatingClassLoader
, а также с ошибкой при разрешении зависимостей для ResponseFilter
. Это может быть связано с тем, что зависимости либо неправильно настроены, либо версии библиотек несовместимы друг с другом.
Решение
-
Проверка версий библиотек:
Убедитесь, что вы используете совместимые версии Jetty и Jersey. Попробуйте использовать более новые версии, поскольку вы используете Jetty 9.2.3, который довольно старый. Рекомендуется перейти на Jetty версии 9.4.x или 10.x. Также обновите зависимости Jersey до последней версии, например, 3.x.Вот ваши зависимости с обновлениями:
<dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> <version>9.4.44.v20210927</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-servlet</artifactId> <version>9.4.44.v20210927</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> <version>9.4.44.v20210927</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-webapp</artifactId> <version>9.4.44.v20210927</version> </dependency> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <version>2.1.6</version> </dependency> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-server</artifactId> <version>3.0.2</version> </dependency> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-jetty-http</artifactId> <version>3.0.2</version> </dependency>
-
Настройка Jetty и Jersey:
При создании сервера и контекстов убедитесь, что переменнаяjersey.config.server.provider.packages
правильно указана. Например:ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); servletContextHandler.setContextPath("/"); servletContextHandler.addServlet(new ServletHolder(new org.glassfish.jersey.servlet.ServletContainer()), "/*"); servletContextHandler.setInitParameter("jersey.config.server.provider.packages", "com.myCompany.myProd.serverApp.fltr"); Server server = new Server(8080); server.setHandler(servletContextHandler);
-
Проверка других конфигураций:
Убедитесь, что ваш классResponseFilter
и остальные классы Jersey находятся в правильном пакете и правильно аннотированы. Например, не забудьте использовать аннотации@Provider
и@Singleton
, если необходимо. -
Тестирование на локальной машине:
Перед деплоем на Google App Engine, запустите приложение локально и проверьте, доступен ли endpoint (например,http://localhost:8080
) и нет ли ошибок в логах. - Деплой на Google App Engine:
После того как все проверено и исправлено, сделайте деплой на Google App Engine. Помните, что установка Jetty и Jersey должна быть независимой от "упакованных сервисов" GAE.
Заключение
Если вы будете следовать данным рекомендациям, вероятно, проблема с зависимостями и ошибками в конфигурации Jetty и Jersey будет решена. Убедитесь, что используете последние версии библиотек и проверяйте логи для более точного понимания возникающих ошибок. Если же проблема сохранится, попробуйте обратиться к документации Jetty и Jersey для дополнительных подсказок.