Причины не прямого написания сервлета для создания REST API

В моей нынешней компании мы начинаем новый проект, который будет REST API в Java, развернутый в контейнере сервлетов, таком как Tomcat. В моем предыдущем опыте использования REST-фреймворков, таких как JAX-RS с Джерси, JBOSS REST Easy, Spring MVC. Я знаю, каковы некоторые преимущества использования фреймворка, например, над написанием непосредственно сервлетов для обработки запросов.

(Конечно, мы знаем, что упомянутые фреймворки по-прежнему используют сервлеты под обложками)

Мне трудно их убедить. Поскольку они предлагают писать сервлеты, думая, что это лучше для производительности (что может быть так, но я думаю, что накладные расходы на использование одной из этих фреймворков должны быть несущественными для REST API).

Вот мои причины:

1) Меньше шаблона и более сжатого кода (который проще поддерживать и тестировать). С помощью инфраструктуры JAX-RS или SpringMVC вы можете легко определить ресурс REST, написав методы с аннотациями, указывающими PATH ресурса, метод http для использования, параметры запроса и url, заголовки, такие как принятая кодировка и т.д.

Пример:

@GET
@Path("/users")
@Produces({MediaType.APPLICATION_JSON}) 
public UserList getUsers(@QueryParam("group") String group) {
    return userService.findUsers(group);
}

С сервлетами вам понадобится хотя бы что-то вроде этого:

Сопоставьте URL-адрес для каждого сервлета в web.xml(который не нужен в Servlet 3.0 и выше):

<servlet>
    <servlet-name>UsersServlet</servlet-name>
    <servlet-class>test.UsersServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>UsersServlet</servlet-name>
    <url-pattern>/users</url-pattern>
</servlet-mapping>

Затем внутри класса сервлета:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
    String group = request.getParameter("group");
    response.setContentType("application/json");
    PrintWriter out = response.getWriter();
    JsonSerializer someJsonSerializer = new JsonSerializer();
    String json = someJsonSerializer.serialize(userService.findUsers(group));      
    out.print(json);
}

2) Адаптивность. Указанные структуры позволяют легко добавлять в приложение функции, которые в противном случае вам нужно будет сделать это вручную, например, используя несколько входов и выходов мультимедийного типа. Например, создание службы для возврата xml или json или любого другого в зависимости от заголовка accept. Рамки, такие как SpringMVC и Jersey, очень упрощают настройку сериализаторов/десериализаторов для ваших запросов, ответов.

3) Лучшие методы REST. Обычно эти структуры основаны на надежном понимании лучших практик, которым должен следовать API REST, и определяются на основе стандартов архитектуры REST, что упрощает создание надежного и стандартного соответствующего приложения. С другой стороны, сервлеты дают вам такой высокий уровень свободы в том, как обрабатывать ваши запросы/ответы, что будет сложнее понять, что вы вообще не являетесь RESTfull.

Любые другие?

Ответы

Ответ 1

Позвольте мне сыграть защитника дьявола с моим ответом.

Во-первых, вам не нужно добавлять сервлеты в файл web.xml. Servlets 3.0 позволяет использовать annotations.

Во-вторых, на этих платформах наблюдается значительный успех. См. эти тесты

В-третьих, вы можете использовать GSON в сервлете, который быстрее, чем Джексон (используется по умолчанию в Spring и Джерси), Это дает вам еще большую производительность, особенно учитывая, что производительность имеет решающее значение для ваших требований.

Наконец, если вы обеспокоены шаблоном, поместите этот код, который вы написали внутри сервлета в каком-то классе утилиты, и используйте его из нескольких сервлетов. Это бьет, нося вокруг каркаса огромную нагрузку, когда вы (как и большинство людей), вероятно, будете использовать небольшую часть своей функциональности.

Ответ 2

Во-первых, я бы подумал о настройке простого теста с двумя приложениями, имеющими сервлет "Hello World" - один с чистыми сервлетами, один с Spring MVC или Apache CXF или ваш выбор. Затем запустите тест производительности, чтобы доказать (надеюсь), что поражение производительности незначительно.

Кроме того, сериализаторы и десериализаторы являются одним из хороших примеров, но шаблон перехватчика/фильтра, который доступен в этих рамках, очень полезен и для других вещей:

  • Аутентификация/Безопасность
  • Регистрация необработанных запросов при необходимости
  • Преобразования заголовков и содержимого, которые могут храниться отдельно от бизнес-логики

Кроме того, есть инструменты, которые подключаются к этим фреймворкам, которые будут генерировать документацию (WADLs/WSDLs/Enunciate) и библиотеки классов клиентов. Существуют также тестовые библиотеки, которые могут быть использованы для создания автоматических тестов для хорошо известных фреймворков.

Я тоже изобретал колесо. Но это уже не имеет смысла (если оно когда-либо было.)

Ответ 3

Серверные дни назад я добавил комментарий, говорящий, что я был для чистого решения Servlet 3.0 против использования инфраструктур RES MVC.

После нескольких месяцев использования я подтверждаю свой выбор!

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

Вот мой рабочий пример:

package example;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;

/**@WebServlet(name = "booking", urlPatterns = { "/api/v1/booking" })*/
public class BookingWs extends javax.servlet.http.HttpServlet {

    public static final Logger LOGGER = LoggerFactory.getLogger(BookingWs.class);

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        try {
            // Used for JSON handling
            Gson gson = new Gson(); 

            // De-serialize from request
            BookingRequest bRequest = gson.fromJson(request.getReader(), BookingRequest.class);

            // Do your business logic.
            BookingResponse bResponse = new BookingResponse();
            bResponse.request = bRequest;
            bResponse.accepted = "bar".equalsIgnoreCase(bRequest.type);
            bResponse.reason = bResponse.accepted ? "Welcome" : "Only bar table booking left";

            // Serialize and send response back;
            response.setContentType("application/json");
            PrintWriter pw = response.getWriter();
            gson.toJson(bResponse, pw);
        } catch (Throwable t) {
            response.setStatus(500);
            PrintWriter pw = response.getWriter();
            pw.write("{\"error\":\"" + t.getLocalizedMessage() + "\"}");
        }
    }
}

class BookingRequest{
    String type;
    int seats;
    String name;
    long requiredTimestamp;
}

class BookingResponse{
    BookingRequest request;
    boolean accepted;
    String reason;
}  

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

Как сказал французский автор Антуан де Сент-Экзюпери:

"Совершенство достигается не тогда, когда больше ничего добавить, а когда нет ничего, что нужно уйти".

Я забрал Джексона, чтобы приблизиться к нему: -)

(Да, я должен признать, я использовал GSON, но это небольшая банка, без какой-либо конфигурации).

Ответ 4

Для меня реальным преимуществом использования Spring MVC является увеличение производительности. Написание всего с нуля для настройки вещей имеет смысл, если вам нужно действительно настроенное приложение. Хотя может быть здорово создать что-то новое без каких-либо фреймворков, когда оно станет больше, вы столкнетесь с проблемами, которые уже были решены сотнями проклятых хороших разработчиков. Использование Spring MVC позволит вам сэкономить много времени, что вы, вероятно, потратите на повторное использование колеса и еще больше времени, когда вам придется обучать кого-то, чтобы справиться с вашим удивительным пользовательским кодом.