Search code examples
spring-bootspring-mvcspring-batchpostconstruct

How to get @Postconstruct with Spring batch in web container?


Currently I am trying to get my script to run on a tomcat server by using the basic web container guidelines for spring-batch-boot from the documentation https://docs.spring.io/spring-batch/reference/html/configureJob.html The script was working correctly as a jar file before modifications to the main class but when I try converting it to a servlet I am having issues with my @PostConstruct starting only on server startup. This code sets application.properties to spring.batch.job.enabled=false and has a controller of

@Controller
public class JobLauncherController {
   @Autowired
   JobLauncher jobLauncher;

   @Autowired
   Job job;

   @RequestMapping("/jobLauncher.html")
   public void handle() throws Exception{
      jobLauncher.run(job, new JobParameters());
}

With The main Application to start the servlet for tomcat as

@SpringBootApplication
@EnableBatchProcessing
public class BatchApplication extends SpringBootServletInitializer{

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(BatchApplication.class);
}

public static void main(String[] args) {

    SpringApplication.run(BatchApplication.class, args);

}

The problem is that my job uses custom item readers and writers that initializes it before running it using @PostConstruct. It runs the @PostConstruct at server startup which is what helps initialize the beans for writing. My item readers/writers look like this

public class CustomReader extends ItemStreamSupport implements ItemReader<Acct>, ResourceAwareItemReaderItemStream<Acct> {
    //basic autowiring
    private int nextAcctIndex;
    private List<Acct> acctsList = new ArrayList();

    @PostConstruct
    private void initialize() throws IOException {
        //logic to parse files
        acctsList = Collections.unmodifiableList(acctsList);
        nextAcctIndex = 0;
    }

    @Override
    public Acct read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        // System.out.println("Start Read");

        Acct nextAcct = null;
        if (nextAcctIndex < acctsList.size()) {
            nextAcct = acctsList.get(nextAcctIndex);
            nextAcctIndex++;
            //System.out.println(nextAcct);
        }

The BatchConfiguration calls everything like most examples as
@Bean public IteamReader<Acct> CustomReader(){ return new CustomReader();}

My question is am I going about this the wrong way or is there a way to make it so the @PostConstruct is able to be called only when the Controller request for it?


Solution

  • you need to use

    @BeforeStep
    public void beforeStep(StepExecution stepExecution) {
        init();
    }
    

    @PostConstruct is used to initialize once after applicationContext is loaded. In your case you want to run this initialization every time job is running (you don't want data to be leaked across different jobs, right?)