3

I'm new to Jersey (2.22.2), so bear with me please. I am creating a REST service that interfaces with an LDAP server for storing, removing, and retrieving user data. The service acts as a security intermediary by performing encryption/decryption.

There is quite a bit of initialization that must take place before the REST services can be utilized, and I would like to only perform this initialization once (when the application is deployed on the server). So this service would be run as a singleton.

Would appreciate if someone could give me some pointers on the best way to go about doing this? Thanks!

Wes
  • 1,183
  • 3
  • 23
  • 51

3 Answers3

7

Jersey 2.22.2 has built-in support altering the lifecycle of its resources. You can use the @Singleton annotation. Read about it in the official documentation at JAX-RS Application, Resources and Sub-Resources: Life-cycle of Root Resource Classes. Simply put your initialization code in the resource's default constructor.

  • Scope: Singleton
  • Annotation: @Singleton
  • Annotation full class name: javax.inject.Singleton

In this scope there is only one instance per jax-rs application. Singleton resource can be either annotated with @Singleton and its class can be registered using the instance of Application. You can also create singletons by registering singleton instances into Application.

Example:

package com.airhacks;
import java.util.Date;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

@Path("/hello")
@Singleton
public class HelloWorldService {

    public HelloWorldService() throws InterruptedException {
        // Some expensive initialization goes here.
        Thread.sleep(5000);
        System.out.println("Initialized at " + new Date());
    }

    @GET
    public Response getMsg() {
        String output = "Hello world at " + new Date();
        return Response.status(200).entity(output).build();
    }

}

In the above example, the first request took five seconds due to lazy initialization on Glassfish 3, and then all subsequent requests were served immediately.

DavidS
  • 5,022
  • 2
  • 28
  • 55
1

User Spring Framework.

https://projects.spring.io/spring-framework/

https://jersey.java.net/documentation/latest/spring.html

There a full working example here:

https://github.com/jersey/jersey/tree/2.22.2/examples/helloworld-spring-webapp

You basically add this dependency to your jersey project and it'll include Spring automatically:

        <dependency>
          <groupId>org.glassfish.jersey.ext</groupId>
          <artifactId>jersey-spring3</artifactId>
          <version>${project.version}</version>
        </dependency>

and then you define your Spring Beans in a file called applicationContext.xml and src/main/resources:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="mySingletonService" class="com.test.MyService"/>
<beans/>

Last But not least, in your actual resource you can inject this singleton service using the @Autowire annotation:

    @Path("/resource")
@Component
public class MyResource {

    @Autowired
    private MyService myService;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getHello() {
        return myService.sayHello();
    }
}

Using the @SingletonResource and initializing state within the resource is a terrible, terrible idea IMO. Separation of concerns is important, and keeping state in a REST Resource is just plain awful. Separate the code that deals with your interface (REST) and your business logic by creating let's say an LDAPResource and an LDAPService. The part Spring plays here is just the wiring that otherwise you'd have to instantiate yourself.

Ulises
  • 9,115
  • 2
  • 30
  • 27
  • This isn't a good answer. It just says "Use Spring Framework" and links to some documentation without explaining how it addresses the user's question. – DavidS Mar 23 '16 at 18:45
  • @DavidS Would Spring be a better framework for this? I'm up for whatever is best suited for this even if it means scrapping Jersey. – Wes Mar 23 '16 at 18:55
  • @Wes, Spring is a framework supports many use cases. Jersey is a small library for making REST services. I can't predict your future, but I would start with just Jersey. I think my answer shows that Spring would be an unnecessary dependency at this point: Jersey already supports what you want to do. – DavidS Mar 23 '16 at 19:00
  • This edited answer still doesn't explain how to create a _singleton_ REST resource, or otherwise perform the expensive initialization only once. – DavidS Mar 23 '16 at 19:02
  • It actually does. The question doesn't say "Singleton Resource" it says "Service". So with the approach I explained, Wes can actually add all the initialization stuff in the Spring context as Spring Beans (Singletons by default) and then wire the service into a regular Jersey resource with an @Autowire annotation – Ulises Mar 23 '16 at 19:35
  • I did not know that Spring beans are singletons by default, and I doubt the asker knew either. Thanks for clarifying. – DavidS Mar 23 '16 at 19:49
  • Thanks, I will look at the Spring solution then. I am just getting started on the project anyway so I don't need to scrap anything. – Wes Mar 23 '16 at 19:59
  • OK please mark Ulises answer as correct then, @Wes. – DavidS Mar 23 '16 at 20:06
1

You can use @Immediate rather than @Singleton in order to ensure that your service gets started as soon as possible. There was some issue at one time where Jersey was not starting the Immediate context by default, but I think that's been resolve by now

jwells131313
  • 2,364
  • 1
  • 16
  • 26
  • Have you confirmed this is working? I Googled it and found this [open ticket](https://java.net/jira/browse/JERSEY-2291). – DavidS Oct 13 '16 at 17:38
  • Looks to me like it is still opened but that hk2 can't fix it, it has to be fixed at the Jersey level. I'll talk to the Jersey guys about it – jwells131313 Oct 13 '16 at 20:02