Sök…


Grundläggande beroende injektion med Jersey's HK2

Jersey (2) använder HK2 som ett system för beroendeinjicering (DI). Vi kan använda andra injektionssystem, men dess infrastruktur är byggd med HK2, och gör att vi också kan använda det inom våra applikationer.

Att ställa in enkel beroendeinjektion med Jersey tar bara några koder. Låt oss till exempel säga att vi har en tjänst som vi vill sprida in i våra resurser.

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

Och vi vill injicera den här tjänsten i en Jersey-resurs

@Path("greeting")
public class GreetingResource {

    @Inject
    public GreetingService greetingService;

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

För att injektionen ska fungera är allt vi behöver en enkel konfiguration

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

Här säger vi att vi vill binda GreetingService till injektionssystemet och annonsera det som injicerbart av samma klass. Vad det sista uttalandet innebär är att vi bara kan injicera det som GreetingService och (antagligen uppenbarligen) inte av någon annan klass. Som ni ser senare är det möjligt att ändra detta.

Det är allt. Att allt du behöver. Om du inte känner till den här ResourceConfig konfigurationen (kanske du använder web.xml) kan du söka under Konfigurera JAX-RS i Jersey- ämnet i SO Docs.


Obs! Injektionen ovan är fältinjektion, där tjänsten injiceras i resursfältet. En annan typ av injektion är konstruktörsinjektion, där tjänsten injiceras i konstruktören

private final GreetingService greetingService;

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

Detta är förmodligen det föredragna sättet att gå i motsats till fältinjektion, eftersom det gör resursen enklare att testa enheten. Konstruktörsprutning kräver ingen annan konfiguration.


Ok nu kan vi säga att istället för en klass är GreetingService ett gränssnitt och vi har en implementering av det (vilket är mycket vanligt). För att konfigurera det använder vi följande syntax i ovanstående configure

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

Detta läser som "binda NiceGreetingService och annonsera det som GreetingService ". Detta betyder att vi kan använda exakt samma kod i GreetingResource ovan, eftersom vi annonserar kontraktet som GreetingService och inte NiceGreetingService . Men själva genomförandet, när det injiceras, kommer att vara NiceGreetingService .

Vad sägs nu om omfattning. Om du någonsin har arbetat med någon injektionsram kommer du att ha stött på konceptet med omfattning, som avgör tjänstens livslängd. Du kanske har hört talas om ett "Request Scope", där tjänsten lever endast under begäran. Eller ett "Singleton Scope", där det bara finns en instans av tjänsten. Vi kan konfigurera dessa omfattningar också med följande syntax.

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

Standardomfånget är PerLookup , vilket innebär att varje gång denna tjänst begärs kommer en ny att skapas. I exemplet ovan, med RequestScoped , RequestScoped en ny tjänst för en enda begäran. Detta kan vara eller inte vara detsamma som PerLookup , beroende på hur många platser vi försöker injicera den. Vi kanske försöker injicera det i ett filter och i en resurs. Om detta var PerLookup , skulle två instanser skapas för varje begäran. I det här fallet vill vi bara ha en.

De andra två tillgängliga områdena är Singleton (endast en instans skapad) och Immediate (som Singleton ) men skapas vid start (medan med Singleton skapas den inte förrän den första begäran).

Förutom bindande klasser kan vi också bara använda en instans. Detta skulle ger oss en standard singleton, så vi inte behöver använda in syntax.

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

Vad händer om vi har en viss komplex skapningslogik eller behöver lite begärda sammanhangsinformation för tjänsten. I det här fallet finns Factory . De flesta saker vi kan injicera i våra Jersey-resurser, vi kan också injicera i en Factory . Ta till exempel

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

Här har vi en fabrik som får förfrågningsinformation från UriInfo , i detta fall en frågeparameter, och vi skapar GreetingService utifrån den. För att konfigurera det använder vi följande syntax

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

Det är allt. Det här är bara grunderna. Det finns mycket mer att göra HK och Jersey.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow