12

I have a Spring Batch tasklet as follows in my application.

@Service
public class SampleTasklet implements Tasklet {
    
    @Autowired
    private UserService userService;

    @Override
    public RepeatStatus execute(StepContribution contribution,
                                ChunkContext chunkContext) throws Exception {

        System.err.println(userService.getUsers().size());
        return RepeatStatus.FINISHED;
    }

}

and I have a Service Class as follows.

@Service
@Slf4j
public class UserService {
    public Map<String, String> getUsers(){
        return null
    }

}

Spring Boot class :

@SpringBootApplication
@Slf4j
public class SampleBatchApp {

    public static void main(String[] args) {
        log.info("Custom DAM Batch Application starting");
        SpringApplication.run(SampleBatchApp.class, args);
    }

}

Spring Batch File: -- EDITED as per comments.

@Configuration
@EnableBatchProcessing
public class SampleBatch {

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Autowired
    public SampleTasklet sampleTasklet;

    @Bean
    public Job importUserJob() {
        return jobBuilderFactory.get("importUserJob")
                .start(step1())
                .build();
    }
       
    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                .tasklet(sampleTasklet)
                .build();
    }

}

When I start my application I get an error as follows.

Field userService in SampleTasklet required a bean of type 'UserService' that could not be found.

Can you please explain this weird behavior? I have tried looking for this in multiple places and I think we can't @autowire a service class inside a tasklet. Am I correct?

Paulo Merson
  • 13,270
  • 8
  • 79
  • 72

3 Answers3

8

OK I found the error.

In your SampleBatch you declare your Bean SampleTasklet in Java Config. That means you have to make sure all dependencies get injected. That is why you do not get the UserService autowired.

Make sure that the UserService gets set in

@Bean
public SampleTasklet sampleTasklet(UserService userService){
    return new SampleTasklet(userService);
}

and do not forget to add this constructor in your SampleTasklet and assign the UserService there.

public class SampleTasklet implements Tasklet {

private UserService userService;

    public SampleTasklet (UserService userService){
        this.userService=userService;
    }
mrkernelpanic
  • 4,268
  • 4
  • 28
  • 52
  • Will try the same. and let u know. I have tried doing Autowired of SampleTasklet instead of Bean. I got the error that i mentioned earlier – jagannathan rajagopalan Dec 08 '17 at 10:16
  • and remove `@Service` if you instantiate the Beans yourself. You have to decide what you want/ need. Either full handling of Spring or mixed or ... – mrkernelpanic Dec 08 '17 at 10:18
  • Doing it via @Bean seems to be bit complex and messy. Is it possible to do via Autowired annotation so that i need not manage what needs to injected? – jagannathan rajagopalan Dec 08 '17 at 10:20
  • Thanks for your continued. Doing it via @Bean seems to be bit complex and messy. Is it possible to do via Autowired annotation so that i need not manage what needs to injected? Not sure whether spring batch supports for creating steps? – jagannathan rajagopalan Dec 08 '17 at 10:26
  • Sure, just autowire your `SampleTasklet` in your `SampleBatch` configuration. But then you have to add `@Service` again to the `SampleTasklet` and also autowire the UserService. – mrkernelpanic Dec 08 '17 at 10:30
  • I have tried autowiring and i have updated the code in the question. I still get userService in SampleTasklet required a bean of type 'UserService' that could not be found. – jagannathan rajagopalan Dec 08 '17 at 10:36
  • It looks to me that from Spring Batch we cannot autowire a tasklet that can inturn autowire a service class. Is it correct? @mrkernelpanic – jagannathan rajagopalan Dec 08 '17 at 11:04
  • No that is wrong, double check your packages where your UserService resides vs your Spring Config/ Application.I assume your component-scan won't detect the UserService as a bean. – mrkernelpanic Dec 08 '17 at 12:05
1

Where is your UserService class located? Since one of the things@SpringBootApplication annotation does is a component scan, but it will only scan on sub-packages. i.e. if your SampleBatchApp class is in com.mypackage, then it will scan for all classes in sub-packages i.e. com.mypackage.*.

Or other alternative is to use a @SpringBootApplication(scanBasePackages = {"com.mypackage"})

Karl Alexander
  • 351
  • 4
  • 16
0

I added @Component and @Configuration to the class and an @Autowired to my service instance in the TaskLet class, as shown:

@Component
@Configuration
public class CrawlerTask implements Tasklet {
 
    @Autowired
    private BatchService service;

And added my TaskLet in my configuration:

@Autowired
private CrawlerTask crawlerTask;