Комментарии 12
У меня похожий подход.
Есть микросервис в котором как правило три модуля. Core - содержит Dto, enum-ы и т.п., Client - реализация API через разные имплементации транспорта или их нюансов и собственно Service - наша микросервис. Т.к. все микросервисы пишутся на Java, то модуль Core и Client задействуются максимально. Весьма удобно.
Модуль client это реализация API, которая вызывает сервисный код, или уже готовый клиент к микросервису?
Мы пытались делать REST-клиент, как стартер, поставляемый с микросервисом, но позже отказались от этой идеи. Версии спринга могут различаться, усложняется миграция на новую версию. Поэтому пришли к выводу, что нужно поставлять только интерфейсы для создания и клиента, и серверного АПИ для реализации
Это уже готовый клиент, который принимает-возвращает DTO-шки из Core. Реализовываем его на Java 11 (хотя сам сервис на 17ой) на базе HttpClient - ни какого spring, из зависимостей только jacskon и интерфейсы логеров. Он удобен тем, что можно делать и асинхронные вызовы и обычные.
Сам клиент потом в других сервисах объявляем как бин в каком-нибудь BeanConfiguration классе. Дополнительно во всех клиентах и сервисах договорились о едином наборе исключений (оформлены отдельной либой). Сделали OperationNotPermitedException, EntityNotFoundExceprion, ExternalServiceException и т.п. - весьма удобно и единообразно.
Я вижу в создании таких клиентов одну большую проблему - огромное количество типового, шаблонного кода, который приходится писать вручную. И тут нужно либо смириться, либо написать библиотеку с оберткой для клиентов (и описанием исключений возможно), либо переходить на генерацию клиентов по swagger. Помимо этого, удобно использовать аннотации spring boot 3 для создания клиентов на основе интерфейсов
Все что можно вынести в абстракции или библиотеки (если код общий для многих), мы стараемся выносить (ибо не SOLID-но), но вы правы - писать код клиентов то еще удовольствие. Но у нас и специфика "специфичная", т.к. вариативность развертывания продукта заставляет делать странные для многих вещи) Например, есть сервис журналирования событий который может принимать события как по http rest api так и через kafka.. Там, где не нужна отказоустойчивость и минимум ресурсов - работаем по http с одним инстансом сервисов, где-то с несколькими через Netflix Eureka, а где-то через kafka (регистрация) + http (получение). Написание клиента с нужными имплементациями интерфейсов (data recorder, data provider) позволяет гибко собирать проект под разные потребности без лишних заморочек. Сервисы использующие клиента просто на основе своей конфигурации создают нужный бин с нужной имплементацией общего клиентского интерфейса скрывая от сервиса то, как оно там работает внутри.
Может когда-нибудь и найду силы написать про это пару статей. Как написать сервер на микросервисной архитектуре способный эффективно работать как в высокопроизводительном кластере так и на Orange Pi :-D
Отличное решение!
Я предпочитаю также разбивать на модули, но только мой client это ваш client + core
В этом клиенте генерю feign клиенты используя swagger.json, а потом кому надо просто подключают клиента с уже готовым кодом для интеграции
Чуть-чуть не понял почему бы не публиковать библиотеку в maven-репозиторий (при необходимости приватный) вместо многомолульнвх проектов?
Так вероятность перерости в ядро монолита сиильно ниже
Можете рассказать по авторизации: Должна ли быть авторизация между микросервисами? Как микросервисы узнают, что запрос пришёл от валидного другого микросервиса, а не хакера? Как прокидываются данные по учетке пользователя?
Про авторизацию в микросервисах это тема отдельной статьи, и универсального рецепта не существует. Тут прежде всего стоит исходить из проекта и корпоративной архитектуры.
Как правило, в систему должен приходить уже авторизованный запрос, а за саму авторизацию отвечает отдельный микросервис, гейтвей или даже целая система. Да и видов авторизации пользователей может быть одновременно несколько: логин/пароль, jwt-токен, ldap, сертификат, двухфакторка и т.д.
После авторизации информацию о пользователе можно, например, сохранить в кэш. (Но в целом ничего страшного и запрашивать пользователя по идентефикатору при необходимости из сервиса, хранящего пользователя) Между микросервисами можно передавать идентефикатор пользователя, jwt-токен или идентефикатор временной записи в кеше, по которой мы можем получить полтщователя.
Кажется вопрос выше был не про авторизацию пользователя в сервисе, а авторизацию самого сервиса в межсервисном взаимодействии, т.е. сервис должен стучаться к другому сервису с конкретным выданным шифрованным ключом, чтобы принимающий сервис знал что к нему пришел не абы кто, а конкретный разрешенный сервис.
Решение проблем общего кода в микросервисах Spring Boot и не только