Jersey constructor with parameters

2019-07-29 12:39发布

问题:

I want to use a DAO in my RESTful service developed with Jersey, so the DAO implementation should be injected via the constructor of the service:

@Path("eventscheduler)
public class EventSchedulerService {
    private IEventSchedulerDao dao;

    public EventSchedulerService(IEventSchedulerDao dao) { this.dao = dao; }
}

However, I know Jersey expects a default constructor to setup everything correctly. I have been trying to figure out how to do this for a while but surprisingly this seems to be an uncommon case, I wonder how people inject DAOs into their services, or deal with injection in general at all.

How can I do this?

回答1:

If you're using Jersey 2, it uses HK2 as it's DI framework. All resource classes go through the DI lifecycle when they are constructed. And constructor injection is not a problem.

The most basic way (with Jersey) to make an arbitrary object injectable, is to bind in an AbstractBinder

public class Binder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(EventSchedudlerDaoImpl.class).to(EventSchedulerDao.class);
    }
}

Then register the binder with Jersey

public class JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(new Binder());
    }
}

Then you just need to declare the injection point by adding @Inject on top of the constructor.

@Inject
public EventSchedulerService(EventSchedulerDao dao) {
    this.dao = dao;
}

As far as the binder implementation, the binding syntax basically reads as

bind( Implementation ).to( Contract ).in( Scope );

The bind method can take an instance or it can take a class. When you provide an instance, the Scope is automatically Singleton.

The to method specifies the advertised contract, which is the type that can be declared at the injection point. In this case, only the interface EventSchedulerDao can be used for the injection point. If you don't have an interface you can just do

bindAsContract(EventSchedulerDao.class)

assuming EventSchedulerDao is the implementation class.

The scopes available are PerLookup, RequestScoped and Singleton. If not specified, the default scope will be PerLookup, meaning a new instance of the service will be created for each injection point. You should already know what Singleton means. RequestScoped means that a new instance will be created for each request, which may not be the same as PerLookup, as the service may be injected at multiple points through out the request lifeclyle.

See Also:

  • Dependency injection with Jersey 2.0
  • Custom Injection and Lifecycle Management
  • hk2 tagged questions. Alot of them are Jersey related.


回答2:

You must annotate the class constructor (or the property itself) with javax.inject.Inject.

import javax.inject.Inject;

class EventSchedulerResource {
  private final IEventSchedulerDao dao;

  @Inject
  public EventSchedulerResource(IEventSchedulerDao dao) {
    this.dao = dao;
  }

  // ...

}

If the IEventScheduler is an interface you must create a configuration class class that extends org.glassfish.jersey.server.ResourceConfig and register the binding of interface to a concrete implementation with bind(EventSchedulerDaoImpl.class).to(IEventScheduler.class) (See here: https://jersey.java.net/documentation/latest/ioc.html chapter 23.1)