Java 如何在启动期间使用参数初始化 Servlet?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1276082/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to initialize a Servlet during startup with parameters?
提问by Biju CD
Can we write an argument constructor in a Servlet? If yes, how can you call?
我们可以在 Servlet 中编写参数构造函数吗?如果有,怎么打电话?
采纳答案by dfa
Can we write an argument constructor in a Servlet?
我们可以在 Servlet 中编写参数构造函数吗?
Yes, you can but it is useless since the servlet container won't invoke it.
是的,您可以,但它没有用,因为 servlet 容器不会调用它。
The proper way to do it is to use the init()
method:
正确的做法是使用以下init()
方法:
@Override
public void init() throws ServletException {
String foo = getInitParameter("foo");
String bar = getServletContext().getInitParameter("bar");
// ...
}
In this example, getInitParameter("foo")
returns the value of the <init-param>
of the specific <servlet>
entry in web.xml
, and getServletContext().getInitParameter("bar")
returns the value of the independent <context-param>
in web.xml
.
在这个例子中,getInitParameter("foo")
返回的值<init-param>
的具体的<servlet>
在条目web.xml
,并且getServletContext().getInitParameter("bar")
返回独立的值<context-param>
中web.xml
。
回答by Tom
Constructors are objects managed by the application server.
构造函数是由应用服务器管理的对象。
For initialization, see the init()method.
对于初始化,请参见init()方法。
Update:
更新:
Can I use a constructor in my servlet?
A: A servlet is a normal Java class, so when there are no custom constructors, there is an implicit default constructor with no arguments. Servlet containers typically use the Class.newInstance() method to load servlets, so you must be careful to add an explicit default constructor if you add non-default constructors.
我可以在我的 servlet 中使用构造函数吗?
A: servlet 是一个普通的 Java 类,所以当没有自定义构造函数时,有一个没有参数的隐式默认构造函数。Servlet 容器通常使用 Class.newInstance() 方法来加载 servlet,因此如果添加非默认构造函数,则必须小心添加显式默认构造函数。
回答by ZZ Coder
You can't. Servlet is instantiated reflectively by container. If servlet spec have allowed arguments in constructor, you would have to have some complicated deployment descriptor like,
你不能。Servlet 由容器反射实例化。如果 servlet 规范在构造函数中允许参数,则必须有一些复杂的部署描述符,例如,
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>MyServlet</servlet-class>
<servlet-argument id="1" type="string">Test<servlet-argument>
<servlet-argument id="2" type="int">10</servlet-argument>
<load-on-startup>1</load-on-startup>
</servlet>
I guess no one wants that.
我想没有人想要那样。
回答by gawi
The problem can be state more generically:
问题可以更笼统地表述为:
"According to the servlets (2.3) specification, the servlets are instantiated by the servlet engine by invoking the no-arg constructor. How can I initialize a servlet properly given that correct initialization depends on the central/global/unique/application configuration?"
“根据 servlets (2.3) 规范,servlet 引擎通过调用 no-arg 构造函数来实例化 servlet。如果正确的初始化取决于中央/全局/唯一/应用程序配置,我该如何正确初始化 servlet?”
Actually, you can use serlvets with constructor and/or initialize them as you like. However, it requires a little bit of plumbing.
实际上,您可以将 serlvets 与构造函数一起使用和/或根据需要初始化它们。但是,它需要一点管道。
Assuming you have a servlet with a constructor having arguments:
假设您有一个带有参数的构造函数的 servlet:
package org.gawi.example.servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SampleServlet extends HttpServlet
{
private final String mMessage;
public SampleServlet(String message)
{
mMessage = message;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/plain");
response.getWriter().write(mMessage);
}
}
The first thing you need is a unique servlet whithin your application, let's call it InitializationServlet, to create all the required instances. Those instances must then be exported in the servlet context to be retrieve by another servlet (explained later). The InitializationServlet may look like this:
您需要的第一件事是在您的应用程序中使用唯一的 servlet,我们称之为 InitializationServlet,以创建所有必需的实例。然后必须将这些实例导出到 servlet 上下文中以供另一个 servlet 检索(稍后解释)。InitializationServlet 可能如下所示:
package org.gawi.example.servlets;
import javax.servlet.*;
import javax.servlet.http.*;
public class InitializationServlet extends HttpServlet
{
public void init() throws ServletException
{
SampleServlet servletA = new SampleServlet("this is servlet A");
SampleServlet servletB = new SampleServlet("this is servlet B");
SampleServlet servletC = new SampleServlet("this is servlet C");
getServletContext().setAttribute("servletA", servletA);
getServletContext().setAttribute("servletB", servletB);
getServletContext().setAttribute("servletC", servletC);
}
}
You see that only the init()
method has been provided. This servlet is not servicing any HTTP request. Its only purpose is to store the servlet in the ServletContext. Note that you could have also use this servlet to load your application configuration. So this can act as the web-application entry point, like the main(String[] args)
method of a program. This might remind you of the ContextLoaderServlet of SpringSource.
你看到只提供了init()
方法。此 servlet 不为任何 HTTP 请求提供服务。它的唯一目的是将 servlet 存储在 ServletContext 中。请注意,您还可以使用此 servlet 加载应用程序配置。所以这可以作为 Web 应用程序的入口点,就像main(String[] args)
程序的方法一样。这可能会让您想起 SpringSource 的 ContextLoaderServlet。
The last piece is the DelegateServlet that will effectively be instantiated by the servlet container, only this servlet will forward all the pertinent method calls to the wrapped servlet instance:
最后一部分是 DelegateServlet,它将被 servlet 容器有效地实例化,只有这个 servlet 会将所有相关的方法调用转发到包装的 servlet 实例:
package org.gawi.example.servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DelegateHttpServlet extends HttpServlet
{
private static final String SERVLET_CONTEXT_KEY_INIT_PARAMETER = "servletContextKey";
private HttpServlet mServlet;
public void init(ServletConfig servletConfig) throws ServletException
{
super.init(servletConfig);
locateServlet(servletConfig);
mServlet.init(servletConfig);
}
private void locateServlet(ServletConfig servletConfig) throws ServletException
{
String servletContextAttributeName = servletConfig.getInitParameter(SERVLET_CONTEXT_KEY_INIT_PARAMETER);
if (servletContextAttributeName == null)
{
throw new ServletException("Unable to find init parameter '" + SERVLET_CONTEXT_KEY_INIT_PARAMETER + "'");
}
Object object = servletConfig.getServletContext().getAttribute(servletContextAttributeName);
if (object == null)
{
throw new ServletException("Unable to find " + servletContextAttributeName + " in servlet context.");
}
if (!(object instanceof HttpServlet))
{
throw new ServletException("Object is not an instance of"
+ HttpServlet.class.getName()
+ ". Class is "
+ object.getClass().getName()
+ ".");
}
mServlet = (HttpServlet) object;
}
public void destroy()
{
mServlet.destroy();
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
{
mServlet.service(req, res);
}
}
During its initialization, the DelegateServlet will look-up the target servlet in the servlet context using the servletContextKey
servlet initial argument.
在初始化期间,DelegateServlet 将使用servletContextKey
servlet 初始参数在 servlet 上下文中查找目标 servlet 。
The web.xml for such an application might look like that:
此类应用程序的 web.xml 可能如下所示:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Example</display-name>
<description>Example web showing handling of servlets w/ constructors.</description>
<servlet>
<servlet-name>Initialization</servlet-name>
<servlet-class>org.gawi.example.servlets.InitializationServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>A</servlet-name>
<servlet-class>org.gawi.example.servlets.DelegateHttpServlet</servlet-class>
<init-param>
<param-name>servletContextKey</param-name>
<param-value>servletA</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>B</servlet-name>
<servlet-class>org.gawi.example.servlets.DelegateHttpServlet</servlet-class>
<init-param>
<param-name>servletContextKey</param-name>
<param-value>servletB</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet>
<servlet-name>C</servlet-name>
<servlet-class>org.gawi.example.servlets.DelegateHttpServlet</servlet-class>
<init-param>
<param-name>servletContextKey</param-name>
<param-value>servletC</param-value>
</init-param>
<load-on-startup>4</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>A</servlet-name>
<url-pattern>/servlet/a</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>B</servlet-name>
<url-pattern>/servlet/b</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>C</servlet-name>
<url-pattern>/servlet/c</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>5</session-timeout>
</session-config>
</web-app>
Be sure to load the InitializationServlet first, using a low <load-on-startup>
value.
确保首先加载 InitializationServlet,使用较低的<load-on-startup>
值。
The benefit of this approach is that HttpServlet
objects can be handled like any other regular Java object or bean. Hence, it provides a better control over initialization: no more tricky stuff to do in the init()
method, nor messy servlet init-arg handling.
这种方法的好处是HttpServlet
可以像处理任何其他常规 Java 对象或 bean 一样处理对象。因此,它提供了对初始化的更好控制:在init()
方法中没有更多棘手的事情要做,也没有凌乱的 servlet init-arg 处理。