【问题标题】:Spring: Step Scope & Bean AutowiringSpring:Step Scope 和 Bean 自动装配
【发布时间】:2021-03-22 04:59:23
【问题描述】:

我目前正处于一个我似乎无法弄清楚的问题的真正痛苦之中。我希望这里有人可以提供一些指导。这一切都围绕着 StepScope、bean 自动装配和 bean 创建。

配置一(自动装配 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() {
            return new 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...
}

结果

org.springframework.beans.factory.UnsatisfiedDependencyException:创建名为“scopedTarget.scopedTarget.Processor”的bean时出错:通过字段“stepScopeBeanOne”表示的依赖关系不满足;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException:没有可用的“StepScopeBeanOne”类型的合格 bean:预计至少有 1 个有资格作为自动装配候选者的 bean。依赖注解:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

我的想法

我认为这与解析处理器 bean 时 bean StepScopeBeanOne 不在 ApplicationContext 中有关。

配置二(Step Scope Beans的Setter注入)

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;
        }
}

处理器与配置一相同

结果

org.springframework.beans.factory.BeanCreationException:在类路径资源 [Config.class] 中定义名称为“scopedTarget.scopedTarget.Processor”的 bean 创建错误:通过工厂方法进行 Bean 实例化失败;嵌套异常是 org.springframework.beans.BeanInstantiationException:无法实例化 [Processor]:工厂方法“处理器”抛出异常;嵌套异常是 java.lang.IllegalStateException:@Bean 方法 Config.stepScopeBeanOne 被称为类型 [StepScopeBeanOne] 的 bean 引用,但被类型 [com.sun.proxy.$Proxy149] 的不兼容 bean 实例覆盖。覆盖在类路径资源 [Config.class] 中定义的 BeanDefinition 中声明的同名 bean

我的想法

我之前遇到过这个问题,我的解决方法是为我正在注入的类创建一个接口。

public interface StepScopeBeanOne {
    //methods
}

public class StepScopeBeanOneImpl implements StepScopeBeanOne {
   //methods
}

我不想再走那条路,因为我相信它会增加代码的复杂性。如果有人有不同的解决方案,请分享。

配置三(有效的)

从这些 bean 中删除 Step Scope 会导致一个很好的自动装配。

配置类

@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;
        }
}

处理器相同

结果

通过 @Autowiring 注解注入 Bean。

我的想法

您可能会问自己,为什么不直接删除 @StepScope?好吧,我不能。我需要对这些 bean 中的每一个进行 step 范围,以允许正确注入 JobParameters。我们在作业参数中使用步骤名称来提供微调的步骤配置。

总体

我的目标是让配置一正常工作。在这个目标之外,更好地理解 Spring 中的 bean 创建将不胜感激。

【问题讨论】:

  • 您没有分享一个完整的最小示例来重现该问题,但我尝试过,但无法根据您分享的内容重现该问题。我用一个例子添加了一个答案。希望对您有所帮助。

标签: java spring spring-boot spring-batch


【解决方案1】:

我的目标是让配置一正常工作。

下面是一个基于“配置一”的完整示例:

import java.util.Arrays;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableBatchProcessing
public class MyJobConfiguration {

    @Bean
    @StepScope
    public StepScopeBeanOne stepScopeBeanOne() {
        return new StepScopeBeanOne();
    }

    @Bean
    @StepScope
    public StepScopeBeanTwo stepScopeBeanTwo () {
        return new StepScopeBeanTwo();
    }

    @Bean
    @StepScope
    public Processor processor() {
        return new Processor();
    }

    @Bean
    public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
        return jobs.get("job")
                .start(steps.get("step")
                        .<Integer, Integer>chunk(5)
                        .reader(new ListItemReader<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)))
                        .processor(processor())
                        .writer(items -> items.forEach(System.out::println))
                        .build())
                .build();
    }

    public static void main(String[] args) throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyJobConfiguration.class);
        JobLauncher jobLauncher = context.getBean(JobLauncher.class);
        Job job = context.getBean(Job.class);
        jobLauncher.run(job, new JobParameters());
    }
    
    static class StepScopeBeanOne {
        
    }

    static class StepScopeBeanTwo {

    }

    static class Processor implements ItemProcessor<Integer, Integer> {

        @Autowired
        private StepScopeBeanOne stepScopeBeanOne;

        @Autowired
        private StepScopeBeanTwo stepScopeBeanTwo;
        
        @Override
        public Integer process(Integer item) throws Exception {
            return item + 1;
        }

        public void setStepScopeBeanOne(StepScopeBeanOne stepScopeBeanOne) {
            this.stepScopeBeanOne = stepScopeBeanOne;
        }

        public void setStepScopeBeanTwo(StepScopeBeanTwo stepScopeBeanTwo) {
            this.stepScopeBeanTwo = stepScopeBeanTwo;
        }
    }
}

这将打印以下输出,而没有任何关于步进范围 bean 或依赖注入的问题:

[main] WARN org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer - No datasource was provided...using a Map based JobRepository
[main] WARN org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer - No transaction manager was provided, using a ResourcelessTransactionManager
[main] INFO org.springframework.batch.core.launch.support.SimpleJobLauncher - No TaskExecutor has been set, defaulting to synchronous executor.
[main] INFO org.springframework.batch.core.launch.support.SimpleJobLauncher - Job: [SimpleJob: [name=job]] launched with the following parameters: [{}]
[main] INFO org.springframework.batch.core.job.SimpleStepHandler - Executing step: [step]
1
2
3
4
5
6
7
8
9
10
[main] INFO org.springframework.batch.core.step.AbstractStep - Step: [step] executed in 73ms
[main] INFO org.springframework.batch.core.launch.support.SimpleJobLauncher - Job: [SimpleJob: [name=job]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 119ms

@StepScope 等价于@Scope(value = "step", proxyMode = ScopedProxyMode.TARGET_CLASS)(参见javadoc),因此默认情况下,步进范围的 bean 是基于类的代理(使用 cglib),不需要实现接口。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 2021-09-02
    相关资源
    最近更新 更多