2

正如我们所知init(),构造函数的工作与destroy()servlet 的 finalize 方法相同,并且finalize()Servlet.

现在的问题是:如果finalize()在 Servlet 中定义了构造函数和方法,它们会被调用吗?是不是我们将在构造函数中初始化的任何东西都会被 in 覆盖init(),或者构造函数根本不会被调用?

4

3 回答 3

5

小修正先

让我们先回顾一些假设。更多细节在帖子的其余部分。

我们知道 init() 完成了构造函数的工作

不,它没有。它与它有很大不同:

  • 声明一个throws ServletException
  • 声明一个ServletConfig参数,* 它调用它的父构造函数(因为 Java 默认调用父的无参数构造函数)。

对于最后一点,在您的一般情况下,Servlet不做HttpServlet任何事情都没有关系,但是如果使用这些抽象类的扩展,那么您不应该假设它们也没有弄乱构造函数并做事情在他们中。虽然您可以选择init()不调用 paren't init(),但始终会调用父级的无参数构造函数。

[...] 和 destroy() 相同的 finalize 方法

不,它没有。

在 servlet 中使用构造函数和 finalize 方法并没有什么坏处

如果您的构造函数和终结器中发生异常可能会造成伤害,无论如何我肯定不建议使用它们,但建议坚持init()destroy()遵守规范。规范中未定义自定义构造函数和析构函数引发的异常的异常处理规则,因此这些将是未定义的行为/特定于容器。

他们会被召唤吗?

你试过了吗?怎么了?

(是的:将为每个新线程实例调用无参数构造函数,并且将调用终结器......只要 GC 愿意。

是不是我们将在构造函数中初始化的任何东西都将被 init() 中的内容覆盖,或者根本不会调用构造函数?

init()不是构造函数。

您可能能够覆盖在init()构造函数中初始化的某些内容(例如成员变量),或撤消/还原您在构造函数中执行的操作。看不出这有用的原因,但你可能可以。但如果这就是你的意思,它们不会相互抵消。

为什么还要这样做?

我在这里问自己的问题更多:

  • 为什么你觉得你需要一个自定义构造函数?
  • 为什么你觉得你需要一个终结器?(或者一般来说,实际上?)

小服务程序生命周期

摘自 Java EE 6 教程的Servlet 生命周期部分:

  1. 如果 servlet 的实例不存在,则 Web 容器
    • 加载 servlet 类。
    • 创建 servlet 类的实例。
    • 通过调用 init 方法初始化 servlet 实例。创建和初始化 Servlet 中介绍了初始化。
    • 调用服务方法,传递请求和响应对象。服务方法在编写服务方法中讨论。
  2. 如果需要删除 servlet,容器通过调用 servlet 的 destroy 方法来完成 servlet。有关更多信息,请参阅完成 Servlet。

[...]

servlet 执行时可能会发生任意数量的异常。发生异常时,Web 容器会生成包含以下消息的默认页面:

发生了 Servlet 异常

如何正确init()

让我们回顾一下 Javadoc init()(重点是我的)

由 servlet 容器调用以向 servlet指示 servlet 正在投入使用。

servlet 容器在实例化 servlet 后恰好调用一次 init 方法。init 方法必须成功完成,servlet 才能接收任何请求。

如果 init 方法,则 servlet 容器无法将 servlet 投入服务

  • 抛出 ServletException
  • 在 Web 服务器定义的时间段内不返回

因此,请注意不要在您的 .NET 中做任何太费力的init()事情,而那些只需要做一次的事情。如果是所有请求都需要做的事情,那么在请求处理方法中做(例如doGet(),,doPost()...)。

另请参阅Java EE 6 教程以及 Java EE 5中的创建和初始化 Servlet)。

如何正确destroy()

由 servlet 容器调用以向 servlet指示 servlet 正在停止服务。只有在 servlet 的服务方法中的所有线程都退出或经过超时时间之后,才会调用此方法。servlet容器调用该方法后,不会再在该servlet上调用service方法。

此方法使 servlet 有机会清理任何被占用的资源(例如,内存、文件句柄、线程),并确保任何持久状态与 servlet 在内存中的当前状态同步。

另请参阅Java EE 6 教程以及 Java EE 5中的Finalizing a Servlet)(当然,这里的词选择不佳......)。

有关历史 Servlet 设计以及为什么试图绕过它是一件坏事 (TM) 的更多信息!

请参阅http://oreilly.com/catalog/jservlet/chapter/ch03.html#15894

为什么不使用构造函数呢?嗯,在 JDK 1.0(最初是为它编写 servlet)中,动态加载的 Java 类(例如 servlet)的构造函数不能接受参数。因此,为了向新的 servlet 提供有关其自身及其环境的任何信息,服务器必须调用 servlet 的 init() 方法并传递一个实现 ServletConfig 接口的对象。此外,Java 不允许接口声明构造函数。这意味着javax.servlet.Servlet 接口不能声明接受 ServletConfig 参数的构造函数。它必须声明另一个方法,例如 init()。当然,您仍然可以为您的 servlet 定义构造函数,但在构造函数中,您无权访问 ServletConfig 对象或抛出 ServletException。

特别注意最后一句话:

[...] 但在构造函数中,您无权访问 ServletConfig 对象或抛出 ServletException。

所以在 servlet 的构造函数中做任何事情都是:

  • 不切实际的,
  • 但大多非常危险!
于 2013-06-10T10:33:20.167 回答
0

我很确定 servlet 将遵循正常的对象生命周期,并且调用构造函数。

init 方法的存在意味着您可以包含初始化代码,该代码依赖于框架的其他部分也已初始化。它在框架构建中的一个已知点被调用。

可能会调用Finalize - 它会在所有 java onjects 上遇到与 finalize 相关的所有相同问题

于 2013-06-10T10:31:15.247 回答
0

构造函数创建 servlet 的对象。init()用于初始化 servlet 对象。容器ServletConfig在方法中传递对 servlet 对象的引用,init(ServletConfig)以便 Servlet 可以访问ServletConfigand ServletContext。您可以覆盖无参数init()方法来执行任何特定于您的 Servlet 的初始化代码。如果没有init()method ,您的 Servlet 将无法访问其 init 参数。

由于destroy()是容器用来清理 Servlet 持有的资源的方法,因此您应该使用它。该finalize()方法应该被视为从内存中删除对象时绝对最后一次清理的机会,而不是正常的例程清理方法destroy()。由于在Servlet容器仍然有对Servlet对象的引用时调用它,所以它会在之前调用GC 进程总是会调用finalize().

于 2013-06-10T10:31:46.277 回答