Java 具有 init 方法的单例
Java singleton with init method
Singleton 是一项需要注入身份验证和配置数据的服务。我以 class:
结尾
class SingleService {
private String conn;
private String user;
private String pass;
private SingleService() {
// Can throw exception!!
conn = Config.getProperty("conn");
user = Config.getProperty("user");
pass = Config.getProperty("pass");
// Can throw exception!!
internalService = tryConnect(conn, user, pass);
}
private static SingleService instance;
public static void init() {
instance = new SingleService();
}
public static synchronized SingleService getInstance() {
if (instance == null) init();
return instance;
}
}
专用 init()
方法用于应用程序启动期间的异常处理,以尽早检测到初始化错误,因为稍后我们只是调用 getInstance()
并且不希望得到错误:
class App {
public static void main(String args[]) {
try {
Config.init("classpath:auth.properties");
SingleService.init();
} catch (Exception ex) {
logger.error("Can't init SingleService...");
System.exit()
}
doJob();
}
private static void doJob() {
SingleService.getInstance().doJob();
}
}
我担心 init()
方法和单例 class 签名。补一下 class 设计的不好但是不明白哪里出了问题
是否可以从 getSingleton()
和 synchronized
中移除初始化并在初始化期间保留对异常的控制?
SingleService ss1 = SingleService.getInstance();
SingleService.init();
SingleService ss2 = SingleService.getInstance();
所以 ss1
是一个不同于 ss2
的对象,这不是 Singleton 的设计目的。如果 ss1
在任何时候被修改 ss2
将不受影响。
这就是我的编码方式,因此您可以在需要时抛出异常,但仍然有一个线程安全的单例。
enum SingleService {
INSTANCE;
private String conn;
private String user;
private String pass;
private SingleService instance;
public synchronized void init(Config config) throws SomeException {
// don't leave in a half state if we fail.
internalService = null;
conn = config.getProperty("conn");
user = config.getProperty("user");
pass = config.getProperty("pass");
internalService = tryConnect(conn, user, pass);
}
public synchronized void methodForService() {
if (internalService == null) throw new IllegalSateException();
// do work.
}
}
您绝对不会公开对象创建方法。如果您想检查某些东西,请使用断言或任何不会破坏实例对象的操作。
public static void checkIfValid() {
assert Config.getProperty("conn");// do not corrupt instance object
assert Config.getProperty("user");
assert Config.getProperty("pass");
}
public static synchronized SingleService getInstance() {
if (instance == null){ // only here you can initiate instance object
instance = new SingleService();
}
return instance;
}
我寻找的问题的生产代码:
public abstract class AbstractCaller<Port> {
abstract protected Port createPort();
protected init() {
Port port = createPort();
// heavy use of introspection/reflection on **port** object.
// Results are used later by **call** method.
}
public call() {
// Reflection based on data collected by **init** method.
}
}
public class ConcreteCaller extends AbstractCaller<ConcretePort> {
private ConcreteService service = new ConcreteService();
@Override
protected ConcretePort createPort() {
return service.getPort();
}
private static class Holder {
public static ConcreteCaller INSTANCE;
static {
INSTANCE = new ConcreteCaller();
INSTANCE.init();
}
}
public static Caller getInstance() {
return Holder.INSTANCE;
}
}
抽象 class 具有通用 init
方法,只能在完全初始化的具体 class 上运行。内部静态 class 用于延迟实例化并执行 init
调用。
无法从 superclass 构造函数应用 init
方法来避免在每个实现中调用 init
。
Singleton 是一项需要注入身份验证和配置数据的服务。我以 class:
结尾class SingleService {
private String conn;
private String user;
private String pass;
private SingleService() {
// Can throw exception!!
conn = Config.getProperty("conn");
user = Config.getProperty("user");
pass = Config.getProperty("pass");
// Can throw exception!!
internalService = tryConnect(conn, user, pass);
}
private static SingleService instance;
public static void init() {
instance = new SingleService();
}
public static synchronized SingleService getInstance() {
if (instance == null) init();
return instance;
}
}
专用 init()
方法用于应用程序启动期间的异常处理,以尽早检测到初始化错误,因为稍后我们只是调用 getInstance()
并且不希望得到错误:
class App {
public static void main(String args[]) {
try {
Config.init("classpath:auth.properties");
SingleService.init();
} catch (Exception ex) {
logger.error("Can't init SingleService...");
System.exit()
}
doJob();
}
private static void doJob() {
SingleService.getInstance().doJob();
}
}
我担心 init()
方法和单例 class 签名。补一下 class 设计的不好但是不明白哪里出了问题
是否可以从 getSingleton()
和 synchronized
中移除初始化并在初始化期间保留对异常的控制?
SingleService ss1 = SingleService.getInstance();
SingleService.init();
SingleService ss2 = SingleService.getInstance();
所以 ss1
是一个不同于 ss2
的对象,这不是 Singleton 的设计目的。如果 ss1
在任何时候被修改 ss2
将不受影响。
这就是我的编码方式,因此您可以在需要时抛出异常,但仍然有一个线程安全的单例。
enum SingleService {
INSTANCE;
private String conn;
private String user;
private String pass;
private SingleService instance;
public synchronized void init(Config config) throws SomeException {
// don't leave in a half state if we fail.
internalService = null;
conn = config.getProperty("conn");
user = config.getProperty("user");
pass = config.getProperty("pass");
internalService = tryConnect(conn, user, pass);
}
public synchronized void methodForService() {
if (internalService == null) throw new IllegalSateException();
// do work.
}
}
您绝对不会公开对象创建方法。如果您想检查某些东西,请使用断言或任何不会破坏实例对象的操作。
public static void checkIfValid() {
assert Config.getProperty("conn");// do not corrupt instance object
assert Config.getProperty("user");
assert Config.getProperty("pass");
}
public static synchronized SingleService getInstance() {
if (instance == null){ // only here you can initiate instance object
instance = new SingleService();
}
return instance;
}
我寻找的问题的生产代码:
public abstract class AbstractCaller<Port> {
abstract protected Port createPort();
protected init() {
Port port = createPort();
// heavy use of introspection/reflection on **port** object.
// Results are used later by **call** method.
}
public call() {
// Reflection based on data collected by **init** method.
}
}
public class ConcreteCaller extends AbstractCaller<ConcretePort> {
private ConcreteService service = new ConcreteService();
@Override
protected ConcretePort createPort() {
return service.getPort();
}
private static class Holder {
public static ConcreteCaller INSTANCE;
static {
INSTANCE = new ConcreteCaller();
INSTANCE.init();
}
}
public static Caller getInstance() {
return Holder.INSTANCE;
}
}
抽象 class 具有通用 init
方法,只能在完全初始化的具体 class 上运行。内部静态 class 用于延迟实例化并执行 init
调用。
无法从 superclass 构造函数应用 init
方法来避免在每个实现中调用 init
。