У меня есть приложение REST, которое использует встроенный Jetty в качестве сервера. Большинство конечных точек должны быть общедоступными (и иметь соответствующую аутентификацию), но некоторые из них предназначены только для внутреннего использования. Я хотел бы избежать накладных расходов на аутентификацию на них и вместо этого использовать брандмауэр для ограничения доступа:
Внешние видимые конечные точки подаются на порт 10000, который внешний брандмауэр остается открытым. Внутренние видимые конечные точки подаются на порт 20000, который блокируется внешним брандмауэром.
Однако я не могу понять, как это сделать со встроенным Jetty. Я попытался создать два объекта Server
, один на порту 10000 с соответствующими зарегистрированными сервлетными обработчиками и один на порту 20000 с зарегистрированными обработчиками сервлетов. Однако работает только экземпляр сервера, который запускается вторым; запросы к конечным точкам, размещенным на первом запущенном в 404 ответах.
Документация Jetty рассказывает о том, как это сделать с помощью *. xml configuration, но не для внедренного экземпляра.
Любые мысли или идеи? Или есть лучший способ добиться внутренней/внешней изоляции конечных точек, которой я пользуюсь? Жесткое требование состоит в том, что как внутренние, так и внешние конечные точки должны "запускаться" в одной JVM.
Изменить
Оказывается, проблема связана с использованием расширения Guice и Guice-servlets (проблемы 618 и 635). Запуск двух встроенных экземпляров Jetty отлично работает, как описано в James Kingsbery answer ниже.
Guice использует фильтр (GuiceFilter), зарегистрированный в контексте сервера, для получения запросов, требующих инъекции зависимостей с запросами (DI), и для создания сервлетов и фильтров, для которых требуется DI. К сожалению, он использует статический объект для управления списком сервлетов и связанных с ним фильтров.
В типичной настройке guice-servlet.jar, содержащий GuiceFilter
, включается для каждого приложения и загружается другим загрузчиком классов для каждого приложения --- и все работает нормально. Нет так со встроенным Jetty, где по существу все загружается системным загрузчиком по умолчанию.
Решение проблемы Guice
Последний мастер (commit fbbb52dcc92e) Guice содержит обновленный GuiceFilter
с поддержкой динамической ссылки на объект FilterPipeline
(статический объект, вызывающий проблемы). К сожалению, конструктор для ввода экземпляра FilterPipeline
является закрытым пакетом. Таким образом, для его использования вам необходимо создать класс-оболочку в пакете com.google.inject.servlet
, который предоставляет этот конструктор:
package com.google.inject.servlet;
import com.google.inject.Inject;
public class NonStaticGuiceFilter extends GuiceFilter {
/**
* Do not use. Must inject a {@link FilterPipeline} via the constructor.
*/
@SuppressWarnings("unused")
private NonStaticGuiceFilter() {
throw new IllegalStateException();
}
@Inject
public NonStaticGuiceFilter(FilterPipeline filterPipeline) {
super(filterPipeline);
}
}
Чтобы использовать этот класс, создайте экземпляр с помощью инжектора с установленным ServletModule
и зарегистрируйте его с помощью Jetty Context
:
// Create the context handler
ServletContextHandler handler = new ServletContextHandler(myServer, "/context");
// Create the injector, registering your ServletModule
final Injector injector = Guice.createInjector(new MyServletModule());
// Add the Guice listener for this injector
handler.addEventListener(new GuiceServletContextListener() {
@Override
protected Injector getInjector() {
return injector;
}
});
// Filter all requests through Guice via NonStaticGuiceFilter.
// Guice will construct the FilterPipeline instance needed by
// NonStaticGuiceFilter.
handler.addFilter(
new FilterHolder(injector
.getInstance(NonStaticGuiceFilter.class)), "/*", null);