MiamiBeach
MiamiBeach

Reputation: 3487

Moving from Guice to Spring: beans with default constructor and properties handling

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:

  1. 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?

  2. Properties files handling. While working with Guice I did a bad thing: I have scattered @Named annotation along huge number of private fields where property values were injected. Sometimes there were 5 properties to be injected in some class - and this resulted in 5 annotations. That was not a good solution.I tried to do better with Spring, but the only thing I have found is instantiating and injecting Configuration files everywhere. Just take a look of this perfection:
    @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

Answers (1)

Luca Masera
Luca Masera

Reputation: 732

  1. 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) {
          ...
       }
    }
    
  2. 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

Related Questions