简体   繁体   中英

Initialize singleton in Java Jersey 2 JAX-RS

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!

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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM