初始化"单身"通过配置文件是否合适?

时间:2014-08-30 22:26:57

标签: java multithreading oop system distributed

通过配置文件初始化单例是否合适?

我注意到singleton的构造函数不应该有任何参数,原因是如果你需要使用参数来配置你的对象,那么可能不应该是singleton。似乎这句话非常有名,但确实存在特殊的ser case案例:

例如 我们设计了一个简单的分布式系统来处理大量的用户。查询:

  • 只有一个中央服务器
  • n个子服务器,每个子服务器连接到中央服务器
  • 子服务器之间没有连接

显然,我们可能会设计中央服务器"作为单身人士,详情如下:

  • enum ServerType;
  • abstract class Server;
  • 类CentralServer继承自Server;(CentralServer是singleton)
  • class SubServer继承自Server;
  • class Query;
  • ...... ......

但是中央服务器需要一些配置,例如:

  • 服务器名
  • 描述
  • portNum-ipAddress map
  • 其子服务器列表
  • BlockingQueue的大小
  • ...... ......

如何通过这些属性初始化中央服务器?
我目前的解决方案:

  • 使用配置文件完成此部分作业。
  • 我定义了另一个名为Configuration的类。

所以中央服务器的当前构造函数如下:

class CentralServer extends Server implements Runnable, ....... {
    ....
    ....
    private static CentralServer _instance;
    private CentralServer () {
        super();
        .... 
        serverName = Configuration.getCentralServerName();
        description = Configuration.getCentralServerDescription();
        Configuration.initCentralServerPortNumIpMap(portNumIpMap);
        Configuration.initCentralServerSubServersList(subServersList);
        sizeBlockingQueue = Configuration.initCentralServerBlockingQueueSize();
        ....
    }

    public CentralServer getInstance() {
        if (_instance == null) {
            _instance = new CentralServer();
        }
        return _instance;
    }
    ....
    ....
}

Configuration类将读取和分析配置文件,以获取配置信息。

<小时/> 我的问题:

  • 如果没有合适或不合适的初始化单身,请 提供更合适的方法

  • 我还需要配置所有子服务器,所以似乎是配置 class太重了,我应该将Big Configuration类拆分成 两个子类? class CentralConfiguration和class 子结构

3 个答案:

答案 0 :(得分:2)

不幸的是,你对Singelton的实现是错误的!仅仅因为它不是线程安全的。

public CentralServer getInstance() {
    if (_instance == null) {   // race condition possible here 
        _instance = new CentralServer();
    }
    return _instance;
}

两个线程可能会进入此关键部分并将_instance==null评估为true,并将创建两个不同的实例。 您可以简单地静态实例化您的实例。

private final static CentralServer INSTANCE = new CentralServer();

public static CentralServer getInstance() {
    return INSTANCE;
}

但是,实现singeltons的最佳方法是使用enums

public enum CentralServer { // the best way to implement singletons, due to the author of Effective Java  
INSTANCE;

private CentralServer() {
}
}

这为您提供免费序列化。 但是,我不认为你需要一个singelton,singeltons通常是反模式。 Check this out

在您的代码中,CentralServer高度依赖Configuration,我认为这不是一件好事,您应该将配置视为依赖

class CentralServer{
 private final Configuration serverConf;

 private CentralServer(Configuration serverConf){  // inject configuration
   this.serverConf = serverConf;
 }
 public static CentralServer createCentralServer(Configuration serverConf){ // static factory perhaps
  return new CentralServer(serverConf);
 }
}

这将为您提供更灵活的更改或模拟配置。我认为工厂模式在这里更合适。

答案 1 :(得分:1)

  

初始化单身如此合适与否,如果没有,请给予   出更合适的方法:

这不是一种合适的方法,因为实现不是threadsafe而且它可以被破坏f.e.通过reflection。您应该考虑在此主题上阅读Effective Java by Joshua Bloch

最好是创建一个枚举单例,因为这种方法对于以后的更改更灵活,具有线程安全的实例并且是不可破解的。

编辑:example

  

我还需要配置所有子服务器,所以似乎是配置   class太重了,我应该将Big Configuration类拆分成   两个子类? class CentralConfiguration,类SubConfiguration?

出于配置目的,通常会在某处读取config.xml文件或config.properties文件以读取重要的预配置。创建实例后,您应该从这样的文件中提取信息,并在关闭时写出必要的更改。但与往常一样,许多方式都会导致罗马。

答案 2 :(得分:1)

在单例初始化期间使用外部资源是完全可以接受的。 Singleton模式的普通用户是记录器,它们几乎总是从外部数据文件配置。

它确实使初始化变得更加复杂,但是制作完全可靠的单例来访问外部资源(例如配置文件)并非不可能。如果他们的配置需要数据库访问,他们甚至可以使用其他单例,例如连接池。

这个问题的其他答案正确处理了单例初始化的实际问题。