image

Небольшое вступление


Spark — это просто чудесный микрофреймворк для создания веб-приложений на джаве без особых усилий.  Spark стремится к простоте и обеспечивает только минимальный набор функций. Тем не менее он предоставляет все необходимое для создания веб-приложения, которые поместятся в несколько строк кода. С синтаксисом, вдохновленным Sinatra, код выглядит очень чистым.

Давайте начнем со вездесущого хеллоуворлда.

Создаём новый проект и импортируем Spark. Лично я использую maven для управления зависимостями.

Добавляем в pom.xml.

<dependency>
    <groupId>com.sparkjava</groupId>
    <artifactId>spark-core</artifactId>
    <version>2.6.0</version>
</dependency>

Теперь приступим непосредственно к «хеллоу ворлду».

import static spark.Spark.*;

public class Main {
    public static void main(String[] args) {
        get("/hello", (req, res) -> "Hello, World!");
    }
}

Вот и всё. Всё настолько просто!

Теперь spark прослушивает GET запросы на /hello. Всякий раз, когда мы переходим на  localhost:4567/hello, вызывается метод handle(). Внутри него мы возвращаем объект, который должен быть отправлен клиенту (в этом случае «Hello World»).

Лично мое мнение, что данный код настолько лаконичный, что даже не требует пояснений.

Стоп-стоп. Что насчет запуска/остановки сервера?

  1. Остановка — надо всего лишь вызвать метод stop().
  2. Запуск — а вот здесь все интересно.  Сервер автоматически запускается, когда вы делаете что-то, что требует запуска сервера (я знаю что звучит действительно странно). Но можно запустить и вручную, вызвав метод init().

Поддержка шаблонизаторов


Хотел бы затронуть такую тему как шаблонизаторы. Спарк имеет большую нативную поддержку оных. А именно:

  • Velocity
  • Freemarker
  • Mustache
  • Handlebars
  • Jade
  • Thymeleaf
  • Pebble
  • Water
  • jTwig
  • Jinjava
  • Jetbrick

Для всех них есть «обёртки» от спарка. Для примера давайте рассмотрим мой любимый Freemarker.

Для начала давайте импортируем доп. зависимость.

 <dependency>
            <groupId>com.sparkjava</groupId>
            <artifactId>spark-template-freemarker</artifactId>
            <version>2.5.5</version>
        </dependency>

Создадим шаблон «hello.ftl» в директории src/main/resources.

<html>
<head>
</head>
<body>
    <h1>Hello, ${name}!</h1>
</body>
</html>

Теперь надо сконфигурировать freemarker дабы он искал шаблоны в ресурсах. Это всего лишь 4 строчки кода.

FreeMarkerEngine freeMarkerEngine = new FreeMarkerEngine();
Configuration freeMarkerConfiguration = new Configuration();
freeMarkerConfiguration.setTemplateLoader(new ClassTemplateLoader(Main.class, "/"));
freeMarkerEngine.setConfiguration(freeMarkerConfiguration);

Вот и всё, можно спокойно использовать фримаркер.

get("/", (request, response) -> {
        Map<String, Object> model = new HashMap<>();
        model.put("name", "Freemarker");
        return freeMarkerEngine.render(new ModelAndView(model, "hello.ftl"));
});



Почти полноценный проект


Давайте напишем, какой-то лёгкий, но достаточный что бы показать хотя бы малую часть возможностей спарка? Мне из того что можно реально быстро написать, пришел в голову только сокращатель ссылок. Что ж, начнем?

Надо добавить еще одну зависимость Google Guava. В итоге у нас получается 3 зависимости.

    <dependencies>
        <dependency>
            <groupId>com.sparkjava</groupId>
            <artifactId>spark-core</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>com.sparkjava</groupId>
            <artifactId>spark-template-freemarker</artifactId>
            <version>2.5.5</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.0</version>
        </dependency>

Нам Guava нужна, потому что в ней реализована хэш-функция Murmur3. Весь плюс в том что она достаточно сильна устойчива к коллизиям. Так же что бы не тратить лишнее время, мы будем все данные хранить только в переменных, без всяких бд и т.д.

Сделаем костяк программы.


staticFileLocation("/static");
get("/shortener", (request, response) -> {
});
get("/:url", (request, response) -> {
});

:url это параметр который можно достать через метод params(). К примеру:

get("/hello/:name", (request, response) -> {
    return "Hello: " + request.params(":name");
});

Что-то я отвлекся, продолжим.

Создадим коллекцию(Map) для хранения, настроим шаблонизатор(как я говорил freemarker мой любимый, так что будет именно он) и укажем спарку где у нас будут храниться статистические файлы. staticFiles.location("/static") укажет ему что файлы будут лежать в src/main/resources/static. К примеру файл /static/css/style.css будет доступен по адресу http://{host}:{port}/css/style.css. Если же вы хотите хранить файлы предположим в /var/www/public_html, тогда используем метод staticFiles.externalLocation("/var/www/public_html").

 ConcurrentHashMap<String, String> urls = new ConcurrentHashMap<String, String>();
        FreeMarkerEngine freeMarkerEngine = new FreeMarkerEngine();
        Configuration freemarkerConfiguration = new Configuration();
        freemarkerConfiguration.setTemplateLoader(new ClassTemplateLoader(Main.class, "/templates/"));
        freeMarkerEngine.setConfiguration(freemarkerConfiguration);
        staticFileLocation("/static");

Настроим перенаправление.

 get("/:url", (request, response) -> {
            if(urls.containsKey(request.url()))
                response.redirect(urls.get(request.url()));
            response.redirect("/");
            return null;
        });

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

Давайте поработаем с фронтендом, а то мы совсем про него забыли. Начнем с главной.
Здесь мы создадим простую минималистическую форму. И еще запихнем шрифтик Proxima Nova. Заигрался конечно… ну да ладно.

<!DOCTYPE html> 
<html lang="en" style="height:100%;">
<head> 
    <meta charset='utf-8'>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="main"> 
        <form action="/shortener" method="GET">
            <input type="text" id="input" name="url" autocomplete="off" autofocus size="44" maxlength="512" />
	 </form>
    </div>
</body>     
</html>

@font-face {
    font-family: Proxima Nova;
    src: url(pn.otf);
}
* {
    font-family: Proxima Nova;
    background: #2a2826;
    color: #9C9C9C;
    margin: 0;
    padding: 0;
}
body, html {
    height: 100%;

}
#main {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    font-size: 1.5em;

}
#input {
    border: none;
    outline:none;
    font-size: 1.5em;
}

В итоге все это добро выглядит так.



Теперь страница на которую будет выводится ссылка «shortener.ftl».


<!DOCTYPE html>
<html lang="en" style="height:100%;">
<head>
    <meta charset='utf-8'>
    <link rel="stylesheet" href="style.css">
</head>
<body>
<div id="main" style="text-align: center">
    ${url}
</div>
</body>
</html>

Итоговая структура проекта.



Что ж, дописываем последние строки. В итоге Main класс, выглядит так.

import com.google.common.hash.Hashing;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import spark.ModelAndView;
import spark.Request;
import spark.Response;
import spark.template.freemarker.FreeMarkerEngine;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static spark.Spark.*;

public class Main {
    public static void main(String[] args) {
        ConcurrentHashMap<String, String> urls = new ConcurrentHashMap<String, String>();
        FreeMarkerEngine freeMarkerEngine = new FreeMarkerEngine();
        Configuration freemarkerConfiguration = new Configuration();
        freemarkerConfiguration.setTemplateLoader(new ClassTemplateLoader(Main.class, "/templates/"));
        freeMarkerEngine.setConfiguration(freemarkerConfiguration);
        staticFileLocation("/static");
        get("/shortener", (request, response) -> {
            String shortURL = "http://localhost:4567/" +
                    Hashing.murmur3_32().hashString(request.queryParams("url"), StandardCharsets.UTF_8).toString();
            Map<String, Object> model = new HashMap<>();
            if(!urls.containsKey(shortURL)) {
                model.put("url", shortURL);
                urls.put(shortURL, request.queryParams("url"));
                return freeMarkerEngine.render(new ModelAndView(model, "shortener.ftl"));
            }
            model.put("url", shortURL);
            return freeMarkerEngine.render(new ModelAndView(model, "shortener.ftl"));
        });
        get("/:url", (request, response) -> {
            if(urls.containsKey(request.url()))
                response.redirect(urls.get(request.url()));
            response.redirect("/");
            return null;
        });
    }
}

Вот и всё. 41 строка кода и мы написали сокращатель ссылок.

Заключение


На этом моменте, я закончу эту немного затянувшуюся «Getting started» статью. Мне очень жаль что в рунете этот проект обошли стороной. Если вам понравится, я продолжу писать о Spark`е и раскрою больше его возможностей.

Ссылки


> Сайт проекта
> Исходные коды SparkJava

Комментарии (52)


  1. Crandel
    09.10.2017 16:08
    +2

    Интересно, как легко гуглить вопросы по этому микрофреймворку? Ведь есть еще Apache Spark, а Big Data сейчас в почете


    1. pmcode
      09.10.2017 17:05
      +1

      Гуглить по sparkjava. Да, трудно, пока собирал про него информацию измучался.


      1. Crandel
        09.10.2017 17:13

        Почему же разработчики не переименуют проект? Для таких микрофреймворков это не должно быть проблемой


        1. grossws
          10.10.2017 03:09

          Я, честно говоря, не помню, подходили ли Apache Spark PMC к товарищам из sparkjava, но PMC не сильно парится насчёт совпадения названия, т. к. существенно разные области и это не мешает трейдмарку Apache Spark.


          1. Crandel
            10.10.2017 09:34

            Я не думаю, что это будет каким-то образом мешать Apache Spark, но я сейчас работаю над проектом Apache Spark с Java API и при гуглении spark java мне этот фреймворк ниразу не попадался. Хотя может это гугл такой умный, фильтрует поиск для меня


            1. mat3 Автор
              10.10.2017 10:28

              Я гуглил spark web framework.


    1. Matvey-Kuk
      10.10.2017 01:20

      Cisco Spark, Chevrolet Spark…


      1. Crandel
        10.10.2017 09:36

        Не согласен, не пересекающиеся ниши, а вот сабж и Apache Spark — оба фреймворка имеют Java API


    1. eignatik
      10.10.2017 17:03

      Участвовал в двух проектах со спарком как-то. В целом не было проблемой поискать в гугле. Просто запросы писал поподробнее. На самом деле искать что-то по нему вполне можно)


  1. bromzh
    09.10.2017 16:28

    На сколько оно легковесно и что с поддержкой стандартов?
    Например, есть undertow, часть проекта WildFly (ex. JBoss). Jar весит около мегабайта, чистый сервер ест всего 4Мб хипа. Но самый большой плюс — поддержка стандартов (Servlet 3.1, JSR-356 для вебсокетов).


    1. AndreyRubankov
      09.10.2017 21:00
      +2

      Spark – это сахар поверх jetty: github.com/perwendel/spark/blob/master/pom.xml

      Но самый большой плюс — поддержка стандартов (Servlet 3.1, JSR-356 для вебсокетов).

      Servlet API – это крутой стандарт, но он уже монстроузорный :-(

      Servlet API – это не HTTP стандарт, это абстракция над гораздо большим количеством протоколов. С чистым Servlet API крайне неудобно работать. И над ним делают еще парочку абстракций, чтобы добавить удобства. А потом это все выливается в довольно медленный код и раздутый хип.

      Servlet API нужно омолаживать; его уже нужно чем-то заменить! Делать какой-то Java HTTP API.


      1. 3draven
        09.10.2017 22:54
        -9

        Бредишь? Очень удобная штука, главно врубиться.


        1. AndreyRubankov
          10.10.2017 10:27
          +3

          Чистый Servlet API – крайне неудобная вещь.

          • Нужно оверрайдить нужные http методы сервлетов (doGet, doPost, etc).
          • Нужно приводить ServletRequest в HttpServletRequest.
          • Нужно самому руками вычитывать энтити из InputStream и парсить их!!
          • Нужно так же делать сериализацию энтитей и писать в OutputStream!!

          Где же тут удобство?

          Фреймворки и дополнительные уровни абстракций появляются потому, что сервлеты в чистом виде – это боль и унижение.


          1. 3draven
            10.10.2017 13:08
            -6

            Точно бредишь :) Я на wildfly держу несколько проектов. Сериализация-десериализация автоматом. Я оперирую только объектами. Реализация методов для запросов — это ООП, родной. Там же наследование и переопределение… для тех кто понимает конечно. С Request я напрямую вообще дел не имею, ибо JSON-API уже изобрели давно.


            1. Miraage
              10.10.2017 15:30

              Ну вообще круто!!! /s


  1. pmcode
    09.10.2017 16:59

    Мне Jooby больше нравится. Если смотреть на API, то он Spark и не отличишь, но у него: DI (via Guice) из коробки, в разы лучше документация, очень гибкая концепция модулей, поддержка роутинга в стиле JAX-RS, несколько серверов (Netty, Jetty, Undertow) на выбор и другие плюшки. Жалко комьюнити пока не очень большое, Spark поболее раскручен, конечно.

    Хотел бы затронуть такую тему как шаблонизаторы. Спарк имеет большую нативную поддержку оных.

    А server-side rendering сейчас еще нужен? Как-то казалось что сейчас микрофреймворк это для REST сервиса или для SPA.


    1. j_wayne
      09.10.2017 17:34

      Конечно нужен. Я использовал sparkjava для небольшого инфраструктурного сервиса. SPA городить слишком жирно, вывести-то всего пару табличек. В целом, было несколько более трудоемко, по сравнению с большими фреймворками.


    1. worldmind
      09.10.2017 22:06

      Порльзуясь случаем спрошу — а что сейчас в джава мире для клиент-сайда популярно?
      Хотелось бы что-то вроде GWT, чтобы делать интерфейс из компонентов и не думать о джаваскрипте, GWT актуален ещё?


      1. staticlab
        09.10.2017 22:22
        +2

        Вроде бы Vaadin сейчас в моде.


        1. nile1
          10.10.2017 08:27

          Vaadin медленный, слишком много логики обрабатывается на стороне сервера.
          Нынче в моде React/VueJS/Angular и прочие client-side JavaScript фреймворки.


          1. staticlab
            10.10.2017 10:57

            А в JavaScript-фреймворках всё обрабатывается и тормозит на клиенте :3 И вообще, автор хотел обойтись без JS.


      1. voopr
        10.10.2017 08:35

        Если кратко, то нет, не актуален.
        На мой взгляд это такой Delphi в java мире. Legacy думаю еще достаточно много, но вот начинать на нем что-то новое на мой взгляд не надо.


        1. worldmind
          10.10.2017 09:28

          А аналогов не появилось?


          1. injecto
            10.10.2017 09:40

            Разве что какие-нибудь Kotlin или Scala.js, но они, конечно, без библиотеки виджетов, насколько я знаю. Такой себе урезанный аналог.


        1. konsoletyper
          10.10.2017 14:45

          начинать на нем что-то новое на мой взгляд не надо

          А можно услышать какие-нибудь аргументы? Просто интересно


          1. justboris
            10.10.2017 15:21

            Потому что он безнадежно отстал от прогресса.


            Например Element.querySelector() уже более 5 лет доступен в браузерах, а в GWT его так и не поддержали: https://stackoverflow.com/questions/2406002/find-an-element-by-css-selector-in-gwt/3164919


            И такие флешбеки при разработке на GWT встречаются регулярно. Хочется заиспользовать какую-нибудь браузерную особенность, а нет – GWT о ней не знает и вызвать не дает. Можно выкрутиться через JSNI, но зачем тогда вообще тащить GWT.


            В соседних комментах предлагают Kotlin или Scala.js, в них с актуальностью все получше.


            1. konsoletyper
              10.10.2017 15:25
              +1

              Например Element.querySelector() уже более 5 лет доступен в браузерах, а в GWT его так и не поддержали

              А зачем его вызывать вручную? Я всегда думал, что выбор элементов за меня сделает библиотека виджетов. А сделает она это через JSNI или через overlay-тип — мне какая разница? Конечно, иногда надо напрямую сделать что-то с DOM, но это настолько редко требуется, что кусочек JSNI не проблема написать. Зато остальные 99% кода пишутся на Java без проблем.


              но зачем тогда вообще тащить GWT

              Причина одна, но для кого-то может быть крайне весомой — возможность писать клиентский код на Java.


      1. Throwable
        10.10.2017 11:40
        +1

        Клиент-сайд состоит из двух частей: фреймворка и библиотеки виджетов. В качестве фреймворка довольно давно использую GWT + GQuery + RestyGWT. Доволен. Из печалек: медленная компиляция и неудобный дебаг в superdevmode. В качестве библиотеки виджетов можно использовать GWTBootstrap, GWT-Material, gwt-polymer-elements, любую CSS-based библиотеку, или даже интегрировать практически любой bullshit.js.


        Про упомянутый Vaadin: да, подтормаживает (постоянная синхронизация состояния виджетов с сервером), спорно годится для интернет-проектов, но для энтерпрайзных админок и дэшбоардов — самое то. При помощи GWT можно использовать весь widgetset Vaadin-a на клиентской стороне без использования серверной части, что значительно разгоняет UI. Кроме того, есть полностью js-ный Vaadin Elements. Из печалек: из пресловутый Vaading Grid тормозит гораздо больше на клиенте, чем на сервере.


        P.S. Хочу попробовать подергать Kotlin.js. Кстати, если уж о котлине заговорили, то вот фреймворк со схожим функционалом: https://github.com/Kotlin/ktor


      1. webkumo
        10.10.2017 14:02

        GWT актуален ещё

        Зачем вам этот тормозной монстр? Имхо проще отдельного фронтэндера иметь, чем работать с GWT...


        1. 3draven
          10.10.2017 14:39

          Удваиваю ненужность GWT и прочих. У меня коллега интерфейсы шпарит махом на jquery чистом. Я только REST подгоняю, который JSON выдает и принимает, и все.


        1. worldmind
          10.10.2017 18:15

          Ответил тут.


      1. konsoletyper
        10.10.2017 14:35
        +2

        Пользуясь случаем, попиарю свой проект: http://teavm.org/
        Поддерживаются Java, Scala, Kotlin, есть Angular-образный фреймворк в комплекте


        1. worldmind
          10.10.2017 18:12

          А насколько он аналогичен? GWT в теории хорош тем что:
          1. Не надо писать на джаваскрипте
          2. Можно делать гуй на высоком уровне — есть готовые компоненты


          1. konsoletyper
            10.10.2017 18:27
            +1

            1. В TeaVM не надо писать на JavaScript, для того он и создан
            2. Есть возможность делать гуй на шаблонах (с биндингом, перерисовкой только изменившегося DOM). Пишите шаблоны под bootstrap — будут и компоненты. Можно создавать свои компоненты для шаблонизатора, можно биндиться к JavaScript-компонентам (как и в GWT). Но, разумеется, т.к. мой проект пока не нашёл широкого применения, под него есть только небольшой набор стандартных компонентов.


        1. Throwable
          11.10.2017 17:10

          Я думал, Вы забросили этот проект. Ан-нет, уже даже достаточно юзабельная версия! На выходных попробую. Из пожеланий: добавить автоматический генератор врапперов к JS-библиотекам из TypeScript на DefinetlyTyped.


      1. foal
        10.10.2017 16:15
        +1

        Вполне актуален. Последняя версия поддерживает практически все фичи из Java 8. Java 9 как компилятор обещают скоро, фичи из Java 9 чуть позже. Как и колега, иcпользую GWT + GQuery + Gin + RestyGWT, хотя и посматриваю на Dagger ‡ и RxJava. В общем, доволен как слон :)


  1. nwalker
    09.10.2017 18:18
    +1

    Мне всегда было интересно, как создатели таких проектов предполагают жить без reverse URL resolution.


    1. AndreyRubankov
      09.10.2017 21:09

      reverse URL resolution.
      А не могли бы вы рассказать, что это за зверь такой?
      ps: за 5+ лет еще не приходилось сталкиваться с этим термином; может эта фича не столь и нужная?


      1. staticlab
        09.10.2017 22:02
        +1

        Это когда фреймворк даёт возможность сгенерировать URL для ссылки, сославшись на соответствующий роут по имени и передав нужные параметры.


        Например, в Рельсах:


        link_to "Мой профиль", @profile   # @profile — переменная с экземпляром класса Profile

        генерирует:


        <a href="/profiles/1">Мой профиль</a>


        1. AndreyRubankov
          10.10.2017 10:14

          Звучит, как удобная фича с удобством для поддержки – меняешь роут, меняется и реверс урл.

          Но для того, чтобы она работала, нужно чтобы фреймворк на себя брал очень много обязанностей, как минимум фреймворку нужно, чтобы он знал все его роуты по именам; а чтобы это все корректно работало, то еще и по параметрам (PathParams, QueryParams, etc), т.е. сам фреймворк уже становится раздутым и сложным.

          Часто в этом даже нету необходимости: роуты практически никогда не меняются после релиза. А если меняются, то на старый вешается редирект, чтобы не сломать ничего.

          Это без сомнения крутая фича, но в микрофреймворке она избыточна. Если нужно этот функционал можно прикрутить через стороннюю библиотеку.


        1. j_wayne
          10.10.2017 11:12

          В JVM-фреймворках с этим, к сожалению, печально.
          Искал JVM замену рельсам.
          Rails-alike фреймворки существуют, но почему то они не переняли некоторых удобных деталей.
          Эти самые URL, миграции, routes.rb с resources :foo, only: [:index, :show], лейауты. Разве что грусть-тоска по asset pipeline отпадает сама собой с появлением webpack и подобных.
          jruby on rails сначала показались находкой. Но jruby быстро разочаровала страшными тормозами, очень сильная деградация в зависимости от количества библиотек/кода. TDD-ить невозможно. Прелоадеры глючат. Боль короче)


          1. beduin01
            10.10.2017 14:46
            +1

            Посмотрите vibed.org


            1. j_wayne
              10.10.2017 15:00

              Спасибо. Забавно конечно, но не JVM (есть 3rd party библиотека, ради которой весь сыр-бор). А если устраивать межпроцессное взаимодействие а-ля микросервисы, проще взять те же рельсы и не мучиться. Да и не все привычные фичи в vibe.d есть. Не нашел route resources и миграций например.


          1. rraderio
            10.10.2017 16:27
            -1

            1. j_wayne
              10.10.2017 16:51

              Да, и почему-то роуты описываются индивидуально.
              Нельзя взять и объявить resources :users скажем (такая фича есть разве что в grails, но до лаконичности рельсовой версии ей далеко).
              Зачем это нужно? Проще менять роуты.
              Database Evolutions не предоставляет никакого обобщенного DSL, нужно писать сырой SQL.
              Да, контроля больше. Но с другой стороны, в 95% случаях мне хватало и рельсового DSL, а если уж не хватает, ничего не мешает (почти — автоотката все же не будет) написать специфичный сырой SQL.
              Не покидает ощущение недоделанности. При всех недостатках рельсов, у них есть основная идея — удобство разработчика (да, я понимаю, зачастую в ущерб каким-то другим вещам). И вот эту идею в JVM-фреймворках реализуют, на мой взгляд, не в полной мере.

              P.S. я разрабатываю и на RoR и на Java, т считаю, что RoR в JVM можно назвать лишь ее же но на jruby. Однако мне она не подошла — см. коммент выше.


              1. rraderio
                10.10.2017 17:28

                Зачем это нужно? Проще менять роуты.
                Ну а в Play есть автокомплит для роутов и они проверяются во время компиляции.
                Database Evolutions
                Можно взять Liquibase или другую библиотеку


      1. nwalker
        09.10.2017 22:35

        Я так и не нашел какого-то единого устоявшегося термина, но да, это возможность сгенерировать ссылку, исходя из обработчика или идентификатора роута и параметров.


        Пример из рельсов несколько чересчур магический и высокоуровневый, но суть верно передает.


  1. wert_lex
    09.10.2017 21:00

    Я понимаю, что это сильно за пределами вводной статьи, но это какой-то очень уж сферический пример. Поэтому у меня вопросы:


    1. как это все работает, когда тело метода handle() требует асинхронных операций. В базу, например сходить. И, поскольку Java многопоточная, то как обстоят дела с конкурентным доступом к одному и тому же request/response из разных потоков.
    2. как использовать композицию? Например, накрутить кастомную авторизацию, чтобы сбегать в базу и найти пользователя по сессии.


    1. akamensky
      10.10.2017 06:20

      Я вот как раз такими же вопросами задался некоторое время назад и из этого родилось вот такое чудовище, там точно так же как и в экспрессе можно сделать чтобы несколько handlers отработали в определенном порядке.


  1. rraderio
    10.10.2017 16:21
    +1

    Хотел бы затронуть такую тему как шаблонизаторы. Спарк имеет большую нативную поддержку оных
    А Rocker поддерживается?
    github.com/fizzed/rocker


  1. VladlenBronislav
    11.10.2017 15:18

    Вкратце, можно ли объяснить:
    1. Можно ли обойтись без Guava?
    2. В чем необходимость использования «хэш-функция Murmur3»?
    3. Можно ли Guava заменить на коллекцию из cuncerrent?
    Спасибо за овтеты.


    1. mat3 Автор
      11.10.2017 16:38

      1. Вполне
      2.

      Нам Guava нужна, потому что в ней реализована хэш-функция Murmur3. Весь плюс в том что она достаточно сильна устойчива к коллизиям.
      . Мы используем её для сокращение ссылки.
      3. Я и так не использую коллекции из гуавы