4

I have situation where I share singleton between my code which runs the embedded-server and my web-application. I have war with classes and deployment tool. When I printf instances I see:

abc.Abc@173a10f
abc.Abc@105738

So this is not really singleton. How this works?


My server Jetty start code:

public static void main(String[] args) throws Exception
{
    System.out.println(MySingleton.getInstance());
    // start Jetty here and deploy war with WebAppContext()
}

My ServletContextListener side code:

public class AppServletContextListener implements ServletContextListener{
    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        System.out.println(MySingleton.getInstance());
    }
}

My singleton:

public class MySingleton {
    private static MySingleton INSTANCE = new MySingleton();
    private MySingleton () {}
    public static MySingleton getInstance() {
        return INSTANCE;
    }
}

I forced exception inside constructor. It looks like I get two different.

java.lang.Exception
        at api.MySingleton.<init>(MySingleton.java:33)
        at api.MySingleton.<clinit>(MySingleton.java:22)
        at my.project.StartJetty.main(StartJetty.java:41)
java.lang.Exception
        at api.MySingleton.<init>(MySingleton.java:33)
        at api.MySingleton.<clinit>(MySingleton.java:22)
        at api.AppServletContextListener.contextInitialized(AppServletContextListener.java:25)
        at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:640)
        at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:229)
        at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1208)
        at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:586)
        at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:449)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:58)
        at org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:224)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:58)
        at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:89)
        at org.eclipse.jetty.server.Server.doStart(Server.java:258)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:58)
        at my.project.StartJetty.main(StartJetty.java:66)
4

3 回答 3

5

查看一些Jetty 文档。您可以使用类加载配置。

如果设置为 true,则 Jetty 使用正常的 JavaSE 类加载优先级,并为父/系统类加载器提供优先级。这避免了 webapp 中类的多个版本的问题,但是父/系统加载器提供的版本必须是您以这种方式配置的所有 webapps 的正确版本。

这正是你所描述的情况。一个MySingleton实例正在由主 Java 程序加载,另一个实例正在由 Jetty 的类加载器加载。

于 2013-09-11T20:17:11.933 回答
2

您的 ServletContextListener 和主类由不同的类加载器加载。每当一个类被加载时,它的静态块就会被执行。所以你会得到两个实例......

如果你想确保同一个类加载器加载你的单例,你必须自己指定类加载器。

检查此链接以获取更多详细信息 http://www.javaworld.com/article/2073352/core-java/simply-singleton.html?page=2

于 2013-09-11T20:13:59.427 回答
2

在构造函数中打印堆栈跟踪应该为您提供所需的信息,以找出它在哪里被实例化以及什么顺序。单例模式是一件危险的事情,通常最好用不同的方式来做。

于 2013-09-11T20:10:41.010 回答