我有两个类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"
}
我该怎么做?
答案 0 :(得分:7)
嵌入式码头在这里真是太棒了。
您有几个常见的选择:
ServletHolder
将其交给Jetty(可以是任何值或对象类型)ServletContext
,然后通过应用程序中的ServletContext
访问它(可以是任何值或对象类型)。示例:
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)
您想将相同的单个实例传递给每个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服务器中。