使单例成为Spring bean的正确方法

我正在将单例转换为Spring bean,因此如果单例无法初始化,则整个Web应用程序的spring上下文无法正确加载。

使Spring上下文无法正确加载的优点是人们会在部署期间注意并修复配置。 与使用’非spring bean’单例相反:当在初始化期间抛出exception时,没有人注意到……直到实际用户抱怨缺少function。

我的改变正在按预期进行..但我不确定我是否做了正确的事情。
有什么想法吗?

代码如下所示:

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将被定义为:

   

注意:大部分内容类似于本文中讨论的策略: http : //springtips.blogspot.com/2007/06/configuration-hell-remedy-with.html


编辑1:

使用这个单例的类不是spring bean本身……它们只是非spring的pojos,我无法转换为spring。 他们必须依靠getInstance()方法来获取Singleton。


编辑2 🙁将我在下面的评论复制到此描述部分)我试图针对两件事:

  1. 我希望Spring初始化单例。 因此,如果初始化失败,则应用程序加载失败。
  2. 我希望其他类能够使用类而不必依赖contextAwareObj.getBean(“MySingleton”)

编辑3(最后):我决定让这个class级成为一个单身人士……而不是把它变成一个spring的豆子。 如果它无法初始化,它将在日志文件中记录一些内容..希望进行部署的人注意到….我放弃了我之前提到的方法,因为我觉得它将来会造成维护噩梦,所以我不得不选择 – 单身 – 或 – 春豆。 我选择了单身人士。

必须INSTANCE字段声明为volatile才能使双重检查锁定正常工作。

请参阅Effective Java , Item 71 。

为什么你首先使用单身模式? 让Spring为你创建bean(使用默认的singleton范围)并使用它。 当然总是有人可以手工制作豆子,但在我的情况下这绝不是问题。

dependency injection和Spring管理的bean生命周期将显着减轻您的生活(只需看看您可以避免多少陷阱)。 另请注意,从c-tor或@PostContruct方法抛出的exception将传播并导致应用程序上下文启动也失败。

更新 :我明白你的观点。 这就是我的想法:

 @Service public class Singleton { private static AtomicReference INSTANCE = new AtomicReference(); 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注入到所有内容中。

我不确定你为什么要这样做。 当你告诉Spring一个bean应该是一个单例时,相应的类不需要是一个单独的,也不需要工厂。 Spring只是简单地创建一个实例。

链接的文章对我没有意义,因为没有注入发生,我可以看到:“AnyService”正在调用单例工厂方法; 应用程序上下文中引用单例在引用之前是无关紧要的,似乎没有其他bean引用它。

真正的单身人士很难开始工作。

挥发性双重检查锁定也不起作用。 在维基http://en.wikipedia.org/wiki/Double-checked_locking上阅读它

你最好的选择就是这么做

 public class MySingleton { private static MySingleton INSTANCE = new MySingleton(); 

也就是说,如果您的实际代码中没有任何构造函数参数。

据我所知这是一个腰带和吊带解决方案。

如果您创建一个bean并在配置中将其声明为单例,那么就不需要保护bean不被多次创建。

你现在基本上保护自己免受错误配置bean的人。

我个人会通过spring配置和Javadoc中的文档“解决”它。

要在启动时运行代码(并在出错时失败),请使用多种方法之一来注册启动事件,例如,请参阅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())); } }