Spring annotations - @Configuration to invoke spring bean auto-building
spring, spring-annotations
Solution
The java based container configuration doesnt depend on doing a component scan in any way. Its merely a different approach for the XML based component configuration. With the XML configuration you'd just have to declare your bean with the MyServiceImpl class in case its already @inject annotated. Spring would recognize the annotations and take care of them. If you really want to instanciate MyServiceImpl from a @Configuration java class without calling the constructor yourself, then you'd have to make use of the bean factory (havent tested it, just give it a try):
@Configuration
public class MyConfiguration {
@Autowired AutowireCapableBeanFactory beanFactory;
@Bean public MyService myService() {
return beanFactory.createBean(MyServiceImpl.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true);
}
}
Problem
If I declare a class using @Bean and then component scan for the class, spring will instantiate the class by invoking it's constructor and injecting constructor args and injecting any fields marked with @Inject. For simplicity's sake, lets call this spring auto-building. I dislike component scan and wish to avoid it completely (I don't wish to discuss my reasons for not liking it). I would like to use a @Configuration object instead but would still like to have the auto-building functionality available to me. Is it possible to invoke spring to auto-build my objects instead of explicitly having to pass all the constructor arguments in my @Configuration object? Lets assume that I have a bean: ``` public class MyServiceImpl implements MyService { public MyServiceImpl(Dependency1 d1, Dependency d2) { ... } .... } ``` I could define a configuration object like this: ``` @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); } } ``` But now, I have explicitly had to call the MyServiceImpl constructor myself so I will have to keep updating this as my constructor changes over time. I was hoping that I could declare an abstract method so that spring auto-building could take place: ``` @Configuration public abstract class MyConfiguration { @Bean public abstract MyServiceImpl myService(); } ``` But this doesn't work. Is there a way that I can invoke spring auto-building without using a component scan? In Google Guice, this can be done via the Binder: https://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/Binder.html In Tapestry IOC, this can be done via the ServiceBinder: http://tapestry.apache.org/ioc-cookbook-basic-services-and-injection.html#IoCCookbook-BasicServicesandInjection-SimpleServices Update Based on spod's answer, I was able to achieve what I was after (thanks!). Test case included for anyone that wants to do the same: ``` 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()); } } ```