web-dev-qa-db-fra.com

En quoi consiste exactement la classe ResourceConfig dans Jersey 2?

J'ai vu beaucoup de tutoriels Jersey qui commencent par quelque chose comme

@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
    public JerseyApplication() {
        packages("com.abc.jersey.services");
    }
}

sans expliquer ce qu'est exactement la classe ResourceConfig. Alors, où puis-je trouver sa documentation, son utilisation, etc.? Googler pour "jersey resourceconfig" ne donne aucun document officiel.

Certaines de mes questions sur cette classe et son utilisation sont les suivantes:

  • Que puis-je faire dans la sous-classe de ResourceConfig?
  • Dois-je enregistrer la sous-classe de ResourceConfig pour qu'elle puisse être trouvée ou est-elle automatiquement détectée par Jersey?
  • Si la sous-classe est automatiquement détectée, que se passe-t-il si j'ai plusieurs sous-classes de ResourceConfig?
  • Le but de ResourceConfig est-il identique à celui du fichier web.xml? Si c'est le cas, que se passe-t-il si j'ai les deux dans mon projet? L'un d'eux a-t-il préséance sur l'autre?
45
Chin

JAX-RS standard utilise une classe de configuration Application . ResourceConfig s'étend Application.

Il existe trois manières principales (dans un conteneur de servlet) de configurer Jersey (JAX-RS):

  1. Avec seulement web.xml
  2. Avec les deux web.xml et une classe Application/ResourceConfig
  3. Avec uniquement une classe Application/ResourceConfig annotée avec @ApplicationPath.

Avec seulement web.xml

Il est possible de configurer l'application de manière standard JAX-RS, mais ce qui suit est spécifique à Jersey.

<web-app>
    <servlet>
        <servlet-name>jersey-servlet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.mypackage.to.scan</param-value>
        </init-param>
    </servlet>
    ...
    <servlet-mapping>
        <servlet-name>jersey-servlet</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
    ...
</web-app>

Étant donné que Jersey s'exécute dans un conteneur de servlet, l'application Jersey s'exécute en tant que servlet. Le servlet Jersey qui traite les demandes entrantes est le ServletContainer. Donc, ici nous le déclarons comme le <servlet-class>. Nous configurons également un <init-param> indiquant à Jersey le (s) paquet (s) à analyser pour nos classes @Path et @Provider afin qu'il puisse les enregistrer.

Sous le capot, Jersey créera en fait une instance ResourceConfig, car c’est ce qu’il utilise pour configurer l’application. Ensuite, il enregistrera toutes les classes qu'il découvre via l'analyse du package.

Avec web.xml et Application/ResourceConfig

Si nous voulons configurer notre application par programme avec une sous-classe Application ou ResourceConfig, nous pouvons le faire en modifiant le fichier Web.xml ci-dessus. Au lieu de définir un init-param pour rechercher des paquets, nous utilisons un init-param pour déclarer notre sous-classe Application/ResourceConfig.

<servlet>
    <servlet-name>jersey-servlet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>com.example.JerseyApplication</param-value>
    </init-param>
    <servlet-mapping>
        <servlet-name>jersey-servlet</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</servlet>
package com.example;

public class JerseyApplication extends ResourceConfig {
    public JerseyApplication() {
        packages("com.abc.jersey.services");
    }
}

Ici, nous configurons le init-paramjavax.ws.rs.Application avec le nom complet de notre sous-classe ResourceConfig. Et au lieu d'utiliser le init-param qui indique à Jersey le (s) paquet (s) à analyser, nous utilisons simplement la méthode pratique packages() de ResourceConfig.

Nous pourrions également utiliser les méthodes register() et property() pour enregistrer des ressources et des fournisseurs, ainsi que pour configurer les propriétés de Jersey. Avec la méthode property(), tout ce qui peut être configuré en tant que init-param peut également être configuré à l'aide de la méthode property(). Par exemple, au lieu d'appeler packages(), nous pourrions faire

public JerseyApplication() {
    property("jersey.config.server.provider.packages",
             "com.mypackage.to.scan");
}

Avec seulement Application/ResourceConfig

Sans un fichier web.xml, Jersey a besoin d’un moyen de fournir le mappage de servlets. Nous faisons cela avec l'annotation @ApplicationPath.

// 'services', '/services', or '/services/*'
// is all the same. Jersey will change it to be '/services/*'
@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
    public JerseyApplication() {
        packages("com.abc.jersey.services");
    }
}

Ici avec le @ApplicationPath, c'est comme si nous avions configuré le mappage de servlet dans le web.xml

<servlet-mapping>
    <servlet-name>JerseyApplication</servlet-name>
    <url-pattern>/services/*</url-pattern>
</servlet-mapping>

Lorsque vous utilisez uniquement le code Java pour la configuration, il doit exister un moyen pour Jersey de découvrir notre classe de configuration. Ceci est fait avec l'utilisation de ServletContanerInitializer . C'est quelque chose qui a été introduit dans la spécification Servlet 3.0, nous ne pouvons donc pas utiliser la configuration "Java uniquement" dans les conteneurs de servlets antérieurs.

Fondamentalement, ce qui se passe, c’est que l’implémenteur de l’initialiseur puisse dire au conteneur de servlet quelles classes rechercher, et le conteneur de servlet passera ces classes à la méthode initializer onStartup(). Dans l'implémentation de l'initialiseur par Jersey, Jersey le configure pour rechercher les classes Application et les classes annotées avec @ApplicationPath. Voir cet article pour plus d'explications. Ainsi, lorsque le conteneur de servlets démarre l'application, l'initialiseur de Jersey sera transmis à notre classe Application/ResourceConfig.

Que puis-je faire dans la sous-classe de ResourceConfig?

Il suffit de regarder le javadoc . C'est surtout juste l'inscription des cours. Pas grand chose à faire avec ça. Les méthodes principales que vous utiliserez sont les méthodes register(), packages() et property(). La méthode register() vous permet d’enregistrer manuellement les classes et les instances de ressources et les fournisseurs manuellement. La méthode packages(), décrite précédemment, répertorie le (s) package (s) sur lequel Jersey doit rechercher les classes @Path et @Provider et les enregistrer pour vous. Et la méthode property() vous permet de définir des propriétés configurables 1.

ResourceConfig est juste une classe de commodité. Rappelez-vous, il étend Application, de sorte que nous pourrions même utiliser la classe standard Application

@ApplicationPath("/services")
public class JerseyApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        final Set<Class<?>> classes = new HashSet<>();
        classes.add(MyResource.class);
        return classes;
    }
    @Override
    public Set<Object> getSingletons() {
        final Set<Object> singletons = new HashSet<>();
        singletons.add(new MyProvider());
        return singletons;
    }

    @Override
    public Map<String, Object> getProperties() {
        final Map<String, Object> properties = new HashMap<>();
        properties.put("jersey.config.server.provider.packages",
                       "com.mypackage.to.scan");
        return properties;
    }
}

Avec un ResourceConfig, nous ferions simplement

public class JerseyApplication extends ResourceConfig {
    public JerseyApplication() {
        register(MyResource.class);
        register(new MyProvider());
        packages("com.mypackages.to.scan");
    }
}

En plus d'être plus pratique, il y a également quelques éléments sous le capot qui aident Jersey à configurer l'application.

Un environnement SE

Tous les exemples ci-dessus supposent que vous utilisez un environnement de serveur installé, par exemple. Matou. Mais vous pouvez également exécuter l'application dans un environnement SE, où vous exécutez un serveur intégré et démarrez l'application à partir d'une méthode main. Vous verrez parfois ces exemples lors de la recherche d'informations, alors je veux montrer à quoi ça ressemble, afin que, lorsque vous rencontrez tous ces problèmes, vous ne soyez pas surpris et sachiez en quoi cela diffère de votre configuration.

Alors parfois, vous verrez un exemple comme

ResourceConfig config = new ResourceConfig();
config.packages("com.my.package");
config.register(SomeFeature.class);
config.property(SOME_PROP, someValue);

Ce qui se passe probablement, c’est que l’exemple utilise un serveur intégré, comme Grizzly. Le reste du code pour démarrer le serveur pourrait être quelque chose comme

public static void main(String[] args) {
    ResourceConfig config = new ResourceConfig();
    config.packages("com.my.package");
    config.register(SomeFeature.class);
    config.property(SOME_PROP, someValue);

    String baseUri = "http://localhost:8080/api/";
    HttpServer server = GrizzlyHttpServerFactory
            .createHttpServer(URI.create(baseUri), config);
    server.start();
}

Ainsi, dans cet exemple, un serveur autonome est en cours de démarrage et le paramètre ResourceConfig est utilisé pour configurer Jersey. La différence ici et par rapport aux exemples précédents est que, dans cet exemple, nous n’étendons pas ResourceConfig, mais nous ne l’instancions que. Ce ne serait pas différent si nous devions faire

public class JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        packages("com.my.package");
        register(SomeFeature.class);
        property(SOME_PROP, someValue);
    }
}

HttpServer server = GrizzlyHttpServerFactory
            .createHttpServer(URI.create(baseUri), new JerseyConfig());

Supposons que vous suiviez un didacticiel montrant une configuration pour une application autonome, dans laquelle ils instancient ResourceConfig, mais que vous exécutez votre application dans un conteneur de servlets et que vous utilisiez la configuration précédente pour laquelle vous étendez ResourceConfig. Eh bien, vous savez maintenant quelle est la différence et quels changements vous devez apporter. J'ai vu des gens faire des choses vraiment bizarres parce qu'ils ne comprenaient pas cette différence. Par exemple, j'ai vu quelqu'un instancier un ResourceConfig dans une classe de ressources. C'est pourquoi j'ai ajouté ce petit morceau supplémentaire; alors vous ne faites pas la même erreur.


Notes de bas de page

1. Il existe un certain nombre de propriétés configurables différentes. Le lien vers le ServerProperties ne sont que quelques propriétés générales. Il existe également différentes propriétés liées à des fonctionnalités spécifiques. La documentation doit mentionner ces propriétés dans la section de la documentation associée à cette fonctionnalité. Pour obtenir une liste complète de toutes les propriétés configurables , vous pouvez consulter toutes les constantes de Jersey et rechercher ceux où la valeur de chaîne commence par jersey.config. Si vous utilisez un fichier web.xml, vous utiliseriez la valeur de chaîne sous la forme init-paramparam-name. Si vous utilisez Java config (ResourceConfig), appelez property(ServerProperties.SOME_CONF, value).

127
Paul Samsotha