Tomcat - 在启动时Servlet init()方法被调用两次

4
我有一个与独立Tomcat服务器(未与Apache链接)相关的问题。
当Tomcat启动时,Servlet的init()方法被调用两次,即两个Servlet正在启动。更令人担忧的是,它们似乎是由不同的类加载器加载的 - 在命令行上只有一个Java进程在运行,因此不是多个Tomcat。
web.xml片段(Servlet仅配置一次,并且仅在webapp web.xml中进行配置):
<servlet>
  <servlet-name>LenderInterfaceServlet</servlet-name>
  <display-name>Lender Interface Servlet</display-name>
  <servlet-class>com.foobar.lender.webservice.server.LenderInterfaceServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>

我在init方法中添加了一些日志,并创建了一个名为RatesPoller的单例类,init方法试图获取该实例。从日志中我们可以看到单例实例是不同的:

LenderInterfaceServlet - [init] Start: com.foobar.lender.webservice.server.LenderInterfaceServlet@56d90453
LenderInterfaceServlet - [init] Starting up the Rates pollers.
LenderInterfaceServlet - [init] Got com.foobar.lender.framework.rates.RatesPoller@ae0e515
LenderInterfaceServlet - [init] Start: com.foobar.lender.webservice.server.LenderInterfaceServlet@1b0c6cfc
LenderInterfaceServlet - [init] Starting up the Rates pollers.
LenderInterfaceServlet - [init] Got com.foobar.lender.framework.rates.RatesPoller@5759780d

所以我们有两个不同的servlet和两个不同的单例轮询器。

我怀疑这意味着Tomcat正在启动存储在Tomcat webapps文件夹中的webapp的两个实例。显然,当你想要启动只有一个运行的东西时,这是一个问题,我需要找出如何确保Tomcat不会运行webapp两次!

如果有人有任何想法...

代码:

public class RatesPoller {

  private static RatesPoller instance;

  private RatesPoller() {}

  public static RatesPoller getInstance() {
    if (instance == null) {
        instance = new RatesPoller();
    }
    return instance;
  }

  public RatesPoller clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException("Singleton. Tsk!");
  }
}

还有在LenderInterfaceServlet中的init()方法:

public class LenderInterfaceServlet extends AxisServlet {
  // ...
  @Override
  public void init() throws ServletException {
    logger.info("[init] Start: " + this);
    super.init();
    logger.info("[init] Starting up the Rates pollers.");
    RatesPoller rp = RatesPoller.getInstance();
    logger.info("[init] Got " + rp);
  }
  // ...
}

"单例模式。 唉!"(今天真开心 :)) - ADTC
4个回答

4

Tomcat会自动部署webapps中的所有内容,并根据server.xml进行部署。如果想避免重复加载,只需将您的web应用程序从webapps目录中删除即可。


1
你的代码存在一个错误。你的单例模式不是线程安全的。那个getInstance()方法应该被同步。否则你有可能会构造多个实例。

真的。我认为现在我会使用Spring或Guice来管理这些事情。 - JeeBee

0
我会在init()方法中设置断点,然后查看堆栈以查看调用来自哪里。

它们都来自deployDirectory,可能是因为Tomcat看到了webapp并进行了自动部署,同时又看到了web.xml并使用它进行了部署,因为loan-on-startup被设置了... - JeeBee

-1
如果init()方法失败,可能会在后续的get调用中再次被调用。您是否检查了catalina.out文件,以确保init()调用没有因某种原因而被中止?

不会的。Servlet 没有被加载,因此不会再次执行。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接