Ricerca…


Iniezione delle dipendenze di base usando l'HK2 di Jersey

Jersey (2) usa HK2 come sistema di iniezione di dipendenza (DI). Possiamo utilizzare altri sistemi di iniezione, ma la sua infrastruttura è costruita con HK2 e ci consente di utilizzarla anche all'interno delle nostre applicazioni.

L'impostazione dell'iniezione di dipendenza semplice con Jersey richiede solo poche righe di codice. Diciamo per esempio che abbiamo un servizio che vorremmo iniettare nelle nostre risorse.

public class GreetingService {
    public String getGreeting(String name) {
        return "Hello " + name + "!";
    }
}

E vogliamo iniettare questo servizio in una risorsa di Jersey

@Path("greeting")
public class GreetingResource {

    @Inject
    public GreetingService greetingService;

    @GET
    public String get(@QueryParam("name") String name) {
        return this.greetingService.getGreeting(name);
    }
}

Per far funzionare l'iniezione, tutto ciò di cui abbiamo bisogno è una semplice configurazione

@ApplicationPath("/api")
public class AppConfig extends ResourceConfig {
    public AppConfig() {
        register(GreetingResource.class);
        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bindAsContract(GreetingService.class);
            }
        });
    }
}

Qui stiamo dicendo che vogliamo associare il GreetingService al sistema di iniezione e pubblicizzarlo come iniettabile dalla stessa classe. Ciò che l'ultima affermazione significa è che possiamo solo iniettarlo come GreetingService e (probabilmente ovviamente) non da qualsiasi altra classe. Come vedrai dopo, è possibile cambiarlo.

Questo è tutto. Quello di cui hai bisogno. Se non si ha familiarità con questa configurazione di ResourceConfig (forse si sta utilizzando web.xml), è possibile consultare la configurazione di JAX-RS in argomento Jersey su SO Docs.


Nota: l'iniezione di cui sopra è l'iniezione sul campo, in cui il servizio viene iniettato nel campo della risorsa. Un altro tipo di iniezione è l'iniezione del costruttore, in cui il servizio viene iniettato nel costruttore

private final GreetingService greetingService;

@Inject   
public GreetingResource(GreetingService greetingService) {
     this.greetingService = greetingService;
}

Questo è probabilmente il modo migliore per andare rispetto all'iniezione sul campo, poiché rende la risorsa più facile da testare. L'iniezione del costruttore non richiede alcuna configurazione diversa.


Ok, ora diciamo che al posto di una classe, il GreetingService è un'interfaccia e ne abbiamo un'implementazione (che è molto comune). Per configurarlo, dovremmo utilizzare la seguente sintassi nel metodo configure sopra

@Override
protected void configure() {
    bind(NiceGreetingService.class).to(GreetingService.class);
}

Si legge come "associa NiceGreetingService e pubblicalo come GreetingService ". Questo significa che possiamo usare lo stesso identico codice nella GreetingResource sopra, perché pubblicizziamo il contratto come GreetingService e non come NiceGreetingService . Ma l'effettiva implementazione, una volta iniettata, sarà il NiceGreetingService .

Adesso che mi dici di scope. Se hai mai lavorato con qualsiasi framework di iniezione, avrai trovato il concetto di ambito, che determina la durata del servizio. Potresti aver sentito parlare di un "ambito di richiesta", in cui il servizio è attivo solo per la durata della richiesta. O un "Singleton Scope", dove c'è solo una istanza del servizio. Possiamo configurare questi ambiti anche usando la seguente sintassi.

@Override
protected void configure() {
    bind(NiceGreetingService.class)
            .to(GreetingService.class)
            .in(RequestScoped.class);
}

L'ambito predefinito è PerLookup , il che significa che ogni volta che viene richiesto questo servizio, ne verrà creato uno nuovo. Nell'esempio sopra, utilizzando RequestScoped , verrà creato un nuovo servizio per una singola richiesta. Questo può o non può essere lo stesso del PerLookup , a seconda di quanti posti stiamo cercando di iniettarlo. Potremmo provare a iniettarlo in un filtro e in una risorsa. Se questo fosse PerLookup , sarebbero create due istanze per ogni richiesta. In questo caso, ne vogliamo solo uno.

Gli altri due ambiti disponibili sono Singleton (solo un'istanza creata) e Immediate (come Singleton ) ma vengono creati all'avvio (mentre con Singleton , non viene creato fino alla prima richiesta).

A parte le classi vincolanti, potremmo anche solo usare un'istanza. Questo farebbe ci dà un singleton di default, in modo da noi non hanno bisogno di usare il in sintassi.

@Override
protected void configure() {
    bind(new NiceGreetingService())
            .to(GreetingService.class);
}

Cosa succede se abbiamo una logica di creazione complessa o abbiamo bisogno di alcune informazioni di contesto di richiesta per il servizio. In questo caso ci sono Factory s. La maggior parte delle cose che possiamo iniettare nelle nostre risorse di Jersey, possiamo anche iniettare in una Factory . Prendi ad esempio

public class GreetingServiceFactory implements Factory<GreetingService> {
    
    @Context
    UriInfo uriInfo;
    
    @Override
    public GreetingService provide() {
        return new GreetingService(
                uriInfo.getQueryParameters().getFirst("name"));
    }
    
    @Override
    public void dispose(GreetingService service) {
        /* noop */
    }
}

Qui abbiamo una fabbrica, che riceve le informazioni di richiesta da UriInfo , in questo caso i parametri di una query, e da essa viene creato il servizio di GreetingService . Per configurarlo, usiamo la seguente sintassi

@Override
protected void configure() {
    bindFactory(GreetingServiceFactory.class)
            .to(GreetingService.class)
            .in(RequestScoped.class);
}

Questo è tutto. Queste sono solo le basi. Ci sono molte più cose da fare in HK e in Jersey.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow