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.

Говоря, я не уверен, что это правильный способ сделать это.