Singleton在Java Web应用程序中读取属性文件;正确的做法?

问题描述:

我的意大利面怪兽从几种不同的SOAP服务中使用XML,并且每种服务的URL都被硬编码到应用程序中。我正在取消该硬编码,并将这些URL存储在一个属性文件中。Singleton在Java Web应用程序中读取属性文件;正确的做法?

在读取属性文件而言,我想涵盖根据需要可被引用一个Singleton该逻辑。

更改此:
accountLookupURL ="http://prodServer:8080/accountLookupService";

要这样:
accountLookupURL =urlLister.getURL("accountLookup");

的辛格尔顿将被包含在URLLister中内。

我倾向于回避Singleton模式了,只是因为我已经没有使用它,之前。我在正确的轨道上,在这里?

谢谢!
IVR复仇者

要重申显而易见的,当所有的客户端代码应该与类的单个实例对话时使用单例。因此,使用Singleton IFF,您肯定不会一次加载多个属性文件。就我个人而言,我希望能够拥有该功能(加载多个属性文件)。

+0

使用单不排除加载多个属性文件一次......我有一个使用一个单集中访问多个属性文件(在我的情况实际上是把ResourceBundle)一些代码。也许你的意思是多个属性文件包含相同属性名称的定义? – Nate 2009-12-22 20:58:04

+0

对,如果我加载了多个属性文件,我不会担心名称冲突,因为系统不应该(一定)假定他们之间有任何关系。 – danben 2009-12-22 21:05:49

+0

此外,即使没有名称冲突,您可能希望对属性集合进行逻辑分离(即从不同实例访问集合)。你可以命名空间他们,但我不会为此疯狂。 – danben 2009-12-22 21:06:55

单身是可变的静态因此也是邪恶的。 (假设一个合理有用的“单例”定义

任何使用静态(传递关系)的代码都有几乎所有其他的假设(在这种情况下,是一个web服务器和互联网)。是不好的设计,糟糕的设计使得很多方面变得糟糕(依赖性,易懂性,测试性,安全性等)。

作为一个例子,停止在沙盒中使用JUnit 3的晚期版本的唯一方法是加载配置文件中的一个静态初始化器。如果它从上面使用参数化,就不会有任何问题。

+0

-1没有解决问题或提供任何信息的圆形解释 – danben 2009-12-22 21:02:08

你还没有说为什么你只需要任何的一方面,这是其中W生病得到的URL。如果这只涉及阅读属性文件,我不认为你只需要一个。在我看来,有两个线程同时读取相同的属性文件根本不是问题。

除非你在想有一些对象只读取属性文件一次,然后供将来使用缓存的内容。但这是一个Web应用程序,对不对?所以处理这个问题的方法是在应用程序启动时读入属性,并将它们存储在应用程序上下文中。只有一个应用程序上下文,所以你的“只有一个”对象。

+0

我不确定我能否做到这一点,因为这个应用程序的很大一部分被抽象为JAR文件,其源不可用于我们。这会带来什么? – 2009-12-22 20:52:44

+0

IVR复仇者,你现在如何将属性传递给Jar文件? – Poindexter 2009-12-23 14:57:51

+0

我会想象那些属性是完全按照你上面描述的来读取的。但是,阅读发生在我可以访问的领域之外。我的代码扩展了我没有的源代码,并且这些类正在读取特定的属性。理想情况下,我会更改基类,以便这些URL与现有属性一样可用,但我无法访问基类。然而......--) – 2009-12-23 15:32:02

单身适合此方案,但你必须确保你正在做的单身权利。因此,例如,Bozhno建议不是一个单身人士,它是一个丑陋的静态混合物,不可嘲笑,不易测试,不可注射,并且通常会回来咬你。

可接受的单身只是你有一个明显的例外,平均班,它是通过其自身或通过一些外部工厂/框架(例如Spring IoC来)保证在只有一个实例存在。如果用第一种方法去,你这样做

private MyUberSingletonClass() { 
    //..do your constructor stuff, note it's private 
} 

private static MyUberSingletonClass instance = null; 

public static synchronized MyUberSingletonClass instance() { 
    if (instance == null) { 
     instance = new MyUberSingletonClass(); 
    } 
    return instance; 
} 

public String getUberUsefulStuff(){ 
    return "42"; 
} 

这是可以接受的,如果你不觉得一个工厂,否则的需要,并在应用中不使用任何IoC容器(好主意考虑使用一个虽然)。请注意与Bozhno示例的区别:这是一个很好的香草类,其中唯一的静态是实例var和返回它的方法。还要注意延迟初始化所需的synchronized关键字。

更新:帕斯卡建议这个即将在下面的评论延迟实例单身更好的方式非常酷的帖子:http://crazybob.org/2007/01/lazy-loading-singletons.html

+1

你可能想读这个:http://crazybob.org/2007/01/lazy-loading-singletons.html – 2009-12-22 21:15:02

+0

非常非常好!感谢Pascal。比同步的成语更整齐。我只是想知道,从1.3开始,对于所有的JVM来说这种行为是否一致 - 我最近一直在做Blackberry的开发,正如你所知,CLDC是一个婊子。 – 2009-12-22 21:54:36

作为替代方案,你可以考虑使用类似Apache Commons Configuration(或者其他configuration framework) ?

+0

(+1)最好不要重新发明轮子 – Bozho 2009-12-22 23:26:48

+0

是的,这基本上是我的观点。 – 2009-12-22 23:33:59

根据您的建议,以及我认为我没有像希望的那样访问此应用程序的许多事实(其中很多是在编译代码中抽象出来的),下面是我的解决方案熟了。这当然是一个存根,需要用更好的异常处理等来充实。

public class WebServiceURLs { 

    private static class WebServiceURLsHolder 
    { 
    public static WebServiceURLs webServiceURLs = new WebServiceURLs(); 
    } 

    private Properties webServiceURLs; 


    public WebServiceURLs() 
    { 
    try 
    { 
     Properties newURLProperties = new Properties();  
     InputStreamReader inputStream = new InputStreamReader(
      FileLoader.class.getClassLoader().getResourceAsStream("../../config/URLs.properties")); 
     newURLProperties.load(inputStream); 
     webServiceURLs =newURLProperties; 
    } 
    catch (Exception e) 
    { 
     webServiceURLs =null; 
    }   
    } 

    public String getURLFromKey(String urlKey) 
    {  
    if (webServiceURLs==null) 
     return null; 
    else 
     return webServiceURLs.getProperty(urlKey); 
    } 

    public static WebServiceURLs getInstance() 
    { 
    return WebServiceURLsHolder.webServiceURLs; 
    } 

} 

这是一个很好的努力为我的 “第一次” 单身?

感谢,
IVR复仇者

+0

这不完全是一个单身人士。你应该让WebServiceUrls的一个对象成为它自己的一个实例变量,并使构造函数保持私有状态。 getInstance()方法应检查该对象是否已创建,如果尚未返回,则创建该对象。 – Poindexter 2009-12-23 15:02:03

+0

好的。但它模仿上面Pascal链接中详细描述的结构。这不是我应该采取的方法吗? – 2009-12-23 15:14:35