当用户从资源 class 访问资源时,Rest 服务将如何执行?

How will a Rest Service execute when a user access a resource from resource class?

当多个用户从服务请求相同的资源方法时 class,服务器将如何处理请求?

如何为每个请求执行休息服务? rest服务的执行生命周期与servlet执行有何不同?

比如下面是Resource,在以下场景下会如何实例化和执行:

case 1: two users call the two different methods at a time

case 2: two users call the same method at a time

@Path("greet")
public class GreetingResource {

    @GET
    @Path("welcome/{username}")
    @Produces(MediaType.TEXT_PLAIN)
    public String sayWelcome(@PathParam("username") String User) {
        return "Welcome!" + User;
    }

    @GET
    @Path("hello/{username}")
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHello(@PathParam("username") String User) {
        return "Hello " + User;
    }
}

来自 Jersey documentation 这是 JAX-RS 实现:

Default lifecycle (applied when no annotation is present). In this scope the resource instance is created for each new request and used for processing of this request. If the resource is used more than one time in the request processing, always the same instance will be used. This can happen when a resource is a sub resource and is returned more times during the matching. In this situation only one instance will serve the requests.

来自Life Cycle of JAX-RS Resource Class

By default the life-cycle of root resource classes is per-request which, namely that a new instance of a root resource class is created every time the request URI path matches the root resource.

In short, following things happen in sequence.

Path’s are matched with Resource classes.
Constructor is called.
Dependencies are injected.
Appropriate method is called.
Resource is garbage collected.

Strangely, JAX-RS resource classes are not by default singleton. In general this is unlikely to be a cause of performance issues. Class construction and garbage collection of JVMs has vastly improved over the years and many objects will be created and discarded to serve and process the HTTP request and return the HTTP response.

虽然端点 class 默认情况下是根据请求创建的,但您可以使其成为每个 JAX-RS 应用程序具有一个实例的单例:JAX-RS Resource Lifecycle Performance Impact

谈到您的示例,在这两种情况下,实例化 1 和实例化 2 都没有区别,用户将使用 GreetingResource 的 2 个实例并在 return 上获得他们的名字。在情况 2 中,如果该方法将使用数据库并且 2 个用户将修改同一资源,则您需要使用 optimistic locking 或其他解决方案来管理并发访问。

Servlet classes

servlet 容器创建 servlet class 单个实例 来处理对该 servlet 的所有请求。请参阅 JSR 369 中的以下引用,定义了 Servlet 4.0 规范:

For a servlet not hosted in a distributed environment (the default), the servlet container must use only one instance per servlet declaration. [...]

Servlet 接口定义了初始化 servlet、服务请求以及从服务器删除 servlet 的方法:

  • 构建 servlet,然后使用 init 方法初始化。
  • 处理客户端对 service 方法的任何调用。
  • servlet 停止服务,然后使用 destroy 方法销毁,然后进行垃圾收集并完成。

不要犹豫,查看 specification 了解更多详情。

资源classes

虽然 servlet classes 由 servlet 容器管理,但资源 classes 由 JAX-RS 运行时管理。顺便说一句,JAX-RS 应用程序甚至不需要部署 servlet 容器。

默认情况下,资源 classes(注释为 @Path) are request-scoped. It means that the JAX-RS runtime will create a new resource class instance for each request to that resource. Quoting the JSR 370 的文档定义了 JAX-RS 2.1 规范:

By default a new resource class instance is created for each request to that resource. First the constructor is called, then any requested dependencies are injected, then the appropriate method is invoked and finally the object is made available for garbage collection. [...]

根据 Jersey documentation,一般来说这不太可能是性能问题的原因。 Class JVM 的构建和垃圾收集在这些年里有了很大的改进,许多对象将被创建和丢弃以服务和处理 HTTP 请求和 return HTTP 响应。

此外,这还形成了一个非常自然的编程模型,在该模型中可以使用构造函数和字段,而无需担心对同一资源的多个并发请求。

EJB 和 CDI

对于支持EJB的实现,资源classes可以用@Stateless or @Singleton注释。

JAX-RS 实现也可能支持 CDI,但是 JAX-RS 和 CDI 的组件模型略有不同。默认情况下,JAX-RS资源classes在请求范围内管理,不需要注解指定范围。用 @RequestScoped or @ApplicationScoped 注释的 CDI 托管 beans 可以转换为 JAX-RS 资源 classes.

请参阅 examples 的 Java EE 8 教程。

供应商classes

与资源 classes、provider classes 不同(注释为 @Provider) are application-scoped by default. It means that the JAX-RS runtime will create only a single instance for each provider class. From the JSR 370:

By default a single instance of each provider class is instantiated for each JAX-RS application. First the constructor is called, then any requested dependencies are injected, then the appropriate provider methods may be called multiple times (simultaneously), and finally the object is made available for garbage collection. [...]