簡體   English   中英

Spring:步驟 Scope 和 Bean 自動裝配

[英]Spring: Step Scope & Bean Autowiring

我目前正處於一個我似乎無法弄清楚的問題的真正痛苦之中。 我希望這里有人可以提供一些指導。 這一切都圍繞着 StepScope、bean 自動裝配和 bean 創建。

配置一(自動裝配步驟 Scope Beans):

配置java

(為簡單起見,我減少了配置 class。)

@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 中有關。

配置二(步驟Scope Beans的Setter注入)

配置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:在 class 路徑資源 [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 實例覆蓋。 在 class 路徑資源 [Config.class] 中定義的 BeanDefinition 中聲明的同名覆蓋 bean

我的想法

我之前遇到過這個問題,我的解決方法是為我注入的類創建一個接口。

public interface StepScopeBeanOne {
    //methods
}

public class StepScopeBeanOneImpl implements StepScopeBeanOne {
   //methods
}

我不想再次使用 go 這條路線,因為我相信它會增加代碼的復雜性。 如果有人有不同的解決方案,請分享。

配置三(有效的那個)

從這些 bean 中刪除步驟 Scope 會導致精細而漂亮的自動裝配。

配置.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;
        }
}

處理器是一樣的

結果

Beans 是通過 @Autowireing 注解注入的。

我的想法

您可能會問自己,為什么不直接刪除 @StepScope? 好吧,我不能。 我需要在每個這些 bean 上執行 scope 步驟,以允許正確注入 JobParameters。 我們在作業參數中使用步驟名稱來提供微調的步驟配置。

全面的

我的目標是讓配置一工作。 在該目標之外,將不勝感激更好地理解 Spring 中的 bean 創建。

我的目標是讓配置一工作。

下面是一個基於“配置一”的完整示例:

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

這將打印以下 output ,而不會出現關於步進范圍 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 ),因此默認情況下,step-scoped beans 是基於類的代理(使用 cglib)並且不需要實現接口.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM