jersey
Abhängigkeitsinjektion mit Jersey
Suche…
Grundlegende Abhängigkeitseinspritzung mit Jersey HK2
Jersey (2) verwendet HK2 als Abhängigkeitsinjektionssystem (DI). Wir können andere Injektionssysteme verwenden, aber seine Infrastruktur ist mit HK2 aufgebaut und ermöglicht es uns, sie auch in unseren Anwendungen zu verwenden.
Das Einrichten einer einfachen Abhängigkeitsinjektion mit Jersey erfordert nur wenige Codezeilen. Nehmen wir zum Beispiel an, wir haben einen Service, den wir in unsere Ressourcen einbringen möchten.
public class GreetingService {
public String getGreeting(String name) {
return "Hello " + name + "!";
}
}
Und wir möchten diesen Service in eine Jersey-Ressource integrieren
@Path("greeting")
public class GreetingResource {
@Inject
public GreetingService greetingService;
@GET
public String get(@QueryParam("name") String name) {
return this.greetingService.getGreeting(name);
}
}
Damit die Injektion funktioniert, brauchen wir nur eine einfache Konfiguration
@ApplicationPath("/api")
public class AppConfig extends ResourceConfig {
public AppConfig() {
register(GreetingResource.class);
register(new AbstractBinder() {
@Override
protected void configure() {
bindAsContract(GreetingService.class);
}
});
}
}
Hier möchten wir sagen, dass wir den GreetingService
an das Einspritzsystem binden und als von derselben Klasse injizierbar ankündigen wollen. Die letzte Aussage bedeutet, dass wir sie nur als GreetingService
und (wahrscheinlich offensichtlich) von keiner anderen Klasse einfügen können. Wie Sie später sehen werden, ist es möglich, dies zu ändern.
Das ist es. Das alles was du brauchst. Wenn Sie mit dieser ResourceConfig
Konfiguration nicht vertraut sind (möglicherweise verwenden Sie web.xml), lesen Sie bitte das Thema zum Konfigurieren von JAX-RS in Jersey zu SO-Dokumenten.
Hinweis: Bei der obigen Injektion handelt es sich um eine Feldinjektion, bei der der Service in das Feld der Ressource injiziert wird. Eine andere Art der Injektion ist die Konstruktorinjektion, bei der der Dienst in den Konstruktor eingespritzt wird
private final GreetingService greetingService;
@Inject
public GreetingResource(GreetingService greetingService) {
this.greetingService = greetingService;
}
Dies ist wahrscheinlich der bevorzugte Weg im Gegensatz zur Feldinjektion, da die Ressource einfacher für den Komponententest ist. Die Konstruktorinjektion erfordert keine andere Konfiguration.
Ok, sagen wir jetzt, dass der GreetingService
anstelle einer Klasse eine Schnittstelle ist, und wir haben eine Implementierung davon (was sehr häufig ist). Um dies zu konfigurieren, würden wir in der obigen configure
Methode die folgende Syntax verwenden
@Override
protected void configure() {
bind(NiceGreetingService.class).to(GreetingService.class);
}
Dies liest sich als " NiceGreetingService
binden und als GreetingService
". Dies bedeutet, dass wir denselben Code in der GreetingResource
oben verwenden können, da wir den Vertrag als GreetingService
und nicht als NiceGreetingService
. Die eigentliche Implementierung wird jedoch der NiceGreetingService
.
Was ist nun mit dem Umfang? Wenn Sie jemals mit einem Injektionssystem gearbeitet haben, sind Sie auf das Konzept des Umfangs gestoßen, das die Lebensdauer des Dienstes bestimmt. Sie haben möglicherweise von einem "Request Scope" gehört, bei dem der Dienst nur für die gesamte Dauer der Anfrage aktiv ist. Oder ein "Singleton Scope", bei dem es nur eine Instanz des Dienstes gibt. Wir können diese Bereiche auch mit der folgenden Syntax konfigurieren.
@Override
protected void configure() {
bind(NiceGreetingService.class)
.to(GreetingService.class)
.in(RequestScoped.class);
}
Der Standardbereich ist PerLookup
bedeutet, dass jedes Mal, wenn dieser Dienst angefordert wird, ein neuer erstellt wird. Im obigen Beispiel wird mithilfe von RequestScoped
ein neuer Dienst für eine einzelne Anforderung erstellt. Dies kann, je PerLookup
, an wie vielen Stellen wir versuchen, es zu injizieren, der PerLookup
. Möglicherweise versuchen wir, es in einen Filter und in eine Ressource zu injizieren. Wenn dies PerLookup
wäre, würden für jede Anforderung zwei Instanzen erstellt. In diesem Fall wollen wir nur einen.
Die anderen beiden verfügbaren Bereiche sind Singleton
(nur eine Instanz wurde erstellt) und Immediate
(wie Singleton
), werden jedoch beim Start erstellt (mit Singleton
wird er jedoch erst bei der ersten Anforderung erstellt).
Abgesehen von bindenden Klassen können wir auch eine Instanz verwenden. Dies würde uns einen Standard-Singleton geben, so dass wir keine in
Syntax verwenden müssen.
@Override
protected void configure() {
bind(new NiceGreetingService())
.to(GreetingService.class);
}
Was ist, wenn wir eine komplexe Erstellungslogik haben oder Anforderungskontextinformationen für den Dienst benötigen. In diesem Fall gibt es Factory
s. Die meisten Dinge, die wir in unsere Jersey-Ressourcen injizieren können, können wir auch in eine Factory
injizieren. Nehmen Sie zum Beispiel
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 haben wir eine Factory, die Anforderungsinformationen von UriInfo
, in diesem Fall Abfrageparameter, und wir erstellen daraus den GreetingService
. Zur Konfiguration verwenden wir die folgende Syntax
@Override
protected void configure() {
bindFactory(GreetingServiceFactory.class)
.to(GreetingService.class)
.in(RequestScoped.class);
}
Das ist es. Dies sind nur die Grundlagen. Es gibt noch viel mehr Dinge, die HK und Jersey tun müssen.