Singleton读取Java webapp中的属性文件;正确的做法?

时间:2009-12-22 19:26:19

标签: java properties singleton web-applications

我的spaghetti monster使用来自几个不同SOAP服务的XML,并且每个服务的URL都硬编码到应用程序中。我正在撤消此硬编码,并将URL存储在属性文件中。

在阅读属性文件方面,我想在Singleton中包含可以根据需要引用的逻辑。

改变这个:
    accountLookupURL ="http://prodServer:8080/accountLookupService";

对此:
    accountLookupURL =urlLister.getURL("accountLookup");

Singleton将包含在urlLister中。

我倾向于回避单身人士模式,只是因为我以前不必使用它。我在正确的轨道上吗?

谢谢!
IVR Avenger

6 个答案:

答案 0 :(得分:3)

你还没有说明为什么你只需要获取URL的其中一个。如果这只是涉及读取属性文件,我认为你不需要只有一个。在我看来,让两个线程同时读取相同的属性文件根本不是问题。

除非您考虑使用一些只读取属性文件的对象,然后缓存内容以备将来使用。但这是一个Web应用程序,对吧?因此,处理它的方法是在应用程序启动时读取属性,并将它们存储在应用程序上下文中。只有一个应用程序上下文,所以这是你的“唯一”对象。

答案 1 :(得分:2)

作为替代方案,您是否考虑使用类似Apache Commons Configuration(或可能是其他configuration framework)的内容?

答案 2 :(得分:1)

单身人士适合这种情况,但你必须确保你正确地做单身人士。

所以,例如,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的例子的不同之处:这是一个很好的vanilla类,其中唯一的静态是实例var和返回它的方法。另请注意延迟初始化所需的synchronized关键字。

更新:Pascal在下面的评论中推荐了一篇关于lazy-init单例的更好方法的非常酷的帖子:http://crazybob.org/2007/01/lazy-loading-singletons.html

答案 3 :(得分:1)

基于你的建议,以及我认为我没有像我希望的那样访问这个应用程序的事实(很多都是在编译代码中抽象出来的),这就是我煮熟的解决方案起来。当然,这是一个存根,需要通过更好的异常处理等来充实。

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;
  }

}

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 Avenger

答案 4 :(得分:0)

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

答案 5 :(得分:0)

单身人士是可变的静力因而是邪恶的。 (假设“单身人士”的定义相当有用。

任何使用静态(传递关系)的代码都假设几乎所有其他东西(在这种情况下,Web服务器和互联网)。可变静力学是糟糕的设计,糟糕的设计使许多方面变得腐烂(依赖性,可理解性,测试性,安全性等)。

作为一个例子,阻止在沙盒中使用JUnit 3的后期版本的唯一方法是在一个静态初始化器中加载配置文件。如果它使用了来自Above的参数化,则没有问题。