2016-11-09 2 views
1

Смотрите ниже 1 обновлениеINJECT бобы в весенне-периодического считывания элемента

Я пытаюсь внедрить службу или DAO боб в моей весенней партии ItemReader. Однако введенная ссылка NULL. Я пробовал это с помощью @Autowire и явной конфигурации компонента в XML-файле.

Работа выполняется из приложения spring-mvc. Для этого элемента ItemReader требуется доступ к БД для загрузки списка идентификаторов для обработки. Читатель просматривает этот список, и ItemWriter вносит необходимые изменения в базу данных для каждого идентификатора, используя мои существующие Слои службы и DAO.

Вот моя конфигурация (определяется в отдельном файле пружинными batch.xml включены в web.xml после контекста файла XML-приложений.)

Кроме того, в этой версии я пытаюсь впрыснуть JobService в ItemReader с использованием конфигурации XML.

Общая проблема заключается в следующем: как вводить другие 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); 
    } 
} 

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

Есть ли способ поставить эти уродливые инициализации в конструкторе?

+0

Заявить job.service как singleton и wire to reader используя свойство-ref –

+0

Спасибо @Luca. Я изменил код в соответствии с вашим предложением. Затем я заметил, что проблема в том, что я вызываю свой DAO в конструкторе ItemReader. Я изменил вещи, чтобы инициализировать arrayList (из DAO) в методе read(); поэтому он сначала проверяет, если List == null, инициализирует его, если это так, а затем возвращает элементы. Но это кажется неудобным, потому что эта инициализация должна быть на конструкторе. Есть ли способ заставить его работать оттуда? Также, пожалуйста, ответьте на свой комментарий, чтобы я мог принять его! – tggm

ответ

1

Я хотел бы сделать следующее:

  • Autowire JobService
  • Сделать itemList и jobKey в 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); 
     } 
    } 
} 
+0

У меня была аналогичная проблема с нулевым указателем при доступе к autwired, обслуживаемому в моем читателе.Можете ли вы объяснить, почему мне нужно выполнить вызов службы из afterPropertiesSet вместо внутреннего чтения? Это работает для меня сейчас, но не знаю, почему. –

+0

Реализация InitializingBean на считывателе также, кажется, пропускает процессор и запись, если я также не реализую InitializingBean на этих шагах. Это ожидаемое поведение? –

+0

Ни в коем случае, ни то, что я когда-либо видел в прошлом. Должно быть что-то еще происходит. Я предполагаю, что ваш 'itemsList' пуст, поэтому этот шаг полагает, что у него нет работы. –

Смежные вопросы