Zoeken…


Basisafhankelijkheidsinjectie met HK2 van Jersey

Jersey (2) gebruikt HK2 als zijn afhankelijkheidsinjectiesysteem (DI). We kunnen andere injectiesystemen gebruiken, maar de infrastructuur is gebouwd met HK2 en stelt ons in staat om het ook binnen onze applicaties te gebruiken.

Het instellen van eenvoudige afhankelijkheidsinjectie met Jersey vergt slechts een paar regels code. Laten we zeggen dat we bijvoorbeeld een service hebben die we graag in onze bronnen willen injecteren.

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

En we willen deze service in een Jersey-bron injecteren

@Path("greeting")
public class GreetingResource {

    @Inject
    public GreetingService greetingService;

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

Om de injectie te laten werken, hebben we alleen een eenvoudige configuratie nodig

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

Hier zeggen we dat we de GreetingService aan het injectiesysteem willen binden en adverteren als injecteerbaar door dezelfde klasse. Wat de laatste verklaring betekent, is dat we het alleen als GreetingService kunnen injecteren en (waarschijnlijk duidelijk) niet door een andere klasse. Zoals u later zult zien, is het mogelijk om dit te wijzigen.

Dat is het. Dat is alles wat je nodig hebt. Als u niet bekend bent met deze ResourceConfig configuratie (misschien gebruikt u web.xml), raadpleegt u het onderwerp JAX-RS configureren in Jersey over SO Docs.


Opmerking: De bovenstaande injectie is een veldinjectie, waarbij de service in het veld van de resource wordt geïnjecteerd. Een ander type injectie is constructorinjectie, waarbij de service in de constructor wordt geïnjecteerd

private final GreetingService greetingService;

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

Dit is waarschijnlijk de beste manier om te gaan, in tegenstelling tot veldinjectie, omdat het de resource gemakkelijker maakt om te testen. Constructorinjectie vereist geen andere configuratie.


Ok laten we nu zeggen dat in plaats van een klasse, de GreetingService een interface is en we hebben een implementatie ervan (wat heel gebruikelijk is). Om dat te configureren, zouden we de volgende syntaxis gebruiken in de bovenstaande configure

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

Dit luidt als "bind NiceGreetingService , en adverteer het als GreetingService ". Dit betekent dat we exact dezelfde code kunnen gebruiken in de GreetingResource hierboven, omdat we het contract adverteren als GreetingService en niet NiceGreetingService . Maar de daadwerkelijke implementatie, wanneer geïnjecteerd, zal de NiceGreetingService .

Hoe zit het nu met de scope? Als u ooit met een injectiekader hebt gewerkt, bent u het concept van scope tegengekomen, dat de levensduur van de service bepaalt. Je hebt misschien gehoord van een "Request Scope", waar de service alleen leeft voor de levensduur van het verzoek. Of een "Singleton Scope", waar er slechts één exemplaar van de service is. We kunnen deze scopes ook configureren met behulp van de volgende syntaxis.

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

Het standaardbereik is PerLookup , wat betekent dat elke keer dat deze service wordt aangevraagd, een nieuwe wordt gemaakt. In het bovenstaande voorbeeld wordt met behulp van de RequestScoped een nieuwe service gemaakt voor een enkele aanvraag. Dit kan al dan niet hetzelfde zijn als de PerLookup , afhankelijk van het aantal plaatsen waar we het proberen te injecteren. We proberen het mogelijk in een filter en in een bron te injecteren. Als dit PerLookup , zouden voor elke aanvraag twee instanties worden gemaakt. In dit geval willen we er maar één.

De andere twee beschikbare scopes zijn Singleton (slechts één instantie gemaakt) en Immediate (zoals Singleton ) maar wordt bij het opstarten gemaakt (terwijl het met Singleton pas op het eerste verzoek wordt gemaakt).

Naast bindende klassen kunnen we ook gewoon een instantie gebruiken. Dit zou geeft ons een standaard singleton, dus we don noodzaak om het te gebruiken in syntax.

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

Wat als we een complexe logica voor het maken hebben of wat contextinformatie voor de service nodig hebben. In dit geval zijn er Factory s. De meeste dingen die we in onze Jersey-middelen kunnen injecteren, kunnen we ook in een Factory injecteren. Neem bijvoorbeeld

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 */
    }
}

Hier hebben we een fabriek, die aanvraaginformatie van UriInfo , in dit geval queryparameters, en we maken de GreetingService basis daarvan. Om het te configureren, gebruiken we de volgende syntaxis

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

Dat is het. Dit zijn slechts de basisbegrippen. Er zijn nog veel meer dingen die HK en Jersey te doen hebben.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow