Embedded Jetty: разные порты для видимых внутри и снаружи конечных точек?
У меня есть приложение 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);
Ответы
Ответ 1
Мой обычный костыль, начавшийся со встроенным проектом Jetty, - это архетип Wicket maven. Вот класс, основанный на этом архетипе, который должен сделать в значительной степени то, что вам нужно:
package net.kingsbery;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.bio.SocketConnector;
import org.mortbay.jetty.webapp.WebAppContext;
public class Start {
public static void main(String[] args) throws Exception {
Server server = new Server();
SocketConnector connector = new SocketConnector();
// Set some timeout options to make debugging easier.
connector.setMaxIdleTime(1000 * 60 * 60);
connector.setSoLingerTime(-1);
connector.setPort(10080);
server.setConnectors(new Connector[] { connector });
WebAppContext bb = new WebAppContext();
bb.setServer(server);
bb.setContextPath("/");
bb.setWar("src/main/secret-webapp");
server.addHandler(bb);
Server server2 = new Server();
SocketConnector connector2 = new SocketConnector();
// Set some timeout options to make debugging easier.
connector2.setMaxIdleTime(1000 * 60 * 60);
connector2.setSoLingerTime(-1);
connector2.setPort(20000);
server2.setConnectors(new Connector[] { connector });
WebAppContext bb2 = new WebAppContext();
bb2.setServer(server);
bb2.setContextPath("/");
bb2.setWar("src/main/webapp");
server.addHandler(bb);
server2.addHandler(bb2);
try {
server.start();
server2.start();
} catch (Exception e) {
e.printStackTrace();
System.exit(100);
}
}
}
Если вы используете какой-либо другой обработчик, замените его обработчиком webapp.
Говоря, я не уверен, что это правильный способ сделать это.