我今天想写一篇简短的要点文章。 我真的很好奇我能多快出版此书。 所以走吧
这篇文章是关于Corda Services(使用Corda 3.2
版)的。 这些是什么? 作为经常使用Spring的开发人员,我个人会说它们就像Beans。 Spring Beans可以做的还很多,但是从根本上讲,它们非常相似。 无论如何,让我们停止谈论Spring,而专注于Corda。
您需要知道的最低限度
Corda服务是Flow外部的类,当前只能从正在执行的Flow或其他服务(依次由Flow调用)中调用。 与subFlow
相似,它们允许您重用代码,但出于不同的原因应使用它们。 例如,库查询功能的集合或节点内的启动trackBy
。 这些都是我倾向于使用服务的方式。
Corda服务是通过使用@CordaService
批注以及扩展SingletonSerializeAsToken
来定义的。 完成此操作后,在加载Cordapp并启动节点时,将初始化您刚刚定义的服务:
@CordaService
class MessageRepository(private val serviceHub: AppServiceHub) : SingletonSerializeAsToken() {
private companion object {
val log = loggerFor()
}
init {
log.info("I am alive!")
}
fun findAll(pageSpec: PageSpecification): Vault.Page =
serviceHub.vaultService.queryBy(QueryCriteria.LinearStateQueryCriteria(), pageSpec)
}
serviceHub
提供对您所需一切的访问。 在此示例中,服务访问vaultService
以从节点的保管库检索状态。
现在可以根据需要在Flows或其他服务中使用它。 以下摘录摘自我的流程之一:
private fun repository() = serviceHub.cordaService(MessageRepository::class.java)
serviceHub
适用于所有流量,并提供cordaService
功能。 对于输入,它需要您尝试检索的服务的类。 在这种情况下,正在加载MessageRepository
。
一点点更多信息
这就是开始使用Corda Services所需的全部。 但。 我会为您提供更多信息,以便您不会犯一些与我相同的错误。
第一课。 从Flow调用服务时。 不要将其注入Flow的构造函数中。 而是从call
函数内部的任何位置或此后使用的任何其他函数调用它。 如果您不这样做,则会看到以下错误消息:
java.lang.IllegalStateException: This can only be done after the flow has been started.
上面是从测试调用Flow时会得到的错误。 如果从RPC调用,您将得到以下内容:
Caused by: java.lang.reflect.InvocationTargetException: null
Caused by: java.lang.IllegalStateException: This can only be done after the flow has been started.
根据您选择的Web框架,可能具有较长的stacktrace。
目前尚不清楚,在这一点上注入服务会导致这些错误,并且您可能会发现它们是由于其他原因而弹出的。 但是,至少在Corda 3.2
,我认为可以肯定地说,您不应在构造函数内部或Flow初始化期间执行任何操作。
为了使这一点更加清楚,下面是在较早的代码片段中插入了该服务的代码:
@InitiatingFlow
@StartableByRPC
class ReplyToMessagesFlow : FlowLogic<List>() {
@Suspendable
override fun call(): List {
return messages().map { reply(it) }
}
private fun messages() =
repository().findAll(PageSpecification(1, 100))
.states
.filter { it.state.data.recipient == ourIdentity }
private fun repository() = serviceHub.cordaService(MessageRepository::class.java)
@Suspendable
private fun reply(message: StateAndRef) = subFlow(SendMessageFlow(response(message), message))
private fun response(message: StateAndRef): MessageState {
val state = message.state.data
return state.copy(
contents = "Thanks for your message: ${state.contents}",
recipient = state.sender,
sender = state.recipient
)
}
}
如您所见,该服务被注入到repository
函数中,该函数又被call
。 按照这种结构,一切都将正常工作。
第二课。 不要忘记在服务的构造函数中包含serviceHub: AppServiceHub
(可以随意调用serviceHub
)。 如果不这样做,它将不会创建服务,并且在尝试访问该服务时会弹出以下错误消息:
Caused by: java.lang.IllegalArgumentException: Corda service com.lankydanblog.tutorial.services.MessageRepository does not exist
尽管在这种情况下有一线希望……您极不可能这样做。 因为没有AppServiceHub
实例,使用您自己的服务实际上无能为力。 您将无权访问Vault或任何其他内置服务。 所以,总的来说,这一课是毫无意义的,但我仍然陷入了这个陷阱……
这就是全部?
该死,我想我实际上曾经写过一篇短篇文章! 是好还是坏? 我不是100%确定...
无论如何,我非常努力地想想更多的信息片段。 但是我不能。 使Corda Service正常工作的最低限度的确很容易。
话虽这么说,在过去的几周中,我了解到您可以在Flows中无法完成的服务中完成一些非常酷而有用的工作。 我希望在某个时候涵盖这一主题!
结论
Corda Services允许您在Flow外部创建类,在此您可以在逻辑上对与Flow的执行没有直接关系的代码进行分组。 我最喜欢的使用服务的方法是将保管库查询功能分组到一个类中(这与我在Spring世界中所做的差不多)。 您需要采取一些步骤来确保正确创建服务。 首先,使用@CordaService
对其进行@CordaService
并扩展SingletonSerializeAsToken
。 其次,确保以正确的方式将它们注入到Flow中,除了构造函数(或Kotlin中的init
)以外,几乎在任何地方都没有。 最后,请记住在服务的构造函数中包含AppServiceHub
。 一旦能够使用Corda服务,就可以将代码从Flow中分离出来。 不仅使流程更短,而且使流程更易于理解,同时增加了您花费宝贵时间编写的代码的可重用性。
这篇文章使用的代码可以在我的GitHub上找到 。 该存储库中还有很多内容未包含在本文中。
如果您认为这篇文章有帮助,可以在Twitter上@LankyDanDev关注我,以跟上我的新文章。
翻译自: https://www.javacodegeeks.com/2018/08/corda-services-101.html