Причины не прямого написания сервлета для создания 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 позволит вам сэкономить много времени, что вы, вероятно, потратите на повторное использование колеса и еще больше времени, когда вам придется обучать кого-то, чтобы справиться с вашим удивительным пользовательским кодом.