没有可用的“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
没有可用的“repository.Dao”类型的合格 bean
Spring集成错误“没有可用的输出通道或replyChannel标头”
没有实现 [org.springframework.beans.factory.xml.NamespaceHandler] 接口