如何从单例模式迁移到Spring?

时间:2014-09-15 11:46:08

标签: spring singleton

我目前正在开发一个大型的非Spring代码库。 我想将Spring Context引入代码库,但我希望逐步实现。

我要解决的首要挑战之一是“Springify”一个在代码中使用了很多的大单例对象。

单例在代码中使用如下:

SomeInstance instance = SomeInstance.getInstance();
instance.doSomething()

单例对象包含一个字段和方法,如下所示:

class SomeInstance {
    private static SomeInstance instance;

    public static SomeInstance getInstance(){
    if(instance == null){
        instance = new SomeInstance();
    }
    return instance;
}

好的,但是我想让SomeInstance类成为一个Spring bean。

没问题:

@Component
class SomeInstance {
    ...
}

但是我仍然希望保留getInstance()静态方法,并使其返回单例实例以便向后兼容而不必重构所有内容。 如果我想在代码中的任何地方摆脱getInstance()方法,这意味着一个巨大的重构:

  • 制作使用SomeInstance Spring beans
  • 的所有对象
  • 使用@Autowired连接单身

那会很棒,但我现在无法证明这样的大型重构是合理的。

但是如何让SomeInstance Spring管理并仍保持getInstance()方法以实现向后兼容?

我想到了这样的事情:

public static SomeInstance getInstance() {
    return ApplicationContext.getBean("someInstanceBean");
}

但是,可能无法从静态上下文调用getBean()方法...

关于如何处理这个的任何想法?

2 个答案:

答案 0 :(得分:3)

在您的应用程序上下文XML文件中,您需要做的就是编写如下条目:

<bean id="thing" name="thing" class="com.example.ThingSingleton"
    factory-method="getInstance">
</bean>

没有理由更改现有的API。您现有的API强制声明或指定为单例的实际上是单例。这很好,值得保留。 Spring是一种方便的方法,可以使用类的Plain Old Java API将POJO连接在一起,而不是构造函数,工厂方法等的替代方法。

完成后,您可以对自己说“我的代码都不应该调用com.example.ThingSingleton.getInstance(),所以我应该将其标记为@Deprecated,这是我使用之前的遗留物弹簧”。但这是非常错误的。在任何真正意义上,该方法都不是已弃用:您明确告诉Spring使用它,这不是一个错误。该方法仍然是获得Singleton实例的唯一批准方式。 恰好发生,没有代码写入它。 不推荐使用并不意味着“我的代码中未使用”。这意味着“不应该使用,因为将来很可能被删除”。您不会删除getInstance()方法,是吗?

答案 1 :(得分:0)

您可以创建一个单例来保存上下文。像这样的东西可能对你有用。 由于ApplicationContextAware接口,ApplicationContext将在启动期间自动设置。

有可能上下文将为null,您可能希望减轻它,但是如果Spring正确初始化则不应该是一个问题。

@Component
public class TestClass implements ApplicationContextAware {


    private static ApplicationContext context = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static  Object getBean(String beanName){
        return context.getBean(beanName);
    }
}