Jetty:将对象从main方法传递给servlet

时间:2016-09-10 01:38:59

标签: java servlets jetty

我有两个类Server(使用main方法,启动服务器)和StartPageServlet使用Servlet。

代码中最重要的部分是:

public class Server {
    public static void main(String[] args) throws Exception {
        // some code

        // I want to pass "anObject" to every Servlet.
        Object anObject = new Object();

        Server server = new Server(4000);
        ServletContextHandler context = 
            new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.addServlet(StartPageServlet.class, "/");
        // more code
}

StartPageServlet:

public class StartPageServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
            throws ServletException, IOException
    {
        // Here I want to access "anObject"
    }

我该怎么做?

3 个答案:

答案 0 :(得分:7)

嵌入式码头在这里真是太棒了。

您有几个常见的选择:

  1. 直接实例化servlet,使用构造函数或setter,然后通过ServletHolder将其交给Jetty(可以是任何值或对象类型)
  2. 将其添加到主文件中的ServletContext,然后通过应用程序中的ServletContext访问它(可以是任何值或对象类型)。
  3. 示例:

    package jetty;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.eclipse.jetty.server.Server;
    import org.eclipse.jetty.servlet.ServletContextHandler;
    import org.eclipse.jetty.servlet.ServletHolder;
    
    public class ObjectPassingExample
    {
        public static void main(String args[]) throws Exception
        {
            Server server = new Server(8080);
    
            ServletContextHandler context = new ServletContextHandler();
            context.setContextPath("/");
    
            // Option 1: Direct servlet instantiation and ServletHolder
            HelloServlet hello = new HelloServlet("everyone");
            ServletHolder helloHolder = new ServletHolder(hello);
            context.addServlet(helloHolder, "/hello/*");
    
            // Option 2: Using ServletContext attribute
            context.setAttribute("my.greeting", "you");
            context.addServlet(GreetingServlet.class, "/greetings/*");
    
            server.setHandler(context);
            server.start();
            server.join();
        }
    
        public static class HelloServlet extends HttpServlet
        {
            private final String hello;
    
            public HelloServlet(String greeting)
            {
                this.hello = greeting;
            }
    
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
            {
                resp.setContentType("text/plain");
                resp.getWriter().println("Hello " + this.hello);
            }
        }
    
        public static class GreetingServlet extends HttpServlet
        {
            private String greeting;
    
            @Override
            public void init() throws ServletException
            {
                this.greeting = (String) getServletContext().getAttribute("my.greeting");
            }
    
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
            {
                resp.setContentType("text/plain");
                resp.getWriter().println("Greetings to " + this.greeting);
            }
        }
    }
    

答案 1 :(得分:1)

的Singleton

您想将相同的单个实例传递给每个servlet吗?

使用Singleton pattern创建全局可用的单个实例。

在Java中最简单的方法是通过Enum。见Oracle Tutorial。另请参阅this article Effective Java:Programming Language Guide,Second Edition (ISBN 978-0-321-35668-0,2008),Dr. Joshua Bloch

所以不需要传递对象。每个servlet都可以通过枚举访问同一个实例。

每个网络应用

如果您想在Web应用程序首次启动时但在该Web应用程序中的任何servlet处理完任何请求之前做一些工作,请编写一个实现ServletContextListener接口的类。

使用@WebListener注释标记您的类,让您的Web容器自动实例化并调用。

答案 2 :(得分:0)

我有类似的情况,但需要与一个通过war部署的servlet共享一个单例,并在Jetty容器中进行热(重新)部署。由于servlet具有由部署者管理的生命周期和上下文,因此接受的答案并不是我所需要的。

我最终采用了暴力方法,将对象添加到server上下文中,该上下文在容器的生命周期中持续存在,然后从servlet中获取对象。这需要在父(系统)类加载器中加载对象的类,以便war webapp不会将其自己的类版本加载到其自己的类加载器中,这将导致演员异常,如here所述。< / p>

嵌入式Jetty服务器代码:

    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();

示例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("<h1>Hello from MyFineServlet</h1>");
        response.getWriter().println("Here's: " + myFineSingleton.toString());
    }
}

我的servlet构建文件(sbt)将my.package.MyFineClass依赖项放入“提供”范围,因此它不会打包到战争中,因为它已经被加载到Jetty服务器中。