我正在将单例转换为Spring bean,因此如果单例无法初始化,则整个Web应用程序的spring上下文无法正确加载。
使Spring上下文无法正确加载的优点是人们会在部署过程中注意并修复配置。与使用'非spring bean'单例相反:当在初始化期间抛出异常时,没有人注意到......直到实际用户抱怨缺少功能。
我的更改正在按预期进行..但我不确定我做的是否正确。
有什么想法吗?
代码如下所示:
public class MySingleton {
private static MySingleton INSTANCE = null;
private MySingleton(){}
public static MySingleton getInstance(){
if(INSTANCE == null){
synchronized(MySingleton.class){
if(INSTANCE == null){
try{
doWork()
}catch(Exception e){
throw new IllegalStateException("xyz", e);
}
INSTANCE = new MySingleton();
}
}
}
return INSTANCE;
}
private static void doWork() {
// do some work
}
}
在spring config xml中,bean将被定义为:
<bean id="MySingletonBean"
class="com.MySingleton"
factory-method="getInstance" lazy-init="false" singleton="true">
</bean>
注意: 其中大部分与本文中讨论的策略类似: http://springtips.blogspot.com/2007/06/configuration-hell-remedy-with.html
<小时/> 修改1:
使用这个单例的类不是spring bean本身..它们只是非弹簧pojos,我无法转换为spring。他们必须依赖getInstance()方法获取Singleton。
编辑2:(将我在下面发表的评论复制到此说明部分) 我试图针对两件事:
<小时/> 编辑3(最终): 我决定让这个班级成为一个单身人士......而不是把它变成一个春天的豆子。如果它无法初始化,它将在日志文件中记录一些内容..希望进行部署的人注意到....我放弃了我之前提到的方法,因为我觉得它将来会造成维护噩梦,所以我不得不选择 - 单身 - 或 - 春豆。我选择了单身人士。
答案 0 :(得分:18)
您必须将INSTANCE
字段声明为volatile
才能使双重检查锁定正常工作。
答案 1 :(得分:12)
为什么你首先使用 singleton 模式?让Spring为你创建bean(使用默认的singleton
范围)并使用它。当然总是有人可以手工制作豆子,但在我的情况下这绝不是问题。
依赖注入和Spring管理的bean生命周期将显着减轻您的生活(只需看看您可以避免多少陷阱)。另请注意,从c-tor或@PostContruct
方法抛出的异常将传播并导致应用程序上下文启动失败。
更新:我明白你的意思了。这就是我的想法:
@Service
public class Singleton {
private static AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();
public Singleton() {
final Singleton previous = INSTANCE.getAndSet(this);
if(previous != null)
throw new IllegalStateException("Second singleton " + this + " created after " + previous);
}
public static Singleton getInstance() {
return INSTANCE.get();
}
}
让Spring做好自己的工作。您可以尽可能使用DI,并在必要时使用Singleton.getInstance()
。
还有更多的核心解决方案,比如编译时AspectJ编织和基本上将Spring bean注入所有内容。
答案 2 :(得分:6)
我不确定你为什么要这样做。当你告诉Spring一个bean应该是一个单例时,相应的类不需要是一个单独的,也不需要工厂。 Spring只是简单地创建了一个实例。
链接的文章对我没有意义,因为没有注入发生,我可以看到:“AnyService”正在调用单例工厂方法;应用程序上下文中引用单例在引用之前是无关紧要的,似乎没有其他bean引用它。
答案 3 :(得分:5)
真正的单身人士很难开始工作。
挥发性双重检查锁定也不起作用。在维基http://en.wikipedia.org/wiki/Double-checked_locking
上阅读相关内容你最好的选择就是这样做
public class MySingleton {
private static MySingleton INSTANCE = new MySingleton();
即如果您的实际代码中没有任何构造函数参数。
答案 4 :(得分:3)
据我所知,这是一种腰带和吊带的解决方案。
如果你创建一个bean并在配置中将它声明为一个单例,那么就不需要保护bean不被多次创建。
你现在基本上保护自己免受错误配置bean的人的伤害。
我个人会通过spring配置和Javadoc中的文档“解决”它。
答案 5 :(得分:1)
要在启动时运行代码(并在出错时失败),请使用多种方法之一来注册启动事件,例如:见http://www.baeldung.com/running-setup-logic-on-startup-in-spring
示例:
@Component
public class InitializingBeanExampleBean implements InitializingBean {
private static final Logger LOG = Logger.getLogger(InitializingBeanExampleBean.class);
@Autowired
private Environment environment;
@Override
public void afterPropertiesSet() throws Exception {
LOG.info(Arrays.asList(environment.getDefaultProfiles()));
}
}
答案 6 :(得分:0)
@Component
public class SingletonDAOImpl {
}
@Component
public class SingletonDAO {
@Autowired private SingletonDAOImpl instance;
public SingletonDAOImpl getInstance(){
return this.instance
}
}
public class WhateverPlaceYouNeedIt{
@Awtowired private SingletonDAO singletonDao;
public void useSIngleton() {
SingletonDAOImpl INSTANCE = singletonDao.getInstance();
}
}
我尝试了很多方法来做类似 SingletonDao.instance.doSomething() 的事情 但只是不是在春天的方式,你会发现很多黑客来做到这一点,但在我看来是不正确的
这里
是同一个原理应用略有不同,很简单,一直尝试KIS实现(Keep it simple)