将 bean 注入 spring-批处理项 reader
Inject beans into spring-batch item reader
请参阅下面的 1 个更新
我正在尝试将服务或 DAO bean 注入到我的 spring-batch ItemReader 中。但是注入的引用是 NULL。我在 XML 文件中使用 @Autowire 和显式 bean 配置进行了尝试。
作业正在 运行 来自 spring-mvc 应用程序。此 ItemReader 需要数据库访问权限才能加载要处理的 ID 列表。 reader 遍历此列表,ItemWriter 使用我现有的服务和 DAO 层对数据库进行必要的更改。
这是我的配置(它是在应用程序上下文 XML 文件之后的 web.xml 中包含的单独 spring-batch.xml 文件中定义的。)
此外,在这个版本中,我尝试使用 XML 配置将 JobService bean 注入到 ItemReader 中。
这里的一般问题是:如何将其他 DAO 的 and/or 服务注入 Item Readers 和 Writers?
<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);
}
}
}
有没有办法把那个丑陋的初始化放在构造函数中?
我会执行以下操作:
- 自动装配
JobService
- 将
itemList
和jobKey
设为final
class变量
- 使用
InitializingBean
界面填充列表
现在您的 reader 看起来像这样:
@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);
}
}
}
请参阅下面的 1 个更新
我正在尝试将服务或 DAO bean 注入到我的 spring-batch ItemReader 中。但是注入的引用是 NULL。我在 XML 文件中使用 @Autowire 和显式 bean 配置进行了尝试。
作业正在 运行 来自 spring-mvc 应用程序。此 ItemReader 需要数据库访问权限才能加载要处理的 ID 列表。 reader 遍历此列表,ItemWriter 使用我现有的服务和 DAO 层对数据库进行必要的更改。
这是我的配置(它是在应用程序上下文 XML 文件之后的 web.xml 中包含的单独 spring-batch.xml 文件中定义的。)
此外,在这个版本中,我尝试使用 XML 配置将 JobService bean 注入到 ItemReader 中。
这里的一般问题是:如何将其他 DAO 的 and/or 服务注入 Item Readers 和 Writers?
<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);
}
}
}
有没有办法把那个丑陋的初始化放在构造函数中?
我会执行以下操作:
- 自动装配
JobService
- 将
itemList
和jobKey
设为final
class变量 - 使用
InitializingBean
界面填充列表
现在您的 reader 看起来像这样:
@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);
}
}
}