依赖注入你的单身人士

时间:2010-05-18 20:10:51

标签: spring dependency-injection singleton

我有一个弹簧注射Dao的单身人士(简化如下):

public class MyService<T> implements Service<T> {
    private final Map<String, T> objects;
    private static MyService instance;

    MyDao myDao;

    public void set MyDao(MyDao myDao) {
        this. myDao = myDao;
    }

    private MyService() {
        this.objects = Collections.synchronizedMap(new HashMap<String, T>());
        // start a background thread that runs for ever
    }

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

    public void doSomething() {
        myDao.persist(objects);
    }
}

我的春季配置可能如下所示:

 <bean id="service" class="MyService" factory-method="getInstance"/>

但是这会在启动时实例化MyService。

是否有一种编程方式将MyDao依赖注入MyService,但没有spring管理MyService?

基本上我希望能够从我的代码中执行此操作:

MyService.getInstance().doSomething();
春天为我注射了MyDao。

4 个答案:

答案 0 :(得分:4)

这是一个解决方案,使用静态工厂方法创建一个类:

public class MyService {
    private static MyService instance;

    private MyDao myDao;

    public static MyService createInstance(final MyDao myDao) {
      instance = new MyService(myDao);
      return instance;
    }

    private MyService(final MyDao myDao) {
      this.myDao = myDao;
    }

    public static synchronized MyService getInstance() {
      return instance;
    }

    public void doSomething() {
      // just do it!
      myDao.justDoIt();
    }
}

并使用spring来启动它:

  <bean class="my.path.MyService" factory-method="createInstance" scope="singleton">
    <constructor-arg ref="reference.to.myDao" />
  </bean>

现在你应该能够做到:

MyService.getInstance().doSomething();

没有任何问题。

答案 1 :(得分:2)

如果你想要一个单例,为什么不在Spring配置中定义一个类,它自动是一个单独的(默认情况下)。

为了避免在启动时初始化,你看过Spring lazy initialisation吗?基本上你需要:

lazy-init="true"

在你的bean定义中。

答案 2 :(得分:0)

正如其他人所提到的,你应该让spring管理你的单身人士,但如果你想自己管理它们并让spring注入依赖关系,那就这样做:

applicationContext.getAutowireCapableBeanFactory().autowireBean(yourService);

答案 3 :(得分:0)

我相信FactoryBean界面对你来说是个不错的选择。当您需要执行一些初始化逻辑时,这是一个非常好的选择。例如,在单独的线程中启动内存数据库或某些后台进程。

您可以在reference documentation中了解更多相关信息。

演示如何在每次有人想从FactoryBean实现中获取bean时实例化数据库并返回数据源的示例。

@PostConstruct
void init() {
    embeddedDatabase = new EmbeddedDatabaseBuilder().addScript(schemaPath)
         .addScript(dataPath).setType(embeddedDatabaseType).build();
}


public DataSource getObject() throws Exception {
    return embeddedDatabase;
}

这可以实现工厂逻辑和返回对象之间的松散耦合。它在内部被Spring框架大量使用。

如果您希望在第一次使用它时对其进行初始化,请将lazy-initialization设置为true。

如果您希望代码与Spring容器交互,另一种方法是创建一个实现ApplicationContextAware接口的工厂。然后你可以做这样的事情:

myDao = context.getBean(MyDao.class);