不直接编写Servlet以创建REST API的原因

在我目前的公司中,我们正在开始一个新项目,该项目将是Java中的REST API,部署在像Tomcat这样的servlet容器中。 在我之前使用REST框架(如JAX-RS和Jersey,JBOSS REST Easy,Spring MVC)的经验中,我知道使用类似于直接编写Servlet来处理请求的框架的一些优点。

(当然我们知道所提到的框架仍然使用Servlets)

我发现很难说服他们。 因为他们建议编写servlet,认为它对性能更好(可能是这种情况,但我认为使用其中一个框架的开销对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); } 

使用servlet,您至少需要这样的东西:

在web.xml中映射每个servlet的url(在Servlet 3.0中不需要):

  UsersServlet test.UsersServlet   UsersServlet /users  

然后在servlet类中:

 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) 适应性 。 上述框架允许您轻松地向应用程序添加function,否则您将需要手动执行,例如使用多个媒体类型输入和输出。 例如,根据accept标头,使服务返回xml或json或任何其他服务。 像SpringMVC和Jersey这样的框架可以很容易地为您的请求和响应配置序列化器/反序列化器。

3) REST最佳实践 。 通常,这些框架是基于对REST API遵循的最佳实践的充分理解而构建的,并且基于REST体系结构的标准进行定义,这使得构建可靠且标准的符合标准的应用程序变得更加容易。 另一方面,Servlets为您提供了如何处理请求/响应的高度自由,以至于您很难意识到您根本不是RESTfull。

任何其他?

让我用我的答案扮演魔鬼的拥护者。

首先,您不需要将servlet添加到web.xml文件中。 Servlets 3.0允许您使用注释 。

其次,这些框架确实对性能产生了重大影响。 请参阅这些基准

第三,你可以在servlet中使用GSON ,它比Jackson快(在Spring和Jersey中默认使用)。 这可以让您获得更高的性能,特别是考虑到性能对您的要求至关重要。

最后,如果您关注样板文件,请将您在servlet中编写的代码放在某个实用程序类中,并从多个servlet中使用它。 当你(像大多数人一样)可能会使用它的一小部分function时,这会超过框架的巨大负荷。

首先,我会考虑使用两个具有“Hello World”servlet的应用程序来设置一个简单的测试 – 一个使用纯servlet,一个使用Spring MVC或Apache CXF或您选择的框架。 然后进行性能测试以certificate(希望)性能影响是微不足道的。

此外,序列化程序和反序列化程序是一个很好的例子,但这些框架中可用的拦截器/filter模式对其他东西也非常有用:

  • 认证/安全
  • 如果需要,记录原始请求
  • 标题和内容转换可以与业务逻辑分开

此外,还有一些工具可以插入到这些框架中,这些工具将生成文档(WADLs / WSDLs / Enunciate)和客户端类库。 还有一些测试库可用于针对众所周知的框架生成自动化测试。

我过去常常重新发明轮子。 但它不再有意义(如果有的话)。

几个月前我发表评论说我是针对RES MVC框架使用的纯Servlet 3.0解决方案。

经过一段时间的使用,我确认了我的选择!

我试图安装jackson和其他框架,但它需要更多的工作,而不是编写额外的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; } 

也许这些框架有一个你绝对需要的function,但对我而言应该是值得的额外lib的麻烦。

法国作家Antoine de Saint Exupery说:

“没有更多的东西可以实现完美,但是当没有任何东西可以拿走时”。

我拿走jackson来接近它:-)

(是的,我不得不承认,我使用的是GSON,但它是一个小jar子,不需要任何配置)。

对我来说,使用Spring MVC的真正优势是提高了生产力。 如果您需要一个真正定制的应用程序,从头开始编写所有内容都是有意义的。 虽然创建没有框架的新东西可能很酷,但是当它变得更大时,你将面临已经被数百名该死的好开发者解决的问题。 使用Spring MVC将为您节省大量时间,您可能会浪费重新发明轮子,甚至更多时间需要培训某人来处理您的真棒自定义代码。