У меня есть одиночный элемент, который имеет введенный Дао пружины (упрощенный ниже):
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, но не иметь пружину управляют MyService?
В основном я хочу смочь сделать это из своего кода:
MyService.getInstance().doSomething();
в то время как наличие пружины вводит MyDao для меня.
Как упоминалось другими, вы должны позволить Spring управлять своими синглтонами, но если вы хотите управлять ими самостоятельно и просто позволяете Spring вводить зависимости, сделайте следующее:
applicationContext.getAutowireCapableBeanFactory().autowireBean(yourService);
Если вам нужен синглтон, почему бы просто не определить этот класс в конфигурациях Spring, и он автоматически синглтон (по умолчанию).
Чтобы избежать инициализации при запуске, смотрели ли вы на Spring отложенную инициализацию ? В основном вам нужно:
lazy-init="true"
в определении вашего bean-компонента.
Я считаю, что интерфейс 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);