Я нахожусь в настроении, чтобы написать короткую и основную статью сегодня. Мне действительно любопытно, как быстро я могу опубликовать это. Итак, начнем.
Этот пост о Corda Services (используется Corda версии 3.2
). Кто они такие? Как разработчик, который часто использует Spring, я бы сказал, что они похожи на Beans. Spring Beans может сделать больше, но на базовом уровне они очень похожи. В любом случае, давайте прекратим говорить о весне и сосредоточимся на Корде.
Минимум, который вам нужно знать
Сервисы Corda — это классы, внешние по отношению к потокам, которые в настоящее время могут вызываться только из исполняющего потока или из другой службы (которая, в свою очередь, вызывается потоком). Подобно subFlow
, они позволяют повторно использовать код, но должны использоваться по разным причинам. Например, набор функций запроса хранилища или инициирование trackBy
внутри узла. Это то, для чего я склонен пользоваться услугами в любом случае.
Сервисы Corda определяются с помощью аннотации @CordaService
вместе с расширением SingletonSerializeAsToken
. Как только это будет сделано, когда ваш Cordapp загружен и узел запускается, служба, которую вы только что определили, будет инициализирована:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@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
для получения состояний из хранилища узла.
Теперь он готов к использованию из ваших потоков или других служб, если это необходимо. Фрагмент ниже взят из одного из моих потоков:
1
|
private fun repository() = serviceHub.cordaService(MessageRepository:: class .java) |
serviceHub
доступен во всех потоках и обеспечивает функцию cordaService
. Для ввода требуется класс службы, которую вы пытаетесь получить. В этом случае MessageRepository
загружается.
Чуть-чуть больше информации
Это все, что вам нужно, чтобы начать пользоваться Corda Services. Но. Я дам вам немного больше информации, чтобы вы не повторяли те же ошибки, что и я.
Урок первый. При звонке на услугу из потока. Не вводите его внутрь конструктора потока. Вместо этого вызывайте его изнутри функции call
или любых других, использованных с этой точки. Если вы этого не сделаете, вы увидите следующее сообщение об ошибке:
1
|
java.lang.IllegalStateException: This can only be done after the flow has been started. |
Выше ошибка, которую вы получите при вызове потока из теста. Если вы звоните из RPC, вы получите что-то вроде этого:
1
2
|
Caused by: java.lang.reflect.InvocationTargetException: null Caused by: java.lang.IllegalStateException: This can only be done after the flow has been started. |
Вероятно, с длинной трассировкой стека в зависимости от выбранного веб-фреймворка.
Не совсем ясно, что внедрение службы в этот момент вызывает эти ошибки, и вы можете обнаружить, что они появляются по другим причинам. Но я думаю, что можно с уверенностью сказать, по крайней мере в Corda 3.2
, что вы не должны ничего делать внутри конструктора или во время инициализации потока.
Просто чтобы сделать это еще яснее, ниже приведен код, который сопровождал более ранний фрагмент кода, где я внедрил службу:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
@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
как угодно). Если вы этого не сделаете, служба не будет создана, и при попытке доступа к ней появится следующая ошибка:
1
|
Caused by: java.lang.IllegalArgumentException: Corda service com.lankydanblog.tutorial.services.MessageRepository does not exist |
Хотя в этой ситуации есть луч надежды … Маловероятно, что вы это сделаете. Потому что без экземпляра AppServiceHub
вы мало что можете сделать с собственным сервисом. У вас не будет доступа к хранилищу или другим встроенным службам. Итак, в конце дня этот урок немного бессмысленный, но я все же попал в эту ловушку …
Это все?
Блин, я думаю, что на самом деле я написал короткий пост на этот раз! Это хорошо или плохо? Я не уверен на 100% …
Во всяком случае, я очень стараюсь придумать еще несколько фрагментов информации. Но я не могу. Минимум, чтобы заставить Corda Service работать, действительно хорош и прост.
Тем не менее, за последние несколько недель я узнал, что есть некоторые очень интересные и полезные вещи, которые вы можете делать в сервисах, которые нельзя сделать в Flows. Это тема, которую я надеюсь охватить в какой-то момент!
Вывод
Сервисы Corda позволяют вам создавать классы, внешние по отношению к потокам, где вы можете логически группировать код, который не имеет прямого отношения к выполнению потока. Мой любимый способ использовать сервис — это сгруппировать функции запросов хранилища в один класс (почти то же, что я делал бы в мире Spring). Есть несколько шагов, которые необходимо предпринять, чтобы убедиться, что вы правильно создали свой сервис. Во-первых, аннотируйте его с помощью @CordaService
и @CordaService
SingletonSerializeAsToken
. Во-вторых, убедитесь, что вы правильно внедрили их в свои потоки, что практически везде, кроме конструктора (или init
в Kotlin). Наконец, не забудьте включить AppServiceHub
в конструктор службы. Как только вы сможете использовать сервисы Corda, вы сможете отделить код от ваших потоков. Это не только делает потоки короче, но и облегчает их понимание, увеличивая возможность повторного использования кода, на который вы потратили свое драгоценное время.
Код, используемый для этого поста, можно найти на моем GitHub . В этом хранилище есть еще много чего, чего не было в этом посте.
Если вы нашли этот пост полезным, вы можете подписаться на меня в Twitter на @LankyDanDev, чтобы не отставать от моих новых сообщений.
Опубликовано на Java Code Geeks с разрешения Дэна Ньютона, партнера нашей программы JCG . Смотреть оригинальную статью здесь: Corda Services 101
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |