Reputation: 3487
I just have finished moving my pet project from Guice to Spring DI. I want to share some notes and ask for advice. Guice config was done with annotations (the only possible way), and Spring config is also only with annotations: one AppConfig class annotated with @Configuration and a plenty of bean creation methods annotated with @Bean inside.
Observations and questions:
Spring's configuration is full of methods that create beans with default no-args constructor:
@Bean public DataProvider getDataProvider() { return new DataProvider(); }
Thats definitely bad. Guice instantiates beans with default constructor without any additional configuration. Can I do this in Spring? I know that if I add @Component annotation along with classpath scanning annotation it will do the trick. But: 1. injecting with @Component is different from injecting with @Bean 2. I need to scatter my configuration among even more files than while just adding @Autowired. Thats bad. The only solution to keep all configs in one place is old good XML configuration, but again with explicit declaration of all beans. Or I am wrong and this can be done better in Spring?
@Bean public MyProjectStorageConfiguration getStorageConfiguration( @Value("${mongo.collections.names})") String mongoNames, @Value("${mongo.collections.data})") String mongoData, @Value("${files.maindata})") String mainData, @Value("${files.secondarydata})") String secondaryData, @Value("${files.backupdata})") String backupData, @Value("${files.additionaldata})") String additionalData) { return new MyProjectStorageConfiguration(mongoNames,mongoData, mainData,secondaryData,backupData,additionalData); }
Looks like my pet project needs to be refactored again. Any suggestions?
Upvotes: 1
Views: 1519
Reputation: 732
Yes, you're right. This is really a bad habit.
But it's not caused by Spring itself, just by the way the tutorials and all the other things are written. In fact you can use @Autowired
in constructor and Spring will inject the intefaces/classes that fit with the type of the required parameter.
With one, big, thing to remember (coming from Guice): if you have two or more instances of the same interface (two different implementations), to select the right one you have no chance then moving out the parameter to a setter adding the annotations @Autowired
and @Qualifier("[beanName]")
. Or move everything to a configuration file...
@Service
class AClass implements MyService {
@Autowired
public AClass(UniqueInterface uniqueInterface) {
...
}
@Autowired
@Qualifier("[beanName]")
public void setAnInterface(NotUniqueInterface notUniqueInterface) {
...
}
}
Normally you can inject property value directly in code. See values injection modes. But, in a way or another, you'll need to inject the values with annotations or using the configuration beans. There's no others ways (at least for what I know...).
Upvotes: 3