如果我使用@Bean声明一个类然后对该类进行组件扫描,那么spring将通过调用它的构造函数并注入构造函数args并注入标有@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
更新
根据spod的回答,我能够实现我的目标(谢谢!)。测试用例包括给想要这样做的人:
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());
}
}
答案 0 :(得分:7)
基于java的容器配置不依赖于以任何方式进行组件扫描。它仅仅是基于XML的组件配置的不同方法。使用XML配置,您必须使用MyServiceImpl类声明您的bean,以防已经注释了@inject。 Spring会识别注释并照顾它们。如果你真的想在没有自己调用构造函数的情况下从@Configuration java类实现MyServiceImpl,那么你必须使用bean工厂(没有测试它,只是试一试):
@Configuration
public class MyConfiguration {
@Autowired AutowireCapableBeanFactory beanFactory;
@Bean public MyService myService() {
return beanFactory.createBean(MyServiceImpl.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true);
}
}