Инъекция зависимости в ваш синглтон - PullRequest
6 голосов
/ 19 мая 2010

У меня есть синглтон с пружинным Дао (упрощенно ниже):

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 ]

4 голосов
/ 04 апреля 2011

Вот решение, создайте класс со статическим фабричным методом:

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();
    }
}

и используйте пружину для его инициализации:

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

и теперь вы должны уметь:

MyService.getInstance().doSomething();

без проблем.

2 голосов
/ 19 мая 2010

Если вам нужен singleton, почему бы просто не определить этот один класс в конфигах Spring, и он автоматически будет singleton (по умолчанию)

Чтобы избежать инициализации при запуске, вы смотрели на Spring ленивая инициализация ? В основном вам нужно:

lazy-init="true"

в вашем определении бина.

0 голосов
/ 24 мая 2010

Я считаю, что интерфейс FactoryBean - хорошая альтернатива для вас. Это очень хороший выбор, когда вам нужно выполнить некоторую логику инициализации. Например, чтобы запустить базу данных в памяти или некоторые фоновые процессы в отдельных потоках.

Подробнее об этом можно прочитать в справочной документации .

Пример, демонстрирующий, как я создаю экземпляр базы данных и возвращаю источник данных каждый раз, когда кто-то хочет bean-компонент из реализации FactoryBean.

@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);
0 голосов
/ 20 мая 2010

Как уже упоминалось, вы должны позволить Spring управлять своими синглетонами, но если вы хотите управлять ими самостоятельно и просто позволить Spring вводить зависимости, сделайте следующее:

applicationContext.getAutowireCapableBeanFactory().autowireBean(yourService);
...