2

I'd like to defined mutiple Jobs in my spring-batch application, and trying to make them modular as follows:

@Configuration
@EnableBatchProcessing(modular = true)
public class ModularConfig {
    @Bean
    public ApplicationContextFactory getJob1() {
        Sysout("job1");
        return new GenericApplicationContextFactory(Job1.class);
    }

    @Bean
    public ApplicationContextFactory getJob2() {
        Sysout("job2");
        return new GenericApplicationContextFactory(Job2.class);
    }
}

From the sysout I can see both job beans are created.

BUT: when one of those jobs is launched, the @Beans of that job cannot be found.

public class Job1 {
    @Bean
    public Job job(Step step) {
        return jobFactory.get("job1")
                .start(step)
                .build();
    }


    @Bean
    public Step step(ItemReader<String> reader, ItemProcessor<String, String> processor, ItemWriter<String> writer) {
        return stepFactory.get("importStep")
                .reader(reader)
                .processor(processor)
                .writer(writer)
                .build();
    }

    @Bean
    @JobScope
    public IteamReader<String> reader(@Value("#{jobParameters['filename']}") String filename) {
        //returns a FlatFileItemReader<String>
    }

    //omitted also `@Bean` for processor + writer
}

Result: the reader is not found in the job configuration! Why?

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'reader' is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:698) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1175) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getType(AbstractBeanFactory.java:596) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.GenericTypeAwareAutowireCandidateResolver.checkGenericTypeMatch(GenericTypeAwareAutowireCandidateResolver.java:95) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.GenericTypeAwareAutowireCandidateResolver.isAutowireCandidate(GenericTypeAwareAutowireCandidateResolver.java:64) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver.isAutowireCandidate(QualifierAnnotationAutowireCandidateResolver.java:142) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.isAutowireCandidate(DefaultListableBeanFactory.java:687) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.isAutowireCandidate(DefaultListableBeanFactory.java:646) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.isAutowireCandidate(DefaultListableBeanFactory.java:630) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1191) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    ... 34 more

So why may the reader not being found? I mean: what can I do more than naming the bean method itself reader() and also inject it with variable name reader?

Sidenote: when I remove the modularty and just use @Configuration on class Job1 then job runs fine. So I'm quite sure the configuration of the job and the reader should be correct. But of course I cannot run a similar jobclass beneath, so I'd like to have modularity enabled.


Edit: when I enable the @Configuration annotation on my jobs, I'm getting a duplicate job name exception. That's why I'm not having it in the code above.

Caused by: org.springframework.batch.core.configuration.DuplicateJobException: A job configuration with this name [job1] was already registered
    at org.springframework.batch.core.configuration.support.MapJobRegistry.register(MapJobRegistry.java:51) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.configuration.support.DefaultJobLoader.doRegister(DefaultJobLoader.java:258) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.configuration.support.DefaultJobLoader.doLoad(DefaultJobLoader.java:193) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.configuration.support.DefaultJobLoader.load(DefaultJobLoader.java:151) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.configuration.support.AutomaticJobRegistrar.start(AutomaticJobRegistrar.java:173) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    ... 16 more
membersound
  • 81,582
  • 193
  • 585
  • 1,120

1 Answers1

1

Without @Configuration beans on job1 won't be registered. Please have a look at this test case Test Configuration

Rafik BELDI
  • 4,140
  • 4
  • 24
  • 38
  • I your testcase is valid, then it's strange I'm getting a `DuplicateJobException` when I enable `@Configuration` additionally to the modular registration. See my update above. – membersound Jul 20 '16 at 13:20
  • @membersound in your application do you registrer configuration classes manually or you scan a package ? I think you shouldn't scan the job config classes and let GenericApplicationContextFactory register it – Rafik BELDI Jul 20 '16 at 13:37
  • I'm using `spring-boot` with `@SpringBootApplication` which automatically scans the packages. So you'd suggest I'd exclude the package with the job configurations? – membersound Jul 20 '16 at 13:41
  • @membersound just the Job class – Rafik BELDI Jul 20 '16 at 13:44
  • If I do that, and have the jobs registered only by `ApplicationContextFactory`, I'm getting the exception again: `NoSuchBeanDefinitionException: No bean named 'reader' is defined`. – membersound Jul 20 '16 at 13:45
  • can you try registering it manually to `AutomaticJobRegistrar ` – Rafik BELDI Jul 20 '16 at 13:48
  • Registering the jobs manually without having `@Configuration` on the job itself, I'm getting again the exception: `No bean named 'reader' is defined`. If I add `@Configuration` to the job, it works **but** the job `@Bean` is somehow created twice (but without name clash). Then, when trying to invoke the jobs, there name is not found. – membersound Jul 20 '16 at 14:06
  • I created a simple example with 2 jobs that should be running modularized: https://drive.google.com/file/d/0B0qVi9D7R5MZOTE3ME9xdHdKNms/view?usp=sharing There are two problems in the project: 1. even though the two different jobs execute, both seem to be using the `reader` from `job2`. 2. as soon as I enable the `ModularBatchConfig` class, the project is not starting up anymore. Maybe you could help fixing this example so that both jobs can be running modular? Thanks for your time! – membersound Jul 20 '16 at 15:20