我正在将Spring Boot从1.4.2迁移到2.0.0,其中还包括将Spring批处理从3.0.7迁移到4.0.0,当我尝试使用新Spring运行它时看起来批处理不再有效批量版本。
当我尝试调试时,我发现批处理尝试从batch_job_execution_context获取数据时出现问题。
我可以看到从数据库获取数据工作正常,但新版本的批处理无法解析数据库数据
{ “地图”:[{ “条目”:[{ “串”:[ “名称”, “”]},{ “串”:[ “发送者”, “”]},{ “字符串”: [ “ID”, “”]},{ “串”:[ “NAV”, “”]},{ “串”:[ “创建”,140418]}]}]}
出现此错误:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_OBJECT), expected VALUE_STRING: need JSON String that contains type id (for subtype of java.lang.Object) at [Source: (ByteArrayInputStream); line: 1, column: 9] (through reference chain: java.util.HashMap["map"])
我发现当我删除所有批处理元数据表并从头开始重新创建它们时,批处理似乎再次起作用。看起来元数据JSON格式已更改为此
{ “名称”: “”, “发送者”: “145844”, “ID”: “”, “NAV”: “”, “创建”: “160909”}
我不想删除旧数据以使其重新运行,所以有什么方法可以解决这个问题吗?
是否有其他人试图进行此升级?很高兴知道是否还有其他一些我可能没有注意到的突破性变化。
由于
答案 0 :(得分:2)
基于上述迈克尔的回答,此代码块为我扩展了默认配置-我不得不将序列化器连接到JobRepository.class和JobExplorer.class:
@Configuration
@EnableBatchProcessing
MyBatchConfigurer extends DefaultBatchConfigurer {
private final DataSource dataSource;
@Autowired
public BatchConfiguration(final DataSource dataSource) throws Exception {
this.dataSource = dataSource;
}
@Bean
ExecutionContextSerializer getSerializer() {
return new XStreamExecutionContextStringSerializer();
}
@Override
protected JobRepository createJobRepository() throws Exception {
final JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setSerializer(getSerializer());
factory.setTransactionManager(getTransactionManager());
factory.afterPropertiesSet();
return factory.getObject();
}
@Override
protected JobExplorer createJobExplorer() throws Exception {
final JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
jobExplorerFactoryBean.setDataSource(dataSource);
jobExplorerFactoryBean.setSerializer(getSerializer());
jobExplorerFactoryBean.afterPropertiesSet();
return jobExplorerFactoryBean.getObject();
}
}
答案 1 :(得分:1)
在Spring Batch 4之前,ExecutionContext
的默认序列化机制是通过XStream。现在它默认使用Jackson,不与旧的序列化格式兼容。我们仍然可以使用旧版本(XStreamExecutionContextStringSerializer
),但您需要通过实施BatchConfigurer
并覆盖JobRepositoryFactoryBean
中的配置来自行配置。
对于记录,这与此问题有关:https://jira.spring.io/browse/BATCH-2575。
答案 2 :(得分:0)
在@anotherdave和@ michael-minella的解决方案中,您还可以使用以下类的实例替换普通的XStreamExecutionContextStringSerializer
。反序列化时,它接受两种格式,然后序列化为新格式。
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.batch.core.repository.ExecutionContextSerializer;
import org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer;
import org.springframework.batch.core.repository.dao.XStreamExecutionContextStringSerializer;
/**
* Enables Spring Batch 4 to read both ExecutionContext entries written by ealier versions and the Spring 5 format. Entries are
* written in Spring 5 format.
*/
@SuppressWarnings("deprecation")
class XStreamOrJackson2ExecutionContextSerializer implements ExecutionContextSerializer {
private final XStreamExecutionContextStringSerializer xStream = new XStreamExecutionContextStringSerializer();
private final Jackson2ExecutionContextStringSerializer jackson = new Jackson2ExecutionContextStringSerializer();
public XStreamOrJackson2ExecutionContextSerializer() throws Exception {
xStream.afterPropertiesSet();
}
// The caller closes the stream; and the decoration by ensureMarkSupported does not need any cleanup.
@SuppressWarnings("resource")
@Override
public Map<String, Object> deserialize(InputStream inputStream) throws IOException {
InputStream repeatableInputStream = ensureMarkSupported(inputStream);
repeatableInputStream.mark(Integer.MAX_VALUE);
try {
return jackson.deserialize(repeatableInputStream);
} catch (JsonProcessingException e) {
repeatableInputStream.reset();
return xStream.deserialize(repeatableInputStream);
}
}
private static InputStream ensureMarkSupported(InputStream in) {
return in.markSupported() ? in : new BufferedInputStream(in);
}
@Override
public void serialize(Map<String, Object> object, OutputStream outputStream) throws IOException {
jackson.serialize(object, outputStream);
}
}