我正在使用Spring boot编写一个Spring Batch,并且我需要根据条件在两个不同的表中进行编写,因此我尝试CompositeItemWriter
,但是在调用该批处理时,不会调用编写器。
这是我的作业配置类。
@Configuration
public class JobConfiguration {
...
...
...
@Bean
public JdbcCursorItemReader<Notification> reader() {
JdbcCursorItemReader<Notification> reader = new JdbcCursorItemReader<Notification>();
reader.setDataSource(dataSource);
...
...
reader.setRowMapper(new BeanPropertyRowMapper<>(Notification.class));
return reader;
}
@Bean
public NotificationItemProcessor notificatonProcessor() {
return new NotificationItemProcessor();
}
@Bean
public JdbcBatchItemWriter<Notification> updateWriter() {
JdbcBatchItemWriter<Notification> writer = new JdbcBatchItemWriter<Notification>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Notification>());
...
writer.setDataSource(dataSource);
return writer;
}
/**
* Composite Exchange Writer
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
@SuppressWarnings("unchecked")
@Bean
public CompositeItemWriter<Notification> compositeExchangeWriter() throws InstantiationException, IllegalAccessException {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put(ExchangeRouter.INSERT_EXCHANGE_FOR_NOTIFICATION.getActionName(), exchangeWorkflowWriter());
map.put(ExchangeRouter.INSERT_EXCHANGE_FOR_PACK.getActionName(), exchangeWriter());
map.put(ExchangeRouter.DO_NOTHING.getActionName(), doNothing());
return new CompositeItemWriterBuilder(map, ExchangeWriterRouterClassifier.class).build();
}
@Bean
public JdbcBatchItemWriter<Notification> exchangeWorkflowWriter() {
JdbcBatchItemWriter<Notification> writer = new JdbcBatchItemWriter<Notification>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Notification>());
writer.setSql(" INSERT INTO SOME TABLE..");
writer.setDataSource(dataSource);
return writer;
}
@Bean
public JdbcBatchItemWriter<Notification> exchangeWriter() {
JdbcBatchItemWriter<Notification> writer = new JdbcBatchItemWriter<Notification>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Notification>());
writer.setSql("INSERT INTO SOME OTHER TABLE.");
writer.setDataSource(dataSource);
return writer;
}
@Bean
public ItemWriter<Document> doNothing() {
return new DummyWriter();
}
@Bean
public Job generatePdf(JobCompletionNotificationListener listener) throws InstantiationException, IllegalAccessException {
return jobBuilderFactory.get("generatePdf")
.incrementer(new RunIdIncrementer())
.flow(treatStock())
.end()
.build();
}
@Bean
public Step treatStock() throws InstantiationException, IllegalAccessException {
return stepBuilderFactory.get("treatStock")
.<Notification, Notification>chunk(1)
.reader(reader())
.processor(notificatonProcessor())
.writer(compositeExchangeWriter())
.writer(updateWriter())
.build();
}
}
CompositeItemWriter.java
public class CompositeItemWriterBuilder extends CompositeItemBuilder<CompositeItemWriter> {
public CompositeItemWriterBuilder(HashMap<String, Object> matcherMap, Class<?> routerDelegate) throws InstantiationException, IllegalAccessException {
BackToBackPatternClassifier classif = new BackToBackPatternClassifier();
classif.setRouterDelegate(routerDelegate.newInstance());
classif.setMatcherMap(matcherMap);
ClassifierCompositeItemWriter classifier = new ClassifierCompositeItemWriter();
classifier.setClassifier(classif);
this.delegates.add(classifier);
}
public CompositeItemWriterBuilder(List<Object> delegates) {
this.delegates = delegates;
}
@Override
protected Class<?> getCompositeItem() {
return CompositeItemWriter.class;
}
}
CompositeItemBuiler.java
public abstract class CompositeItemBuilder<T> {
protected List<Object> delegates = new ArrayList<Object>();
@SuppressWarnings("unchecked")
public T build() throws InstantiationException, IllegalAccessException {
Object compositeItem = getCompositeItem().newInstance();
Method setDelegates = ReflectionUtils.findMethod(compositeItem.getClass(), "setDelegates", List.class);
ReflectionUtils.invokeMethod(setDelegates,compositeItem, delegates);
return (T) compositeItem;
}
abstract protected Class<?> getCompositeItem();
}
ExchangeWriterRouterClassifier .java(未调用分类方法)
public class ExchangeWriterRouterClassifier {
@Classifier
public String classify(Notification notification) {
return notification.getExchangesWorkflow().getRouter().getActionName();
}
}
Spring如何调用Classifier? 我想念什么吗?
答案 0 :(得分:1)
我正在尝试使用CompositeItemWriter,但是当我调用该批处理时,不会调用writer。
问题出在您的步骤定义中:
@Bean
public Step treatStock() throws InstantiationException, IllegalAccessException {
return stepBuilderFactory.get("treatStock")
.<Notification, Notification>chunk(1)
.reader(reader())
.processor(notificatonProcessor())
.writer(compositeExchangeWriter())
.writer(updateWriter())
.build();
}
您两次调用writer()
方法,因此updateWriter()
将覆盖compositeExchangeWriter()
。您需要使用复合编写器作为参数调用一次该方法,您已经在该方法上设置了委托编写器。
作为使用复合编写器的注意事项,如果委托未实现ItemStream
接口,则需要确保将其注册为流。此处的更多详细信息:https://docs.spring.io/spring-batch/4.0.x/reference/html/readersAndWriters.html#delegatePatternAndRegistering
Spring如何调用分类器?
正确配置ClassifierCompositeItemWriter
后,Spring Batch将在每个项目上调用分类器,以确定要使用的编写者,然后调用适当的编写器来编写项目。
在您的配置中,ClassifierCompositeItemWriter
在此处配置不正确:
@SuppressWarnings("unchecked")
public T build() throws InstantiationException, IllegalAccessException {
Object compositeItem = getCompositeItem().newInstance();
Method setDelegates = ReflectionUtils.findMethod(compositeItem.getClass(), "setDelegates", List.class);
ReflectionUtils.invokeMethod(setDelegates,compositeItem, delegates);
return (T) compositeItem;
}
我不会使用反射来设置委托。问题是您期望方法compositeExchangeWriter
注册一个ClassifierCompositeItemWriter
,但其返回类型为CompositeItemWriter
。因此,复合编写器不被视为分类器。
您可以在此处找到如何使用ClassifierCompositeItemWriter
的示例:https://github.com/spring-projects/spring-batch/blob/master/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/ClassifierCompositeItemWriterTests.java#L44