Search code examples
springspring-batch

spring-batch sample: why call the constructor method directly?


I'm looking at the samples for spring-batch and I'm surprised to see a bean constructor method being called directly rather than through a bean reference. I'm wondering if this is an error.

In https://github.com/TechPrimers/spring-batch-example-1/blob/master/src/main/java/com/techprimers/springbatchexample1/config/SpringBatchConfig.java

...
@Configuration
@EnableBatchProcessing
public class SpringBatchConfig {

    ...

    @Bean
    public FlatFileItemReader<User> itemReader() {

        FlatFileItemReader<User> flatFileItemReader = new FlatFileItemReader<>();
        ...
        flatFileItemReader.setLineMapper(lineMapper());
        return flatFileItemReader;
    }

    @Bean
    public LineMapper<User> lineMapper() {
      ...
    }

Whereas the bean constructor method lineMapper() is annotated as @Bean, the bean constructor method itemReader() does not inject the bean in its constructor but rather calls lineMethod() directly.

I would have expected this definition of itemReader():

@Bean
public FlatFileItemReader<User> itemReader(LineMapper<User> lineMapper) {

    FlatFileItemReader<User> flatFileItemReader = new FlatFileItemReader<>();
    ...
    flatFileItemReader.setLineMapper(lineMapper);
    return flatFileItemReader;
}

Isn't this an error in the current spring-batch samples? Or am I missing something? Perhaps @Configuration does something magic and converts direct calls to constructors into a bean with a proxy? Perhaps lineMapper() doesn't need to be a bean at all?

Thanks for any insight.


Solution

  • Both ways you mentioned will have the same effect which will inject the LineMapper bean into the FlatFileItemReader 's @bean method.

    For the SpringBatchConfig case , it is using injecting inter-bean dependencies feature, which allow to inject a bean into a @Bean method via direct method call. And your guess is correct , it works because the @Bean method is get proxied by the ConfigurationClassEnhancer.BeanMethodInterceptor if you are interested to know how does it works in code level.

    Please note this feature will only enable if you are using full bean mode (i.e. Then @Bean method is defined inside the @Configuration class) and @Configuration 's proxyBeanMethods=true (default value).

    Otherwise, any of the following situation will cause calling lineMapper() just create a new instance but not accessing the LineMapper instance from the spring context :

    @Component
    public class SpringBatchConfig {
    
    
        @Bean
        public FlatFileItemReader<User> itemReader() {
            FlatFileItemReader<User> flatFileItemReader = new FlatFileItemReader<>();
            ...
            flatFileItemReader.setLineMapper(lineMapper());
            return flatFileItemReader;
        }
    
        @Bean
        public LineMapper<User> lineMapper() {
          ...
        }
    }
    
    • Using full bean mode but proxyBeanMethods=false :
    @Configuration(proxyBeanMethods = false)
    public class SpringBatchConfig {
    
    
        @Bean
        public FlatFileItemReader<User> itemReader() {
            FlatFileItemReader<User> flatFileItemReader = new FlatFileItemReader<>();
            ...
            flatFileItemReader.setLineMapper(lineMapper());
            return flatFileItemReader;
        }
    
        @Bean
        public LineMapper<User> lineMapper() {
          ...
        }
    }