Если я объявлю класс с помощью @Bean, а затем просканирую компонент для класса, Spring создаст экземпляр класса, вызвав его конструктор и внедрив аргументы конструктора, а также внедрив любые поля, отмеченные @Inject. Для простоты назовем эту весну автостроительством.
Мне не нравится сканирование компонентов, и я хочу полностью его избежать (я не хочу обсуждать причины, по которым мне это не нравится). Вместо этого я хотел бы использовать объект @Configuration, но все же хотел бы, чтобы мне были доступны функции автоматического построения. Можно ли вызвать Spring для автоматической сборки моих объектов вместо того, чтобы явно передавать все аргументы конструктора в мой объект @Configuration?
Предположим, что у меня есть bean:
public class MyServiceImpl implements MyService {
public MyServiceImpl(Dependency1 d1, Dependency d2) { ... }
....
}
Я мог бы определить объект конфигурации следующим образом:
@Configuration
public class MyConfiguration {
// lets assume d1 and d2 are defined in another @Configuration
@Inject
Dependency1 d1;
@Inject
Dependency2 d2;
@Bean
public MyService myService() {
// I dislike how I have to explicitly call the constructor here
return new MyServiceImpl(d1, d2);
}
}
Но теперь мне пришлось явно вызывать конструктор MyServiceImpl самостоятельно, поэтому мне придется постоянно обновлять его по мере изменения моего конструктора с течением времени.
Я надеялся, что смогу объявить абстрактный метод, чтобы можно было выполнить весеннее автоматическое построение:
@Configuration
public abstract class MyConfiguration {
@Bean
public abstract MyServiceImpl myService();
}
Но это не работает. Есть ли способ, которым я могу вызвать весеннее автоматическое построение без использования сканирования компонентов?
В Google Guice это можно сделать с помощью Binder: https://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/Binder.html
В Tapestry IOC это можно сделать с помощью ServiceBinder: http://tapestry.apache.org/ioc-cookbook-basic-services-and-injection.html#IoCCookbook-BasicServicesandInjection-SimpleServices
Обновить
Основываясь на ответе спода, я смог добиться того, к чему стремился (спасибо!). Тестовый пример включен для всех, кто хочет сделать то же самое:
import java.util.Date;
import javax.inject.Inject;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class AutoBuildConfigurationTest {
@Configuration
public static class MyConfiguration {
@Inject
private AutowireCapableBeanFactory beanFactory;
@Bean
public Date date() {
return new Date(12345);
}
@Bean
public MyService myService() {
return autoBuild(MyService.class);
}
protected <T> T autoBuild(Class<T> type) {
return type.cast(beanFactory.createBean(type, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true));
}
}
public static class MyService {
private Date date;
public MyService(Date date) {
this.date = date;
}
public Date getDate() {
return date;
}
}
@Test
public void testAutoBuild() {
ApplicationContext appContext = new AnnotationConfigApplicationContext(MyConfiguration.class);
MyService myService = appContext.getBean(MyService.class);
Assert.assertEquals(12345, myService.getDate().getTime());
}
}