company_banner

Не Spring Boot’ом единым: обзор альтернатив



    В настоящее время нет недостатка во фреймворках для создания микросервисов на Java и Kotlin. В статье рассматриваются следующие:
    Название Версия Год первого релиза Разработчик
    Helidon SE 1.1.1 2019 Oracle
    Ktor 1.2.1 2018 JetBrains
    Micronaut 1.1.3 2018 Object Computing
    Spring Boot 2.1.5 2014 Pivotal

    На их основе созданы четыре сервиса, которые могут взаимодействовать друг с другом посредством HTTP API с использованием паттерна Service Discovery, реализованного с помощью Consul. Таким образом, они формируют гетерогенную (на уровне фреймворков) микросервисную архитектуру (далее МСА):



    Определим набор требований к каждому сервису:

    • стек технологий:
      • JDK 12;
      • Kotlin;
      • Gradle (Kotlin DSL);
      • JUnit 5.

    • функциональность (HTTP API):
      • GET /application-info{?request-to=some-service-name}
        Возвращает некоторую базовую информация о микросервисе (название, фреймворк, год релиза фреймворка); при указании в параметре request-to названия одного из четырёх микросервисов к его HTTP API выполняется аналогичный запрос, возвращающий базовую информацию;
      • GET /application-info/logo
        Возвращает изображение.

    • реализация:
      • настройка с использованием конфигурационного файла;
      • использование внедрения зависимостей;
      • тесты, проверяющие работоспособность HTTP API.

    • МСА:
      • использование паттерна Service Discovery (регистрация в Consul, обращение к HTTP API другого микросервиса по его названию с использованием клиентской балансировки нагрузки);
      • формирование артефакта uber-JAR.


    Далее рассматривается реализация микросервиса на каждом из фреймворков и сравниваются параметры полученных приложений.

    Helidon service


    Каркас разработки был создан в Oracle для внутреннего использования, впоследствии став open-source’ным. Существует две модели разработки на основе этого фреймворка: Standard Edition (SE) и MicroProfile (MP). В обоих случаях сервис будет обычной Java SE программой. Подробнее о различиях можно узнать на этой странице.

    Если коротко, то Helidon MP — это одна из реализаций Eclipse MicroProfile, что даёт возможность использования множества API, как ранее известных разработчикам на Java EE (например, JAX-RS, CDI), так и более новых (Health Check, Metrics, Fault Tolerance и т. д.). В варианте Helidon SE разработчики руководствовались принципом “No magic”, что выражается, в частности, в меньшем количестве или полном отсутствии аннотаций, необходимых для создания приложения.

    Для разработки микросервиса выбран Helidon SE. Помимо прочего в нём отсутствуют средства для реализации Dependency Injection, поэтому для внедрения зависимостей использован Koin. Далее приведён класс, содержащий main-метод. Для реализации Dependency Injection класс наследуется от KoinComponent. Сначала стартует Koin, далее инициализируются требуемые зависимости и вызывается метод startServer(), где создаётся объект типа WebServer, которому предварительно передаётся конфигурация приложения и настройка роутинга; после старта приложение регистрируется в Consul:

    object HelidonServiceApplication : KoinComponent {
    
       @JvmStatic
       fun main(args: Array<String>) {
           val startTime = System.currentTimeMillis()
           startKoin {
               modules(koinModule)
           }
    
           val applicationInfoService: ApplicationInfoService by inject()
           val consulClient: Consul by inject()
           val applicationInfoProperties: ApplicationInfoProperties by inject()
           val serviceName = applicationInfoProperties.name
    
           startServer(applicationInfoService, consulClient, serviceName, startTime)
       }
    }
    
    fun startServer(
       applicationInfoService: ApplicationInfoService,
       consulClient: Consul,
       serviceName: String,
       startTime: Long
    ): WebServer {
       val serverConfig = ServerConfiguration.create(Config.create().get("webserver"))
    
       val server: WebServer = WebServer
           .builder(createRouting(applicationInfoService))
           .config(serverConfig)
           .build()
    
       server.start().thenAccept { ws ->
           val durationInMillis = System.currentTimeMillis() - startTime
           log.info("Startup completed in $durationInMillis ms. Service running at: http://localhost:" + ws.port())
           // register in Consul
           consulClient.agentClient().register(createConsulRegistration(serviceName, ws.port()))
       }
    
       return server
    }

    Роутинг настраивается следующим образом:

    private fun createRouting(applicationInfoService: ApplicationInfoService) = Routing.builder()
       .register(JacksonSupport.create())
       .get("/application-info", Handler { req, res ->
           val requestTo: String? = req.queryParams()
               .first("request-to")
               .orElse(null)
    
           res
               .status(Http.ResponseStatus.create(200))
               .send(applicationInfoService.get(requestTo))
       })
       .get("/application-info/logo", Handler { req, res ->
           res.headers().contentType(MediaType.create("image", "png"))
           res
               .status(Http.ResponseStatus.create(200))
               .send(applicationInfoService.getLogo())
       })
       .error(Exception::class.java) { req, res, ex ->
           log.error("Exception:", ex)
           res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send()
       }
       .build()

    В приложении используется конфиг в формате HOCON:

    webserver {
     port: 8081
    }
    
    application-info {
     name: "helidon-service"
     framework {
       name: "Helidon SE"
       release-year: 2019
     }
    }

    Для конфигурирования возможно также использовать файлы в форматах JSON, YAML и properties (подробнее здесь).

    Ktor service


    Фреймворк написан на Kotlin. Новый проект можно создать несколькими способами: используя систему сборки, start.ktor.io или плагин к IntelliJ IDEA (подробнее здесь).

    Как и в Helidon SE, в Ktor отсутствует DI “из коробки”, поэтому перед стартом сервера с помощью Koin осуществляется внедрение зависимостей:

    val koinModule = module {
       single { ApplicationInfoService(get(), get()) }
       single { ApplicationInfoProperties() }
       single { ServiceClient(get()) }
       single { Consul.builder().withUrl("http://localhost:8500").build() }
    }
    
    fun main(args: Array<String>) {
       startKoin {
           modules(koinModule)
       }
       val server = embeddedServer(Netty, commandLineEnvironment(args))
       server.start(wait = true)
    }

    Необходимые приложению модули указываются в конфигурационном файле (возможно использование только формата HOCON; подробнее о конфигурировании Ktor-сервера здесь), содержимое которого представлено ниже:

    ktor {
     deployment {
       host = localhost
       port = 8082
       watch = [io.heterogeneousmicroservices.ktorservice]
     }
     application {
       modules = [io.heterogeneousmicroservices.ktorservice.module.KtorServiceApplicationModuleKt.module]
     }
    }
    
    application-info {
     name: "ktor-service"
     framework {
       name: "Ktor"
       release-year: 2018
     }

    В Ktor и Koin используется термин “модуль”, обладающий при этом разными значениями. В Koin модуль — это аналог контекста приложения в Spring Framework. Модуль Ktor — это определённая пользователем функция, которая принимает объект типа Application и может осуществлять конфигурирование пайплайна, установку фич (features), регистрацию роутов, обработку
    запросов и т. д.:

    fun Application.module() {
       val applicationInfoService: ApplicationInfoService by inject()
    
       if (!isTest()) {
           val consulClient: Consul by inject()
           registerInConsul(applicationInfoService.get(null).name, consulClient)
       }
    
       install(DefaultHeaders)
       install(Compression)
       install(CallLogging)
       install(ContentNegotiation) {
           jackson {}
       }
    
       routing {
           route("application-info") {
               get {
                   val requestTo: String? = call.parameters["request-to"]
                   call.respond(applicationInfoService.get(requestTo))
               }
               static {
                   resource("/logo", "logo.png")
               }
           }
       }
    }

    В этом фрагменте кода настраивается роутинг запросов, в частности, статический ресурс logo.png.

    Ktor-сервис может содержать фичи. Фича — это функциональность, встраиваемая в пайплайн запрос-ответ (DefaultHeaders, Compression и другие в примере кода выше). Возможна реализация собственных фич, например, ниже приведён код, имплементирующий паттерн Service Discovery в сочетании с клиентской балансировкой нагрузки на основе алгоритма Round-robin:

    class ConsulFeature(private val consulClient: Consul) {
    
       class Config {
           lateinit var consulClient: Consul
       }
    
       companion object Feature : HttpClientFeature<Config, ConsulFeature> {
    
           var serviceInstanceIndex: Int = 0
    
           override val key = AttributeKey<ConsulFeature>("ConsulFeature")
    
           override fun prepare(block: Config.() -> Unit) = ConsulFeature(Config().apply(block).consulClient)
    
           override fun install(feature: ConsulFeature, scope: HttpClient) {
               scope.requestPipeline.intercept(HttpRequestPipeline.Render) {
                   val serviceName = context.url.host
                   val serviceInstances =
                       feature.consulClient.healthClient().getHealthyServiceInstances(serviceName).response
                   val selectedInstance = serviceInstances[serviceInstanceIndex]
                   context.url.apply {
                       host = selectedInstance.service.address
                       port = selectedInstance.service.port
                   }
                   serviceInstanceIndex = (serviceInstanceIndex + 1) % serviceInstances.size
               }
           }
       }
    }

    Основная логика находится в методе install: во время фазы запроса Render (которая выполняется перед фазой Send) сначала определяется название вызываемого сервиса, далее у consulClient запрашивается список инстансов этого сервиса, после чего вызывается инстанс, определённый с помощью алгоритма Round-robin. Таким образом становится возможным следующий вызов:

    fun getApplicationInfo(serviceName: String): ApplicationInfo = runBlocking {
       httpClient.get<ApplicationInfo>("http://$serviceName/application-info")
    }


    Micronaut service


    Micronaut разрабатывается создателями фреймворка Grails и вдохновлён опытом построения сервисов с использованием Spring, Spring Boot и Grails. Фреймворк является полиглотом, поддерживая языки Java, Kotlin и Groovy; возможно, будет поддержка Scala. Внедрение зависимостей осуществляется на этапе компиляции, что приводит к меньшему потреблению памяти и более быстрому запуску приложения по сравнению со Spring Boot.

    Main-класс имеет следующий вид:

    object MicronautServiceApplication {
    
       @JvmStatic
       fun main(args: Array<String>) {
           Micronaut.build()
               .packages("io.heterogeneousmicroservices.micronautservice")
               .mainClass(MicronautServiceApplication.javaClass)
               .start()
       }
    }

    Некоторые компоненты приложения на основе Micronaut похожи на свои аналоги в приложении на Spring Boot, например, ниже приведён код контроллера:

    @Controller(
       value = "/application-info",
       consumes = [MediaType.APPLICATION_JSON],
       produces = [MediaType.APPLICATION_JSON]
    )
    class ApplicationInfoController(
       private val applicationInfoService: ApplicationInfoService
    ) {
    
       @Get
       fun get(requestTo: String?): ApplicationInfo = applicationInfoService.get(requestTo)
    
       @Get("/logo", produces = [MediaType.IMAGE_PNG])
       fun getLogo(): ByteArray = applicationInfoService.getLogo()
    }

    Поддержка Kotlin в Micronaut реализована на основе плагина компилятора kapt (подробнее здесь). Сборочный скрипт при этом конфигурируется так:

    plugins {
       ...
       kotlin("kapt")
       ...
    }
    
    dependencies {
       kapt("io.micronaut:micronaut-inject-java")
       ...
       kaptTest("io.micronaut:micronaut-inject-java")
       ...
    }

    Далее показано содержимое конфигурационного файла:

    micronaut:
     application:
       name: micronaut-service
     server:
       port: 8083
    
    consul:
     client:
       registration:
         enabled: true
    
    application-info:
     name: ${micronaut.application.name}
     framework:
       name: Micronaut
       release-year: 2018 

    Конфигурирование микросервиса возможно также файлами форматов JSON, properties и Groovy (подробнее здесь).

    Spring Boot service


    Фреймворк был создан с целью упростить разработку приложений, использующих экосистему Spring Framework. Это достигается посредством механизмов автоконфигурации при подключении библиотек. Ниже приведён код контроллера:

    @RestController
    @RequestMapping(path = ["application-info"], produces = [MediaType.APPLICATION_JSON_UTF8_VALUE])
    class ApplicationInfoController(
       private val applicationInfoService: ApplicationInfoService
    ) {
    
       @GetMapping
       fun get(@RequestParam("request-to") requestTo: String?): ApplicationInfo = applicationInfoService.get(requestTo)
    
       @GetMapping(path = ["/logo"], produces = [MediaType.IMAGE_PNG_VALUE])
       fun getLogo(): ByteArray = applicationInfoService.getLogo()
    }

    Микросервис конфигурируется файлом формата YAML:

    spring:
     application:
       name: spring-boot-service
    
    server:
     port: 8084
    
    application-info:
     name: ${spring.application.name}
     framework:
       name: Spring Boot
       release-year: 2014

    Также для конфигурирования возможно использовать файлы формата properties (подробнее здесь).

    Запуск


    Проект работает на JDK 12, хотя, вероятно, и на 11-й версии тоже, требуется только соответствующим образом поменять в сборочных скриптах параметр jvmTarget:

    withType<KotlinCompile> {
       kotlinOptions {
           jvmTarget = "12"
           ...
       }
    }

    Перед запуском микросервисов нужно установить Consul и запустить агент — например, так: consul agent -dev.

    Запуск микросервисов возможен из:

    • IDE
      Пользователи IntelliJ IDEA могут увидеть примерно следующее:

    • консоли
      Для этого нужно перейти в папку проекта и последовательно выполнить:

      java -jar helidon-service/build/libs/helidon-service-all.jar
      java -jar ktor-service/build/libs/ktor-service-all.jar
      java -jar micronaut-service/build/libs/micronaut-service-all.jar
      java -jar spring-boot-service/build/libs/spring-boot-service.jar


    После старта всех микросервисов на http://localhost:8500/ui/dc1/services вы увидите:



    Тестирование API


    В качестве примера приведены результаты тестирования API Helidon service:

    1. GET http://localhost:8081/application-info

      {
        "name": "helidon-service",
        "framework": {
      	"name": "Helidon SE",
      	"releaseYear": 2019
        },
        "requestedService": null
      }
    2. GET http://localhost:8081/application-info?request-to=ktor-service

      {
        "name": "helidon-service",
        "framework": {
      	"name": "Helidon SE",
      	"releaseYear": 2019
        },
        "requestedService": {
      	"name": "ktor-service",
      	"framework": {
      		"name": "Ktor",
        		"releaseYear": 2018
      	},
      	"requestedService": null
        }
      }
    3. GET http://localhost:8081/application-info/logo

      Возвращает изображение.

    Протестировать API произвольного микросервиса можно с помощью Postman (коллекция запросов), IntelliJ IDEA HTTP client (коллекция запросов), браузера или другого инструмента. В случае использования первых двух клиентов требуется указать порт вызываемого микросервиса в соответствующей переменной (в Postman она находится в меню коллекции -> Edit -> Variables, а в HTTP Client — в переменной среды, указываемой в этом файле), а при тестировании метода 2) API также нужно указать название запрашиваемого “под капотом” микросервиса. Ответы при этом будут аналогичны приведённым выше.

    Сравнение параметров приложений



    Размер артефакта


    C целью сохранения простоты настройки и запуска приложений в сборочных скриптах не были исключены какие-либо транзитивные зависимости, поэтому размер uber-JAR сервиса на Spring Boot значительно превышает размеры аналогов на других фреймворках (т. к. при использовании стартеров импортируются не только нужные зависимости; при желании размер можно существенно уменьшить):
    Микросервис Размер артефакта, Мбайт
    Helidon service 16,6
    Ktor service 20,9
    Micronaut service 16,5
    Spring Boot service 42,7


    Время запуска


    Время запуска каждого приложения непостоянно и попадает в некоторое “окно”; в таблице ниже приведено время запуска артефакта без указания каких-либо дополнительных параметров:
    Микросервис Время запуска, секунды
    Helidon service 2,2
    Ktor service 1,4
    Micronaut service 4,0
    Spring Boot service 10,2

    Стоит отметить, что если “почистить” приложение на Spring Boot от ненужных зависимостей и уделить внимание настройке запуска приложения (например, сканировать только нужные пакеты и использовать ленивую инициализацию бинов), то можно значительно сократить время запуска.

    Нагрузочное тестирование


    Для проведения тестирования были использованы Gatling и скрипт на Scala. Генератор нагрузки и тестируемый сервис были запущены на одной машине (Windows 10, четырёхъядерный процессор 3,2 ГГц, 24 Гбайт RAM, SSD). Порт этого сервиса указывается в Scala-скрипте.

    Для каждого микросервиса определяется:

    • минимальный объём heap-памяти (-Xmx), необходимый для запуска работоспособного (отвечающего на запросы) микросервиса
    • минимальный объём heap-памяти, необходимый для прохождения нагрузочного теста 50 пользователей * 1000 запросов
    • минимальный объём heap-памяти, необходимый для прохождения нагрузочного теста 500 пользователей * 1000 запросов

    Под прохождением нагрузочного теста понимается то, что микросервис ответил на все запросы за любое время.
    Микросервис Минимальный объём heap-памяти, Мбайт
    Для запуска сервиса Для нагрузки 50 * 1000 Для нагрузки 500 * 1000
    Helidon service 9 9 11
    Ktor service 11 11 13
    Micronaut service 13 13 17
    Spring Boot service 22 23 25

    Стоит заметить, что все микросервисы используют HTTP-сервер Netty.

    Заключение


    Поставленную задачу — создание простого сервиса с HTTP API и возможностью функционировать в МСА — удалось выполнить на всех рассматриваемых фреймворках. Пришло время подвести итоги и рассмотреть их плюсы и минусы.

    Helidоn

    Standard Edition
    • плюсы
      • параметры приложения
        По всем параметрам показал хорошие результаты;
      • “No magic”
        Фреймворк оправдал заявленный разработчиками принцип: для создания приложения потребовалась всего одна аннотация (@JvmStatic — для интеропа Java-Kotlin).
    • минусы
      • микрофреймворк
        Отсутствуют “из коробки” некоторые необходимые для промышленной разработки компоненты, например, внедрение зависимостей и реализация Service Discovery.

    MicroProfile
    Микросервис на этом фреймворке реализован не был, поэтому отмечу лишь пару известных мне пунктов:

    • плюсы
      • имплементация Eclipse MicroProfile
        По сути, MicroProfile — это Java EE, оптимизированная для МСА. Таким образом, во-первых, вы получаете доступ ко всему многообразию Java EE API, в том числе, разработанному специально для МСА, во-вторых, вы можете изменить имплементацию MicroProfile на любую другую (Open Liberty, WildFly Swarm и т. д.).
    • дополнительно
      • на MicroProfile Starter вы можете с нуля создать проект с нужными параметрами по аналогии с похожими инструментами для других фреймворков (например, Spring Initializr). На момент публикации статьи Helidon реализует MicroProfile 1.2, тогда как последняя версия спецификации — 3.0.


    Ktor

    • плюсы
      • легковесность
        Позволяет подключать только те функции, которые непосредственно нужны для выполнения поставленной задачи;
      • параметры приложения
        Хорошие результаты по всем параметрам.
    • минусы
      • “заточен” под Kotlin, то есть, разрабатывать на Java, вроде, можно, но не нужно;
      • микрофреймворк (см. аналогичный пункт для Helidon SE).
    • дополнительно
      С одной стороны, концепция разработки на фреймворке не входит в две наиболее популярных модели разработки на Java (Spring-подобную (Spring Boot/Micronaut) и Java EE/MicroProfile), что может привести к:

      • проблеме с поиском специалистов;
      • увеличению времени на выполнение задач по сравнению со Spring Boot из-за необходимости явного конфигурирования требуемой функциональности.

      С другой, непохожесть на “классические” Spring и Java EE позволяет взглянуть на процесс разработки под другим углом, возможно, более осознанно.


    Micronaut

    • плюсы
      • AOT
        Как ранее было отмечено, AOT позволяет уменьшить время старта и потребляемую приложением память по сравнению с аналогом на Spring Boot;
      • Spring-подобная модель разработки
        У программистов с опытом разработки на Spring не займёт много времени освоение этого фреймворка;
      • параметры приложения
        Хорошие результаты по всем параметрам;
      • полиглот
        Поддержка на уровне first-class citizen языков Java, Kotlin, Groovy; возможно, будет поддержка Scala. На мой взгляд, это может положительно повлиять на рост сообщества. К слову, на июнь 2019 Groovy в рейтинге популярности языков программирования TIOBE занимает 14-е место, взлетев с 60-го годом ранее, таким образом, находясь на почётном втором месте среди JVM-языков;
      • проект Micronaut for Spring позволяет в том числе изменить среду выполнения имеющегося Spring Boot приложения на Micronaut (с ограничениями).


    Spring Boot

    • плюсы
      • зрелость платформы и экосистема
        Фреймворк “на каждый день”. Для бОльшей части повседневных задач уже есть решение в парадигме программирования Spring, т. е. привычным для многих программистов способом. Разработку упрощают концепции стартеров и автоконфигураций;
      • наличие большого количества специалистов на рынке труда, а также значительная база знаний (включая документацию и ответы на Stack Overflow);
      • перспектива
        Думаю, многие согласятся, что в ближайшем будущем Spring останется лидирующим каркасом разработки.
    • минусы
      • параметры приложения
        Приложение на этом фреймворке не было в числе лидеров, однако некоторые параметры, как было отмечено ранее, могут быть оптимизированы самостоятельно. Также стоит вспомнить о наличии находящегося в активной разработке проекта Spring Fu, использование которого позволяет уменьшить эти параметры.

    Также можно выделить общие проблемы, связанные с новыми фреймворками и отсутствующие у Spring Boot:

    • менее развитая экосистема;
    • малое количество специалистов с опытом работы с этими технологиями;
    • большее время выполнения задач;
    • неясные перспективы.

    Рассмотренные фреймворки принадлежат к разным весовым категориям: Helidon SE и Ktor — это микрофреймворки, Spring Boot — full-stack фреймворк, Micronaut, скорее, тоже full-stack; ещё одна категория — MicroProfile (например, Helidon MP). В микрофреймворках функциональность ограничена, что может замедлить выполнение задач; для уточнения возможности реализации той или иной функциональности на основе какого-либо каркаса разработки рекомендую ознакомиться с его документацией.

    Не берусь судить о том, “выстрелит” ли тот или иной фреймворк в ближайшем будущем, поэтому, на мой взгляд, пока лучше продолжить наблюдать за развитием событий, используя имеющийся каркас разработки для решения рабочих задач.

    В то же время, как было показано в статье, новые фреймворки выигрывают у Spring Boot по рассмотренным параметрам полученных приложений. Если для какого-то из ваших микросервисов критически важны какие-либо из этих параметров, то, возможно, стоит обратить внимание на фреймворки, показавшие по ним лучшие результаты. Однако, не стоит забывать, что Spring Boot, во-первых, продолжает совершенствоваться, во-вторых, имеет огромную экосистему и с ним знакомы значительное количество Java-программистов. Есть и другие фреймворки, не освещённые в настоящей статье: Javalin, Quarkus и т. д.

    С кодом проекта вы можете ознакомиться на GitHub. Благодарю за внимание!

    P.S.: Спасибо artglorin за помощь в подготовке статьи.
    Райффайзенбанк
    285,29
    Развеиваем мифы об IT в банках
    Поделиться публикацией

    Комментарии 14

      0

      Спасибо. Помимо времени запуска интересно еще было бы посмотреть время компиляции, а также возможность и время "горячей перезагрузки".


      Micronaut на самом деле удивил по времени загрузки в 4сек. На сайте уверяют, что оно должно быть вообще моментальным, ибо вся сборка делается на этапе компиляции, а не в рантайме. Возможно это из-за Котлина.


      микрофреймворк
      Отсутствуют “из коробки” некоторые необходимые для промышленной разработки компоненты, например, внедрение зависимостей и реализация Service Discovery.

      Ну, во-первых, в Helidon Microprofile все-же реализован CDI. А во-вторых, по большей части это скорей плюс, а не минус. Делает только то, что должен делать, не завязывает на конкретную технологию и дает полную свободу выбора.

        0
        По поводу микрофреймворка: этот пункт относится только к Helidon SE, но не к Helidon MP, в котором действительно есть CDI. В Helidon SE его нет, поэтому для DI нужно использовать third-party библиотеку, в данном случае — Koin.
          0
          в данный момент набрасываю сервис на quarkus.io
          старт с CDI (поиск и инициализация всех бинов) занимает 1с

          ну и приложение посложнее чем в примерах =)
            0
            Тоже была идея включить в проект микросервис на Quarkus. Но, к сожалению, он пока не поддерживает JDK 12, что было одним из требований.
              0
              Уточню, приложение работает под JDK 12, но сборка (Maven, Gradle) падает.
              0

              Jetty+Guice стартует за полсекунды, причем эти полсекунды отъедает именно Guice. Но это голый контейнер. Попробуйте добавить Hibernate и время взлетит сразу до 10с.

            0
            Я бы включил в список Apache Camel. Отличное решение сделать по-быстрому, практически не программируя. Но, да есть особенность — кривая обучения дальше «hello world» иногда крутовата, в зависимости от компонентов.
              0
              С удовольствием реализовал бы сервис на Apache Camel (и других фреймворках) будь чуть больше свободного времени :)
                +1
                Camel все-таки ортогонален к сабжу. Набор для роутинга и интеграции всех возможных протоколов между собой.
                И его можно пользовать в связке с любым пунктом из сабжа.
                0
                ...Ktor — это микрофреймворки

                Думаю Ktor можно спокойно отнести к full-stack
                  0
                  Почему?
                    0
                    На нем также можно реализовывать фронтовую часть, тем более с шаблонизаторами. Есть свой starter как у Spring Boot, где тоже немало всего для полноценного сервиса. Возможно не до конца понял разделение фрейморов. Спасибо
                  0

                  not_bad в Spring 5 появилось сканирование аннотаций на этапе компиляции: https://stackoverflow.com/questions/25981158/spring-component-annotation-compile-time-scan
                  Подключается добавлением org.springframework:spring-context-indexer
                  Можно еще с ней проверить время старта Spring-boot.

                    0
                    Спасибо, посмотрю.

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое