Jetty: Pass object from main method to servlet

前端 未结 3 1910
臣服心动
臣服心动 2020-12-18 13:38

I have two classes Server (with the main method, starting the server) and StartPageServlet with a Servlet.

The most important part of the c

3条回答
  •  無奈伤痛
    2020-12-18 14:13

    I had a similar situation but needed to share a singleton with a servlet deployed via war with hot (re)deploy in a Jetty container. The accepted answer wasn't quite what I needed in my case since the servlet has a lifecycle and context managed by a deployer.

    I ended up with a brute-force approach, adding the object to the server context, which persists for the life of the container, and then fetching the object from within the servlet(s). This required loading the class of the object in a parent (system) classloader so that the war webapp doesn't load its own version of the class into its own classloader, which would cause a cast exception as explained here.

    Embedded Jetty server code:

        Server server = new Server(8090);
    
        // Add all classes related to the object(s) you want to share here.
        WebAppContext.addSystemClasses(server, "my.package.MyFineClass", ...);
    
        // Handler config
        ContextHandlerCollection contexts = new ContextHandlerCollection();
        HandlerCollection handlers = new HandlerCollection();
        handlers.setHandlers(new Handler[] { contexts });
        server.setHandler(handlers);
    
        // Deployer config (hot deploy)
        DeploymentManager deployer = new DeploymentManager();
        DebugListener debug = new DebugListener(System.err,true,true,true);
        server.addBean(debug);
        deployer.addLifeCycleBinding(new DebugListenerBinding(debug));
        deployer.setContexts(contexts);
        deployer.setContextAttribute(
                "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
                ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$");
    
        WebAppProvider webapp_provider = new WebAppProvider();
        webapp_provider.setMonitoredDirName("/.../webapps");
        webapp_provider.setScanInterval(1);
        webapp_provider.setExtractWars(true);
        webapp_provider.setConfigurationManager(new PropertiesConfigurationManager());
    
        deployer.addAppProvider(webapp_provider);
        server.addBean(deployer);
    
        // Other config...
    
        // Tuck any objects/data you want into the root server object.
        server.setAttribute("my.package.MyFineClass", myFineSingleton);
    
        server.start();
        server.join();
    

    Example servlet:

    public class MyFineServlet extends HttpServlet
    {
        MyFineClass myFineSingleton;
    
        @Override
        public void init() throws ServletException
        {
            // Sneak access to the root server object (non-portable).
            // Not possible to cast this to `Server` because of classloader restrictions in Jetty.
            Object server = request.getAttribute("org.eclipse.jetty.server.Server");
    
            // Because we cannot cast to `Server`, use reflection to access the object we tucked away there.
            try {
                myFineSingleton = (MyFineClass) server.getClass().getMethod("getAttribute", String.class).invoke(server, "my.package.MyFineClass");
            } catch (Exception ex) {
                throw new ServletException("Unable to reflect MyFineClass instance via Jetty Server", ex);
            }
        }
    
        @Override
        protected void doGet( HttpServletRequest request,
                HttpServletResponse response ) throws ServletException, IOException
        {
            response.setContentType("text/html");
            response.setStatus(HttpServletResponse.SC_OK);
            response.getWriter().println("

    Hello from MyFineServlet

    "); response.getWriter().println("Here's: " + myFineSingleton.toString()); } }

    My build file for the servlet (sbt) placed the my.package.MyFineClass dependency into the "provided" scope so it wouldn't get packaged into the war as it will already be loaded into the Jetty server.

提交回复
热议问题