将bean注入弹簧批项目阅读器

时间:2016-11-09 17:36:01

标签: java spring-batch autowired

请参阅下面的1更新

我试图将一个Service或DAO bean注入我的spring-batch ItemReader。但是注入的引用是NULL。我在XML文件中使用@Autowire和显式bean配置尝试了这个。

这项工作是从spring-mvc应用程序运行的。此ItemReader需要数据库访问才能加载要处理的ID列表。读者遍历此列表,ItemWriter使用我现有的服务和DAO层对每个ID在数据库上进行必要的更改。

这是我的配置(它是在应用程序上下文XML文件之后的web.xml中包含的单独的spring-batch.xml文件中定义的。)

此外,在此版本中,我尝试使用XML配置将JobService bean注入ItemReader。

这里的一般问题是:如何将其他DAO和/或服务注入项目读者和作者?

    

<beans:bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
    <beans:property name="dataSource" ref="dataSourceJNDI" />
    <beans:property name="transactionManager" ref="transactionManager" />
    <beans:property name="databaseType" value="mysql" />
</beans:bean>

<beans:bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
    <beans:property name="jobRepository" ref="jobRepository" />
</beans:bean>

<beans:bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />

<beans:bean id="myItemReader" class="my.MyItemReader" scope="step">
    <beans:property name="jobService">
        <beans:bean class="my.JobService"></beans:bean>
    </beans:property>
</beans:bean>

<job id="assignLeadBatch" restartable="false" job-repository="jobRepository">
    <step id="step1">
        <tasklet transaction-manager="dbOpsTransactionManager">
            <chunk reader="myItemReader" writer="myItemWriter" commit-interval="10" />
        </tasklet>
    </step>
</job>

<beans:bean class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
    <beans:property name="jobRegistry" ref="jobRegistry" />
</beans:bean>

ItemReader:

@Scope(value = "step", proxyMode = ScopedProxyMode.INTERFACES)
@Component
public class MyItemReader implements ItemReader<Integer> {

    JobService jobService;

    private List<Integer> itemsList;

    @Autowired
    public AssignLeadsJobItemReader(@Value("#{jobParameters['jobKey']}") final String jobKey) {

        MyJob alj = jobService.loadByKey(jobKey);

        itemsList = new ArrayList<AssignLeadsJobItem>();

        for(Integer i : myJob.getIdList()) {            
            itemsList.add(i);
        }
    }

    @Override
    public Integer read(){
        if(itemsList == null || itemsList.size() == 0) {
            return null;
        } else {
            return itemsList.remove(0);
        }
    }

    public JobService getJobService() {
        return jobService;
    }

    public void setJobService(JobService jobService) {
        this.jobService = jobService;
    }
}

工作服务:

@Service
@Transactional
public class JobService {
    @Autowired
    protected JobDAO jobDao;

    @Autowired
    protected SpringBatchService springBatchService;

    public JobExecution startJob(String jobName, String jobKey) {    
            // Defined in a different Class without transactions.
            return springBatchService.startJob("job_name", jobKey);
    }

    public MyJob loadByKey(String jobKey) {
            return jobDao.loadByKey(jobKey);
    }
}

更新1 我注意到该错误是由于调用ItemReader构造函数上的引用引起的。我这样更改了代码:

@Scope(value = "step", proxyMode = ScopedProxyMode.INTERFACES)
@Component
public class MyItemReader implements ItemReader<Integer> {
    private JobService jobService;
    private List<Integer> itemsList;
    private String jobKey;

    @Autowired
    public MyItemReader(@Value("#{jobParameters['jobKey']}") final String jobKey) {
        this.jobKey = jobKey;
        this.itemsList = null;
    }

    @Override
    public Integer read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        // ugly ugly ugly
        if (itemsList == null) {
            itemsList = new ArrayList<Integer>();

            MyJob jobData = jobService.loadByKey(jobKey);

            for (Integer i : jobData.getIdList()) {
                itemsList.add(i);
            }
        }

        if (itemsList.isEmpty()) {
            return null;
        } else {
            return itemsList.remove(0);
        }
    }
}

有没有办法在构造函数中放置那个丑陋的初始化?

1 个答案:

答案 0 :(得分:1)

我会做以下事情:

  • 自动装配JobService
  • itemListjobKey设为final类变量
  • 使用InitializingBean界面填充列表

现在您的读者会看起来像这样:

@Scope(value = "step", proxyMode = ScopedProxyMode.INTERFACES)
@Component
public class MyItemReader implements ItemReader<Integer>, InitializingBean {

    private final List<Integer> itemsList = new ArrayList<AssignLeadsJobItem>();

    @Autowired
    private JobService jobService;

    private final String jobKey;

    @Autowired
    public MyItemReader(@Value("#{jobParameters['jobKey']}") final String jobKey) {
        this.jobKey = jobKey;
    }

    @Override
    public Integer read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        if(itemsList.size() == 0) {
            return null;
        } else {
            return itemsList.remove(0);
        }
    }

    @Override
    public void afterPropertiesSet() {
        MyJob myJob = jobService.loadByKey(jobKey);
        for(Integer id : myJob.getIdList()) {            
            itemsList.add(id);
        }
    }
}