没有可用的“org.springframework.batch.core.Job”类型的合格 bean:预期单个匹配 bean,但找到了 2:

Posted

技术标签:

【中文标题】没有可用的“org.springframework.batch.core.Job”类型的合格 bean:预期单个匹配 bean,但找到了 2:【英文标题】:No qualifying bean of type 'org.springframework.batch.core.Job' available: expected single matching bean but found 2: 【发布时间】:2019-04-08 13:20:53 【问题描述】:

根据输入参数,我有 2 个作业在单个 spring 批处理应用程序中运行,并且运行成功。但是当我运行我的测试用例时,我得到了以下错误。我正在使用 gradle 来构建我的应用程序。

没有可用的“org.springframework.batch.core.Job”类型的合格 bean:预期的单个匹配 bean,但找到了 2:pureRedDataProcessingJob,pcsMasterProcessingJob

测试类:

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**

 * 
 * @author 
 *
 */
@ContextConfiguration(classes = UidBatchApplication.class, JobLauncherTestUtils.class, 
initializers = ConfigFileApplicationContextInitializer.class)
@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(locations = "classpath:application-test.properties")
@Configuration
@ActiveProfiles("test")
@Profile("test")
@TestConfiguration
@SpringBootTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING)

@EnableAutoConfiguration

public class UidBatchApplicationTest 


    @Autowired
    public JobLauncherTestUtils jobLauncherTestUtils;


    @Test
    public void launchJob() throws Exception 
        JobParameters params = new JobParametersBuilder().addString("jobName", "pcsMasterProcessingJob").toJobParameters();
        jobLauncherTestUtils.launchJob(params);
    


主类配置:

/*

 */



import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import javax.sql.DataSource;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
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.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.MultiResourceItemReader;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;




@Configuration
@ConfigurationProperties
@EnableBatchProcessing

public class UidApplicationConfiguration

    @Autowired
    private DataSource mariaDb;

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public JobExecutionListener listener() 
        return new JobCompletionNotificationListener();
    

    @Bean
    @Qualifier("pureRedDataProcessingJob")
    public Job pureRedDataProcessingJob() 
        return jobBuilderFactory.get(UidConstants.PURE_RED_JOB)
                .incrementer(new RunIdIncrementer()).listener(listener())
                .flow(pureRedStep()).end().build();
    

    @Bean
    public Step pureRedStep() 
        return stepBuilderFactory.get("pureRedStep").<PureRedBean, PureRedBean> chunk(1)
                .reader(multiResourcePureRedReader()).processor(pureRedProcessor()).writer(pureRedWriter()).faultTolerant()
                .build();
    

    @Bean
    public MultiResourceItemReader<PureRedBean> multiResourcePureRedReader()
    
        MultiResourceItemReader<PureRedBean> resourceItemReader = new MultiResourceItemReader<>();
        resourceItemReader.setResources(getPureredFilePath());
        resourceItemReader.setDelegate(pureRedReader());
        return resourceItemReader;
    

    @SuppressWarnings( "rawtypes", "unchecked" )
    @Bean
    public FlatFileItemReader<PureRedBean> pureRedReader()
    
        String[] namesArray = "circularType","rotoKey","xyCoordinate","xyCoordinate","xyCoordinate","adPrintVerNum",
                "adStartDttm","pageNum","itemWic","upc","headLineCopy","bodyCopy","xyCoordinate","pluCode",
                "vendorName","xyCoordinate","xyCoordinate","xyCoordinate","imageFileName","xyCoordinate",
                "offerPrice","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate",
                "quantity","getFree","rewardSpend","rewardPoints","rewardQuantity","percentOff","offerLimit",
                "templateName","adPriceVerbiage","rewardVerbiage","fsiVerbiage","mirVerbiage",
                "ivcVerbiage","retailVerbiage","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate",
                "sevenPartKey","fillerThree","largeImage","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate",
                "summary","additionalDealInfo","disclaimer","smallImage";
        PureredBeanWrapperFieldSetMapper beanWrapper = new PureredBeanWrapperFieldSetMapper();
        beanWrapper.setTargetType(PureRedBean.class);
        DefaultLineMapper linemapper = new DefaultLineMapper();
        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(UidConstants.CSV_DELIMITER);
        tokenizer.setNames(namesArray);
        linemapper.setLineTokenizer(tokenizer );
        beanWrapper.setDistanceLimit(0);
        linemapper.setFieldSetMapper(beanWrapper);

        //Create reader instance
        FlatFileItemReader<PureRedBean> reader = new FlatFileItemReader<>();         
        reader.setLineMapper(linemapper);
        return reader;
    

    @Bean
    public ItemWriter<PureRedBean> pureRedWriter()         
        JdbcBatchItemWriter<PureRedBean> writer = new JdbcBatchItemWriter<>();
        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<PureRedBean>());
        writer.setSql(pureredInsertQuery);      
        writer.setDataSource(mariaDb);
        return writer;
    

    @Bean
    public PureRedProcessor pureRedProcessor() 
        return new PureRedProcessor();
    

    @Bean
    @Qualifier("pcsMasterProcessingJob")
    public Job pcsMasterProcessingJob() 
        return jobBuilderFactory.get(UidConstants.PCS_MASTER_JOB)
                .incrementer(new RunIdIncrementer()).listener(listener())
                .flow(masterStep()).end().build();
    

    @Bean
    public Step masterStep() 
        return stepBuilderFactory.get("masterStep").<UniqueIdMasterBean, UniqueIdMasterBean> chunk(1)
                .reader(multiResourceItemReader()).processor(masterProcessor()).writer(writer()).faultTolerant()
                .build();
    

    @Bean
    public MultiResourceItemReader<UniqueIdMasterBean> multiResourceItemReader()
    
        MultiResourceItemReader<UniqueIdMasterBean> resourceItemReader = new MultiResourceItemReader<>();
        resourceItemReader.setResources(getFilePath());
        resourceItemReader.setDelegate(reader());
        return resourceItemReader;
    

    @SuppressWarnings( "rawtypes", "unchecked" )
    @Bean
    public FlatFileItemReader<UniqueIdMasterBean> reader()
    
        String[] namesArray = "uniqueId","spotSeqNum","adTypeCd","adMarketCd","adStartDttm","adExpiryDttm",
                "adEventType","adSeqNum","adVerCd","adVerSeqNum","adPrintVerNum","adLoyaltyOfferCd","adItemCouponNum",
                "adItemLayoutPosNum","adItemPageNum","adItemRetailMultiple","adItemRetailPrice","adItemSingleUnitPrice",
                "adItemAltPriceMult","adItemAltPrice","adItemAmtOff","adItemPercentOff","adPageTypeCd","minOrderValue",
                "rewardType","offerValue","loyaltyPoints","targetedFlag","","categoryLevelTwo","adFillerOne",
                "adFillerTwo","adFillerThree","statusFlagOne","statusFlagTwo";
        BeanWrapperFieldSetMapperCustom beanWrapper = new BeanWrapperFieldSetMapperCustom();
        beanWrapper.setTargetType(UniqueIdMasterBean.class);
        DefaultLineMapper linemapper = new DefaultLineMapper();
        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(UidConstants.CSV_DELIMITER);
        tokenizer.setNames(namesArray);
        linemapper.setLineTokenizer(tokenizer );
        linemapper.setFieldSetMapper(beanWrapper);

        //Create reader instance
        FlatFileItemReader<UniqueIdMasterBean> reader = new FlatFileItemReader<>();      
        reader.setLineMapper(linemapper);
        return reader;
    

    @Bean
    public ItemWriter<UniqueIdMasterBean> writer()         
        JdbcBatchItemWriter<UniqueIdMasterBean> writer = new JdbcBatchItemWriter<>();
        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<UniqueIdMasterBean>());
        writer.setSql(insertQuery);     
        writer.setDataSource(mariaDb);
        return writer;
    

    @Bean
    public MasterProcessor masterProcessor() 
        return new MasterProcessor();
    

    @Value("$master.filePath")
    private Resource[] filePath;
    @Value("$master.insertQuery")
    private String insertQuery;
    @Value("$purered.filePath")
    private Resource[] pureredFilePath;
    @Value("$purered.insertQuery")
    private String pureredInsertQuery;
    @Value("$categoryList")
    private String categoryList;
    private Map<String,String> categoryMap;

    public Resource[] getPureredFilePath() 
        return pureredFilePath;
    

    public Resource[] getFilePath() 
        return filePath;
    

    public void setCategoryList(String categoryList) 
        this.categoryList = categoryList;
    

    /**
     * @return the clientTagsMap
     */
    public Map<String, String> getCategoryMap() 
        if(null == categoryMap)
            categoryMap = new HashMap<>();
            int count = 0;
            String current = "";
            String value = null;
            String key = null ;
            StringTokenizer tok = new StringTokenizer(categoryList, ",=");
            while (tok.hasMoreTokens()) 
                current = tok.nextToken();
                // the first token in the pair is the key
                if (count%(PCSConstants.KEY_LENGTH)==1)
                    value =  current;
                    categoryMap.put(key, value);
                else
                    // the second is the value
                    key = current;
                
                count++;
            
        
        return categoryMap;
    

谁能帮帮我。

【问题讨论】:

你的测试课上有这么多注解...你在哪里见过这种注解组合? 作业在 jobLauncherTestUtils 中自动装配。当您的上下文中有多个作业时,您需要手动设置 jobLauncherTestUtils。见***.com/a/36352437/5019386 Spring Batch JUnit test for multiple jobs的可能重复 【参考方案1】:

您可能需要手动配置JobLauncherTestUtils。 这看起来类似于这里的线程 Spring Batch JUnit test for multiple jobs

查看导致问题的JobLauncherTestUtils 的代码。

@Autowired
    public void setJob(Job job) 
        this.job = job;
    

【讨论】:

谢谢大家。我按照上述步骤解决了这个问题,并将@Primary 添加到我的一个 bean 方法中。

以上是关于没有可用的“org.springframework.batch.core.Job”类型的合格 bean:预期单个匹配 bean,但找到了 2:的主要内容,如果未能解决你的问题,请参考以下文章

没有可用的“org.springframework.batch.core.Job”类型的合格 bean:预期单个匹配 bean,但找到了 2:

为啥在尝试对整个 Spring Batch Job 进行单元测试时出现此错误?没有可用的“org.springframework.batch.core.Job”类型的合格bean

POM 丢失,没有可用的依赖信息

没有可用的“repository.Dao”类型的合格 bean

Spring集成错误“没有可用的输出通道或replyChannel标头”

没有实现 [org.springframework.beans.factory.xml.NamespaceHandler] 接口