jersey
Injection de dépendance avec Jersey
Recherche…
Injection de dépendance de base à l'aide du HK2 de Jersey
Jersey (2) utilise HK2 comme système d'injection de dépendance (DI). Nous pouvons utiliser d'autres systèmes d'injection, mais son infrastructure est construite avec HK2 et nous permet également de l'utiliser dans nos applications.
Configurer l'injection de dépendance simple avec Jersey ne prend que quelques lignes de code. Disons par exemple que nous avons un service que nous aimerions injecter dans nos ressources.
public class GreetingService {
public String getGreeting(String name) {
return "Hello " + name + "!";
}
}
Et nous voulons injecter ce service dans une ressource Jersey
@Path("greeting")
public class GreetingResource {
@Inject
public GreetingService greetingService;
@GET
public String get(@QueryParam("name") String name) {
return this.greetingService.getGreeting(name);
}
}
Pour que l'injection fonctionne, il suffit d'avoir une configuration simple
@ApplicationPath("/api")
public class AppConfig extends ResourceConfig {
public AppConfig() {
register(GreetingResource.class);
register(new AbstractBinder() {
@Override
protected void configure() {
bindAsContract(GreetingService.class);
}
});
}
}
Ici, nous disons que nous voulons associer le service GreetingService
au système d’injection et l’annoncer comme injectable par la même classe. Ce que la dernière phrase signifie, c’est que nous ne pouvons l’injecter qu’en tant que GreetingService
et (probablement de toute évidence) pas par une autre classe. Comme vous le verrez plus tard, il est possible de changer cela.
C'est tout. C'est tout ce dont vous avez besoin. Si vous n'êtes pas familier avec cette configuration ResourceConfig
(vous utilisez peut-être web.xml), consultez la rubrique Configuration de JAX-RS à Jersey sur SO Docs.
Note: L'injection ci-dessus est l'injection de champ, où le service est injecté dans le champ de la ressource. Un autre type d'injection est l'injection constructeur, où le service est injecté dans le constructeur
private final GreetingService greetingService;
@Inject
public GreetingResource(GreetingService greetingService) {
this.greetingService = greetingService;
}
C'est probablement la meilleure façon de procéder, contrairement à l'injection sur le terrain, car elle facilite le test unitaire des ressources. L'injection de constructeur ne nécessite aucune configuration différente.
Ok, disons qu'au lieu d'une classe, GreetingService
est une interface, et nous en avons une implémentation (ce qui est très courant). Pour configurer cela, nous utiliserons la syntaxe suivante dans la méthode de configure
ci-dessus
@Override
protected void configure() {
bind(NiceGreetingService.class).to(GreetingService.class);
}
Cela se lit comme "lier NiceGreetingService
, et annoncer comme GreetingService
". Cela signifie que nous pouvons utiliser exactement le même code dans GreetingResource
ci-dessus, car nous NiceGreetingService
le contrat en tant que GreetingService
et non NiceGreetingService
. Mais la mise en œuvre réelle, une fois injectée, sera le NiceGreetingService
.
Maintenant, qu'en est-il de la portée? Si vous avez déjà travaillé avec un cadre d'injection, vous aurez découvert le concept de portée qui détermine la durée de vie du service. Vous avez peut-être entendu parler d'une "Demande de portée", où le service n'est actif que pendant la durée de la demande. Ou un "Singleton Scope", où il n'y a qu'une seule instance du service. Nous pouvons configurer ces portées en utilisant également la syntaxe suivante.
@Override
protected void configure() {
bind(NiceGreetingService.class)
.to(GreetingService.class)
.in(RequestScoped.class);
}
La portée par défaut est PerLookup
, ce qui signifie que chaque fois que ce service est demandé, un nouveau sera créé. Dans l'exemple ci-dessus, à l'aide de RequestScoped
, un nouveau service sera créé pour une seule requête. Cela peut être ou ne pas être le même que le PerLookup
, en fonction du nombre d'endroits que nous essayons d'injecter. Nous essayons peut-être de l'injecter dans un filtre et dans une ressource. S'il s'agissait de PerLookup
, deux instances seraient créées pour chaque requête. Dans ce cas, nous n'en voulons qu'un.
Les deux autres étendues disponibles sont Singleton
(une seule instance créée) et Immediate
(comme Singleton
), mais elles sont créées au démarrage (alors qu'avec Singleton
, elles ne sont créées qu'à la première demande).
Outre les classes de liaison, nous pourrions également utiliser une instance. Cela nous donnerait un singleton par défaut, nous n'avons donc pas besoin d'utiliser la syntaxe in
.
@Override
protected void configure() {
bind(new NiceGreetingService())
.to(GreetingService.class);
}
Que se passe-t-il si nous avons une logique de création complexe ou si nous avons besoin d'informations de contexte de requête pour le service? Dans ce cas, il y a Factory
s. La plupart des choses que nous pouvons injecter dans nos ressources de Jersey, nous pouvons également injecter dans une Factory
. Prends pour exemple
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 */
}
}
Ici , nous avons une usine, qui obtient demander des informations de la UriInfo
, dans ce cas , un paramètre de requête, et nous créons le GreetingService
de celui - ci. Pour le configurer, nous utilisons la syntaxe suivante
@Override
protected void configure() {
bindFactory(GreetingServiceFactory.class)
.to(GreetingService.class)
.in(RequestScoped.class);
}
C'est tout. Ce ne sont que les bases. Il y a beaucoup plus de choses à faire à HK et à Jersey.