Embedded Jetty - Adding Context after starting Jet

2019-07-24 00:22发布

问题:

Is it right to start a jetty instance with no context specified and no context handler, then keep adding context to it once the server has started. Although I was able to do this using mutable HandlerCollection and the logs says the Server and the Contexts are started and available, I am not able to access it with the URL. Or should we add at least one root context and contexthandler to the server while starting it?

I did something similar to the example suggested in below link. Jetty 9 (embedded): Adding handlers during runtime

My jetty version is 9.3.7.v20160115

回答1:

the addition of handlers to a running server is a common pattern but the documentation is not clear at all (all the examples in the "embedding jetty" tutorial start the server after the configuration.) AFAIK people is following these approaches:

1) using the HandlerCollection(boolean mutableWhenRunning) ctor to add/remove handlers

2) add and start the handlers explicitly

I observed that #2 was not needed in Jetty 9.1.4, but it is on Jetty 9.2.14 and afterward (BTW these version numbers were picked by Maven as Jersey dependencies which is totally unrelated to this issue.) For example:

    // after server creation ...
    ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
            jettyServer.setHandler(contextHandlerCollection);
    jettyServer.start();
    // ...
    ServletContextHandler newSCH= new ServletContextHandler(ServletContextHandler.SESSIONS);
        newSCH.setResourceBase(System.getProperty("java.io.tmpdir"));
        newSCH.setContextPath("/servlets");
        ServletHolder newHolder = new SwServletHolder(servlet);
        newSCH.addServlet(newHolder, "/*");
        contextHandlerCollection.addHandler(newSCH);
        try {
                newSCH.start(); // needed from about 9.2
        } catch (Exception e) {
                logger.info("Exception starting ServletContextHandler for Jetty", e);
        }

In order to add a SOAP context this is a code that "used to work" on 9.1.4 (on 9.2.14 it reports 404):

import java.lang.reflect.Method;
import java.net.InetSocketAddress;

import javax.jws.WebService;
import javax.xml.ws.Endpoint;

import org.eclipse.jetty.http.spi.JettyHttpServerProvider;
import org.eclipse.jetty.http.spi.HttpSpiContextHandler;
import org.eclipse.jetty.http.spi.JettyHttpContext;
import org.eclipse.jetty.http.spi.JettyHttpServer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;

import com.sun.net.httpserver.HttpContext;

public class JettyJaxWs {

    public static void main(String[] args) throws Exception {
        Server server = new Server(7777);
        ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
        server.setHandler(contextHandlerCollection);
        server.start();
        HttpContext context = buildOrig(server, "/ws");
        MyWebService ws = new MyWebService();
        Endpoint endpoint = Endpoint.create(ws);
        endpoint.publish(context);
        // access wsdl on http://localhost:7777/ws/MyWebService?wsdl
    }

    @WebService
    public static class MyWebService {

        public String hello(String s) {
            return "hi " + s;
        }
    }

    public static HttpContext buildOrig(Server server, String contextString) throws Exception {
        JettyHttpServerProvider.setServer(server);
        return new JettyHttpServerProvider().createHttpServer(new InetSocketAddress(7777), 5).createContext(contextString);
    }

Later, I had to do this for the last method (not sure if there is a better way):

public static HttpContext buildNew(Server server, String contextString) {
        JettyHttpServer jettyHttpServer = new JettyHttpServer(server, true);
        JettyHttpContext ctx = (JettyHttpContext) jettyHttpServer.createContext(contextString);
        try {
            Method method = JettyHttpContext.class.getDeclaredMethod("getJettyContextHandler");
            method.setAccessible(true);
            HttpSpiContextHandler contextHandler = (HttpSpiContextHandler) method.invoke(ctx);
            contextHandler.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ctx;
    }