JAX-RS with embedded server

2019-01-16 20:20发布

问题:

Clarification: this question was about GZIPping an JAX-WS-based REST service, but I've decided to change the topic to make it easier to find

I'm implementing a REST service via JAX-WS Provider <Source>, and publishing it with standard Endpoint (the reason is that I want to avoid using a servlet container or application server).

Is there a way to make server to gzip response content, if Accept-Encoding: gzip is present?


HOW-TO

Samples provided by nicore actually works, and it allows you to make JAX-RS-styled server on top of embedded lightweight server without servlet container, but there are few moments to be considered.

If you prefer to manage classes by yourself (and save a time during startup), you may use the following:

Example

JAX-RS hello world class:

@Path("/helloworld")
public class RestServer {

    @GET
    @Produces("text/html")
    public String getMessage(){
        System.out.println("sayHello()");
        return "Hello, world!";
    }
}

Main method:

For Simple Server:

public static void main(String[] args) throws Exception{
    DefaultResourceConfig resourceConfig = new DefaultResourceConfig(RestServer.class);
    // The following line is to enable GZIP when client accepts it
    resourceConfig.getContainerResponseFilters().add(new GZIPContentEncodingFilter());
    Closeable server = SimpleServerFactory.create("http://0.0.0.0:5555", resourceConfig);
    try {
        System.out.println("Press any key to stop the service...");
        System.in.read();
    } finally {
        server.close();
    }
}

For Grizzly2:

public static void main(String[] args) throws Exception{
    DefaultResourceConfig resourceConfig = new DefaultResourceConfig(RestServer.class);
    // The following line is to enable GZIP when client accepts it
    resourceConfig.getContainerResponseFilters().add(new GZIPContentEncodingFilter());
    HttpServer server = GrizzlyServerFactory.createHttpServer("http://0.0.0.0:5555" , resourceConfig);
    try {
        System.out.println("Press any key to stop the service...");
        System.in.read();
    } finally {
        server.stop();
    }
}

Resolved dependencies:

Simple:

  • Simple Framework itself
  • jersey-simple-server

Grizzly:

  • grizzly-framework
  • grizzly-http
  • grizzly-http-server (different repository!)
  • jersey-grizzly2

Jersey:

  • jersey-archive

Notice

Make sure the javax.ws.rs archive didnt get into your classpath, as it conflicts with Jersey's implementation. The worst thing here is a silent 404 error with no logging - only a small note on FINER level is logged.

回答1:

If you really want to do REST with Java I would suggest you to to use a JAX-RS implementation (RESTeasy, Jersey...).

If your main concern is the dependency on a servlet container, you could use the JAX-RS RuntimeDelegate to register your application as a JAX-RS endpoint.

// Using grizzly as the underlaying server
SelectorThread st = RuntimeDelegate.createEndpoint(new MyApplication(), SelectorThread.class);

st.startEndpoint();

// Wait...
st.stopEndpoint();

Concerning GZIP encoding, each JAX-RS provider has different approaches. Jersey provides a filter to accomplish the encoding transparently. RESTEasy provides an annotation for that.

EDIT

I did some small tests. The following two things will definitely work for you, assuming you are using Maven.

Using Jersey + SimpleServer:

    public static void main( String[] args ) throws Exception {

    java.io.Closeable server = null;

    try {
        // Creates a server and listens on the address below.
        // Scans classpath for JAX-RS resources
        server = SimpleServerFactory.create("http://localhost:5555");
        System.out.println("Press any key to stop the service...");
        System.in.read();
    } finally {
        try {
            if (server != null) {
                server.close();
            }
        } finally {
            ;
        }
    }
}

with maven dependencies

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
    <version>1.10</version>
</dependency>
<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-simple-server</artifactId>
    <version>1.10</version>
</dependency>

Or using the Jersey + Grizzly2:

public static void main(String[] args) throws Exception {

    HttpServer server = null;

    try {
        server = GrizzlyServerFactory.createHttpServer("http://localhost:5555");
        System.out.println("Press any key to stop the service...");
        System.in.read();
    } finally {
        try {
            if (server != null) {
                server.stop();
            }
        } finally {
            ;
        }
    }
}

with maven dependencies

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
    <version>1.10</version>
</dependency>
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-grizzly2</artifactId>
    <version>1.10</version>
</dependency>

Honestly speaking I was not able to get the RuntimeDelegate sample working, too. There certainly is a way to start RESTEasy out of the box, too but I cannot recall it at the moment.



回答2:

gzipping the output is the reponsibility of JAX WS implementation. You should refer to server's (Tomcat, Glassfish, JBoss, etc) documentation in order to configure your http network listeners.



回答3:

If using CXF for your JAX-WS implementation (or JAX-RS), you could just add @GZIP annotation onto the service class.