I'm currently in the midst of a real pain of a problem that I can't seem to figure out. I'm hoping someone on here can provide some guidance. It all revolves around StepScope, bean autowiring, and bean creation.
Configuration One (Autowiring Step Scope Beans):
Config.java
(I've reduced my configuration class for simplicity.)
@Configuration
@EnableBatchProcessing
public class Config {
@Bean
@StepScope
public StepScopeBeanOne stepScopeBeanOne() {
return new StepScopeBeanOne();
}
@Bean
@StepScope
public StepScopeBeanTwo stepScopeBeanTwo () {
return new StepScopeBeanTwo();
}
@Bean
@StepScope
public Processor processor() {
return new Processor();
}
}
Processor.java
public class Processor implements ItemProcessor<Incoming, Outgoing> {
//The two injected step scope beans...
@Autowired
private StepScopeBeanOne stepScopeBeanOne;
@Autowired
private StepScopeBeanTwo stepScopeBeanTwo;
@Override
public Outgoing process(Incoming incoming) {
//do process...
}
public void setStepScopeBeanTwo(StepScopeBeanTwo stepScopeBeanTwo) {
this.stepScopeBeanTwo = stepScopeBeanTwo;
}
public void setStepScopeBeanOne(StepScopeBeanOne stepScopeBeanOne) {
this.stepScopeBeanOne = stepScopeBeanOne;
}
//rest of class...
}
Result
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'scopedTarget.scopedTarget.Processor': Unsatisfied dependency expressed through field 'stepScopeBeanOne'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'StepScopeBeanOne' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
My Thoughts
I believe it has something to do with the bean StepScopeBeanOne not being in the ApplicationContext by the time the Processor bean is being resolved.
Configuration Two (Setter injection of Step Scope Beans)
Config.java
@Configuration
@EnableBatchProcessing
public class Config {
@Bean
@StepScope
public StepScopeBeanOne stepScopeBeanOne() {
return new StepScopeBeanOne();
}
@Bean
@StepScope
public StepScopeBeanTwo stepScopeBeanTwo () {
return new StepScopeBeanTwo();
}
@Bean
@StepScope
public Processor processor() {
Processor processor = new Processor();
processor.setStepScopeBeanOne(stepScopeBeanOne());
processor.setStepScopeBeanTwo(stepScopeBeanTwo());
return processor;
}
}
Processor is the same as Configuration One
Result
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.scopedTarget.Processor' defined in class path resource [Config.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [Processor]: Factory method 'processor' threw exception; nested exception is java.lang.IllegalStateException: @Bean method Config.stepScopeBeanOne called as bean reference for type [StepScopeBeanOne] but overridden by non-compatible bean instance of type [com.sun.proxy.$Proxy149]. Overriding bean of same name declared in: BeanDefinition defined in class path resource [Config.class]
My Thoughts
I've ran into this issue before, and my workaround was to create an interface for the classes I was injecting.
public interface StepScopeBeanOne {
//methods
}
public class StepScopeBeanOneImpl implements StepScopeBeanOne {
//methods
}
I'd prefer to not go that route again, because I believe it adds complexity to the code. If anyone has a different solution please share.
Configuration Three (The one that works)
Removing Step Scope from each of these beans results in a fine and dandy autowiring.
Config.class
@Configuration
@EnableBatchProcessing
public class Config {
@Bean
public StepScopeBeanOne stepScopeBeanOne() {
return new StepScopeBeanOne();
}
@Bean
public StepScopeBeanTwo stepScopeBeanTwo () {
return new StepScopeBeanTwo();
}
@Bean
public Processor processor() {
Processor processor = new Processor();
return processor;
}
}
Processor is the same
Results
Beans are injected via @Autowiring annotation.
My Thoughts
You may be asking yourself, why don't you just remove @StepScope? Well, I can't. I need step scope on each of these beans to allow for JobParameters to be injected correctly. We use the step name in our job parameters to provide fine tuned step configuration.
Overall
My goal is to get Configuration One working. Outside of that goal, a better understanding of bean creation in Spring would be much appreciated.