How do I define a “default” implementation in HK2?

2019-07-10 07:35发布

问题:

I am using HK2 to resolve dependencies of services in my Jersey / Jetty web service. I have a situation where for one particular interface, I want to use a specific implementation as a "default" implementation. By "default" I mean no names or qualifiers - it is what you get if you do not specify any annotations on top of the field or argument. However, in a few very specific situations, I want to provide an alternative implementation that will be qualified with an annotation.

As a result of my experimentation I have actually got this to work reliably by using the ranked() qualifier in my bindings. It appears the highest rank becomes the default. However, I do not understand why it works, and I am concerned I am writing code that depends on an undocumented implementation detail of HK2 that could change when we update versions.

Here's a contrived example of the interesting parts of what I am doing. Is ranked() what I should be using to specify "default" and annotated variants of a service? Should I be using another technique?

public interface IFoo {
    public String getString();
}

public class DefaultImpl implements IFoo {
    public String getString() {
        return "Default Implementation";
    }
}

public class AnnotatedImpl implements IFoo {
    public String getString() {
        return "Annotated Implementation";
    }
}

public class Bindings extends AbstractBinder {

     @Override
     public void configure() {
         ServiceBindingBuilder<DefaultImpl> defaultImpl =
             bind(DefaultImpl.class)
                 .to(IFoo.class);

         defaultImpl.ranked(9);

         ServiceBindingBuilder<AnnotatedImpl> annotatedImpl =
             bind(AnnotatedImpl.class)
                 .qualifiedBy(new MyAnnotationQualifier())
                 .to(IFoo.class);

         annotatedImpl.ranked(1);
     }
}

public class MyService {

    @Inject
    public MyService(
        IFoo defaultImplementation,
        @MyAnnotation
        IFoo annotatedImplementation) {

        // ... my code here ... 
    }
}

回答1:

I stumbled across some documentation on HK2's website that is consistent with the behavior that I am seeing.

If there are more than one Widget (e.g. Widget is an interface that can have many implementations) then the best Widget will be returned from the getService method. The best instance of a service is a service with the highest ranking or the lowest service id. The ranking of a service is found in its Descriptor and can be changed at any time at run time. The service id of a service is a system assigned value for the Descriptor when it is bound into the ServiceLocator. The system assigned value is a monotonically increasing value. Thus if two services have the same ranking the best service will be associated with the oldest Descriptor bound into the system.

Source

Therefore, I am using ranked() on my bindings correctly. It is one of the two ways to control what HK2 defines as the "default" (or "best") service to inject into my dependent services.