Embedded Jetty: ServletContextListener, который регистрирует ServletRequestListener - PullRequest
0 голосов
/ 28 июня 2018

Я использую встроенный Jetty v9.4.x и имею следующую проблему:

Мой сервер регистрирует ServletContextListener:

    final WebAppContext context = new WebAppContext();

    // add listener
    context.addLifeCycleListener(new AbstractLifeCycle.AbstractLifeCycleListener() {
        @Override
        public void lifeCycleStarting(LifeCycle event) {

            ContextHandler.Context ctx = context.getServletContext();
            ctx.setExtendedListenerTypes(true);
            ctx.addListener("LISTENER_CLASS_NAME");
        }
    });

Мой слушатель вызван на Servet start. Однако мой слушатель контекста регистрирует ServletRequestListener внутри:

servletContext.addListener(foo.MyServletRequestListener.class);

И это не сработало со следующим исключением:

java.lang.UnsupportedOperationException
    at org.eclipse.jetty.servlet.ServletContextHandler$Context.addListener(ServletContextHandler.java:1506)

И когда я посмотрел, кажется, что контекст не включен (по крайней мере, этот флаг делает исключение для выброса).

Когда я запускаю одно и то же приложение с web.xml, все работает.

Как я могу позволить contextListener зарегистрировать ServletRequestListener?

1024 * редактировать * В коде причала есть примечание к объяснению: //toggle state of the dynamic API so that the listener cannot use it Это включено только для программно добавленных слушателей - с использованием API, а не web-xml. Как я могу сделать эту работу ???

1 Ответ

0 голосов
/ 28 июня 2018

В Jetty есть много разных типов слушателей, каждый со своим собственным набором методов добавления / удаления / получения / установки.

Ваш AbstractLifeCycleListener является слушателем Jetty LifeCycle, специально подающим заявку на внутренний запуск / запуск / останов / останов Jetty различных компонентов в Jetty.

Ваша реализация этого слушателя в вашем вопросе неполна и показывает отсутствие понимания LifeCycleEvent (вы не ищете какой-либо компонент, который нужно запустить), ваша реализация будет работать сотни раз. (один раз для каждого запускаемого компонента).

Использование ServletContext.addListener() имеет правила вокруг него, и они указывают, что его можно использовать только во время фазы инициализации ServletContext (не до, не после). Использование ServletContext.addListener() вне этой фазы должно привести к IllegalStateException (Javadoc даже так говорит)

ServletContext.addListener() также имеет ограниченный набор прослушивателей сервлетов, которые разрешено использовать с ним, намного меньше, чем количество типов прослушивателей, которые допустимы в веб-приложении или могут быть объявлены в WEB-INF/web.xml, или помечены аннотацией @WebListener.

Единственный способ использовать ServletContext.addListener() - из самого веб-приложения, используя код веб-приложения, из собственного загрузчика классов веб-приложения.

Места для использования ServletContext.addListener(): ...

Как видите, все эти местоположения определяются внутри самого веб-приложения.

Существование ServletContextHandler.addEventListener(EventListener) - это обходное решение, позволяющее добавлять Слушатель при построении ServletContextHandler, но не вызывать до тех пор, пока не произойдет фактическое событие.

Использование ServletContextHandler.addEventListener(EventListener) эквивалентно использованию WEB-INF/web.xml для объявления прослушивателя, которого вы хотите использовать.

Пример:

package jetty.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;


public class ServletContextListenerExample
{
    public static void main(String[] args) throws Exception
    {
        Server server = new Server(8080);

        ServletContextHandler context = new ServletContextHandler();
        context.setContextPath("/");

        MyContextListener contextListener = new MyContextListener();
        context.addEventListener(contextListener);

        // for context based static file serving and error handling
        context.addServlet(DefaultServlet.class, "/");

        HandlerList handlers = new HandlerList();
        handlers.addHandler(context);
        // for non-context error handling
        handlers.addHandler(new DefaultHandler());

        server.setHandler(handlers);
        server.start();
        server.join();
    }

    public static class MyContextListener implements ServletContextListener
    {
        @Override
        public void contextInitialized(ServletContextEvent sce)
        {
            System.err.printf("MyContextListener.contextInitialized(%s)%n", sce);
            sce.getServletContext().addListener(new MyRequestListener());
        }

        @Override
        public void contextDestroyed(ServletContextEvent sce)
        {
            System.err.printf("MyContextListener.contextDestroyed(%s)%n", sce);
        }
    }

    public static class MyRequestListener implements ServletRequestListener
    {
        @Override
        public void requestDestroyed(ServletRequestEvent sre)
        {
            System.err.printf("MyRequestListener.requestDestroyed(%s)%n", sre);
        }

        @Override
        public void requestInitialized(ServletRequestEvent sre)
        {
            System.err.printf("MyRequestListener.requestInitialized(%s)%n", sre);
        }
    }
}

Это зарегистрирует MyContextListener, который реализует оба javax.servlet.ServletContextListener. Когда начинается фаза инициализации ServletContext, запускается событие contextInitialized(). Реализация contextInitalized() затем использует переданный ServletContext для добавления нового MyRequestListener (который реализует javax.servlet.ServletRequestListener) через ServletContext.addListener() API.

Вывод вышеизложенного и нажатие http://localhost:8080/ из браузера ...

2018-06-28 09:42:06.352:INFO::main: Logging initialized @340ms to org.eclipse.jetty.util.log.StdErrLog
2018-06-28 09:42:06.475:INFO:oejs.Server:main: jetty-9.4.11.v20180605; built: 2018-06-05T18:24:03.829Z; git: d5fc0523cfa96bfebfbda19606cad384d772f04c; jvm 9.0.4+11
MyContextListener.contextInitialized(javax.servlet.ServletContextEvent[source=ServletContext@o.e.j.s.ServletContextHandler@12e61fe6{/,null,STARTING}])
2018-06-28 09:42:06.532:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@12e61fe6{/,null,AVAILABLE}
2018-06-28 09:42:06.695:INFO:oejs.AbstractConnector:main: Started ServerConnector@4567f35d{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2018-06-28 09:42:06.695:INFO:oejs.Server:main: Started @690ms
MyRequestListener.requestInitialized(javax.servlet.ServletRequestEvent[source=ServletContext@o.e.j.s.ServletContextHandler@12e61fe6{/,null,AVAILABLE}])
MyRequestListener.requestDestroyed(javax.servlet.ServletRequestEvent[source=ServletContext@o.e.j.s.ServletContextHandler@12e61fe6{/,null,AVAILABLE}])

Внимание. Имейте в виду, что на Jetty гораздо больше API-интерфейсов и типов прослушивателей, чем обсуждалось здесь, они существуют для других функций / компонентов с Jetty, которые не связаны с вашим вопросом. Не зацикливайтесь на них, пропустите их, игнорируйте их, и все будет в порядке.

...