使用Kotlin Arrow自定义Spring Data存储库


Spring Data 提供了一个开箱即用的存储库实现。当这还不够时,其灵活的设计使其可以在不同的抽象级别扩展代码。
这篇文章展示了如何用我们自己的库替换默认的基础库,它在函数签名中使用Kotlin Arrow类型。
这篇文章的完整源代码可以在Github 上以 Maven 格式找到。
函数式编程正变得越来越流行。Spring 为Kotlin 语言提供了几个DSL。例如,Beans DSLRoutes DSL为 Spring 配置提供了更多功能的方法。在类型方面,Vavr(以前是 Javaslang)在 Java 中非常流行,而 Kotlin 有Arrow
下面是非常标准的起步架构:

  1. 具有两个GET映射的REST 控制器
  2. Spring Data JDBC 存储库接口

因为它是标准的,Spring 处理了很多管道,我们不需要编写很多代码。使用 Kotlin,它更加简洁:
class Person(@Id val id: Long, var name: String, var birthdate: LocalDate?)

interface PersonRepository : CrudRepository<Person, Long>

@RestController
class PersonController(private val repository: PersonRepository) {

    @GetMapping
    fun getAll(): Iterable<Person> = repository.findAll()

    @GetMapping("/{id}")
    fun getOne(@PathVariable id: Long) = repository.findById(id)
}

@SpringBootApplication
class SpringDataArrowApplication

fun main(args: Array<String>) {
    runApplication<SpringDataArrowApplication>(*args)
}

 
Arrow 带有四个不同的组件:
  1. Core
  2. FX:KotlinX 协程的功能效果框架伴侣
  3. Optics:对不可变数据的深度访问和转换
  4. Meta:用于 Kotlin 编译器插件的元编程库

 
更改Spring Data默认基础存储库
为了克服这个限制,我们可以利用另一个扩展点:更改默认的Spring Data基本存储库。
Spring Data 应用程序定义了接口,但实现需要来自某个地方。该框架默认提供一个,但可以用我们自己的来切换它。
下面是类图的概述:

详细的流程非常复杂:重要的部分是SimpleJdbcRepository类。Spring Data 将通过JdbcRepositoryFactoryBeanbean找到该类,创建它的一个新实例并在上下文中注册该实例。
让我们创建一个使用Either以下内容的基本存储库:
@NoRepositoryBean
interface ArrowRepository<T, ID> : Repository<T, ID> {              
    fun findById(id: Long): Either<Unit, T>                          
    fun findAll(): Iterable<T>                                       
}

class SimpleArrowRepository<T, ID>(                                 
    private val ops: JdbcAggregateOperations,
    private val entity: PersistentEntity<T, *>
) : ArrowRepository<T, ID> {

    override fun findById(id: Long) = Either.fromNullable(
        ops.findById(id, entity.type)                                
    )

    override fun findAll(): Iterable<T> = ops.findAll(entity.type)
}

我们需要注释主应用程序类@EnableJdbcRepositories并配置后者切换到这个基类。

@SpringBootApplication
@EnableJdbcRepositories(repositoryBaseClass = SimpleArrowRepository::class)
class SpringDataArrowApplication


为了简化客户端代码的使用,我们可以创建一个覆盖默认值的注释:

@EnableJdbcRepositories(repositoryBaseClass = SimpleArrowRepository::class)
annotation class EnableArrowRepositories

现在,用法很简单:

@SpringBootApplication
@EnableArrowRepositories
class SpringDataArrowApplication

此时,我们可以将 Arrow 存储库代码移动到其项目中,并将其分发给其他“客户端”项目使用。