我有一个非常标准的MVC设置,包括用于我的DAO层的Spring Data JPA存储库,一个处理Transactional问题和实现业务逻辑的Service层,以及一个包含一些可爱的基于REST的JSON端点的视图层。
我的问题是围绕Java 8 Stream
批量采用这个可爱的架构:如果我的所有DAO都返回Stream
,我的服务会返回相同的Stream
s(但是事务工作),我的视图处理并处理这些Stream
,然后当我的视图开始处理我的Stream
内的模型对象时,服务层创建的事务将具有已经关闭。如果基础数据存储尚未实现我的所有模型对象(毕竟它是Stream
,尽可能懒惰),那么我的视图将在尝试访问事务之外的新结果时出错。以前这不是一个问题,因为我会将结果完全呈现为一个列表 - 但现在我们已经进入了Stream
s的新世界。
那么,处理这个问题的最佳方法是什么?完全将服务层内的结果实现为List并将其交还?让View层将Service层交给一个完成块,以便在事务内部进行进一步的处理吗?
感谢您的帮助!
答案 0 :(得分:3)
在思考这个问题时,我决定尝试在我的问题中提到的完成块解决方案。我的所有服务方法现在都有一个结果转换器作为它们的最终参数,它接受Stream of Model对象并将其转换为View层需要/请求的任何结果类型。我很高兴地报告它有点像魅力,并且有一些很好的副作用。
这是我的服务基类:
public class ReadOnlyServiceImpl<MODEL extends AbstractSyncableEntity, DAO extends AbstractSyncableDAO<MODEL>> implements ReadOnlyService<MODEL> {
@Autowired
protected DAO entityDAO;
protected <S> S resultsTransformer(Supplier<Stream<MODEL>> resultsSupplier, Function<Stream<MODEL>, S> resultsTransform) {
try (Stream<MODEL> results = resultsSupplier.get()) {
return resultsTransform.apply(results);
}
}
@Override
@Transactional(readOnly = true)
public <S> S getAll(Function<Stream<MODEL>, S> resultsTransform) {
return resultsTransformer(entityDAO::findAll, resultsTransform);
}
}
这里的resultsTransformer
方法温和提醒子类不要忘记try-with-resources模式。
这是一个调用服务基类的控制器示例:
public abstract class AbstractReadOnlyController<MODEL extends AbstractSyncableEntity,
DTO extends AbstractSyncableDTOV2,
SERVICE extends ReadOnlyService<MODEL>>
{
@Autowired
protected SERVICE entityService;
protected Function<MODEL, DTO> modelToDTO;
protected AbstractReadOnlyController(Function<MODEL, DTO> modelToDTO) {
this.modelToDTO = modelToDTO;
}
protected List<DTO> modelStreamToDTOList(Stream<MODEL> s) {
return s.map(modelToDTO).collect(Collectors.toList());
}
// Read All
protected List<DTO> getAll(Optional<String> lastUpdate)
{
if (!lastUpdate.isPresent()) {
return entityService.getAll(this::modelStreamToDTOList);
} else {
Date since = new TimeUtility(lastUpdate.get()).getTime();
return entityService.getAllUpdatedSince(since, this::modelStreamToDTOList);
}
}
}
我认为让控制器通过Java 8 lambda规定服务的返回类型是非常巧妙地使用泛型。虽然我很难看到Controller直接返回Service调用的结果,但我很欣赏这段代码的紧密和富有表现力。
我认为这是尝试批量切换到Java 8 Streams的净积极因素。希望这可以帮助那些有类似问题的人。