Pouvez un programme dépend d'une bibliothèque lors de la compilation, mais pas d'exécution?
Je comprends la différence entre l'exécution et au moment de la compilation et comment faire la différence entre les deux, mais je ne vois pas la nécessité de faire une distinction entre la compilation et à l'exécution dépendances.
Ce que je suis d'étouffement sur est celle de savoir comment un programme dépend pas sur quelque chose lors de l'exécution qu'il dépendait lors de la compilation? Si mon application Java utilise log4j, alors il a besoin de l'log4j.jar fichier pour compiler (mon code d'intégration avec des et de l'invocation de méthodes membres de l'intérieur de log4j) ainsi que de l'exécution (mon code n'a absolument aucun contrôle sur ce qui se passe une fois que le code à l'intérieur log4j.jar est couru).
Je suis en train de lire sur la résolution des dépendances des outils tels que le Lierre et Maven, et ces outils font clairement la distinction entre ces deux types de dépendances. Je ne comprends pas le besoin.
Quelqu'un peut-il donner un simple, "Roi de l'anglais"-explication de type, de préférence avec un exemple que même un mauvais sap comme moi pouvait comprendre?
- Vous pouvez utiliser la réflexion, et de l'utilisation des classes qui n'étaient pas disponibles au moment de la compilation. Pensez à "plugin".
Vous devez vous connecter pour publier un commentaire.
Au moment de la compilation de la dépendance est généralement nécessaire lors de l'exécution. Dans maven, un
compile
l'étendue de la dépendance sera ajouté au classpath de l'exécution (par exemple dans les guerres qu'ils seront copiés dans WEB-INF/lib).Il n'est cependant pas strictement nécessaire; par exemple, nous pouvons compiler contre certaines API, faisant d'elle un moment de la compilation de la dépendance, mais ensuite, au moment de l'exécution inclure une mise en œuvre qui comprend également l'API.
Il peut y avoir de frange cas où le projet nécessite une certaine dépendance à la compilation, mais alors le code correspondant n'est pas réellement nécessaire, mais ce sera rare.
Sur l'autre main, y compris les dépendances d'exécution qui ne sont pas nécessaires au moment de la compilation est très commun. Par exemple, si vous écrivez une application Java EE 6, vous compilez contre la Java EE 6 API, mais au moment de l'exécution, Java EE conteneur peut être utilisé; c'est ce conteneur qui prévoit la mise en œuvre.
Au moment de la compilation des dépendances peuvent être évités par l'utilisation de la réflexion. Par exemple, un pilote JDBC peut être chargé avec un
de la Classe.forName
et de la classe réelle chargés être configurable via un fichier de configuration.provided
champ d'application ajoute une compilation de la dépendance du temps sans l'ajout d'un moteur d'exécution de la dépendance à l'idée que la dépendance sera fourni au moment de l'exécution par d'autres moyens (par exemple, une bibliothèque partagée dans le conteneur).runtime
sur l'autre main ajoute un moteur d'exécution de dépendance sans en faire une compilation de dépendance.Chaque Maven dépendance a un champ d'application qui définit le chemin de classe que la dépendance est disponible sur.
Lorsque vous créez un POT pour un projet, les dépendances ne sont pas livrées avec le générés artefact; ils sont uniquement utilisés pour la compilation. (Cependant, vous pouvez toujours faire maven inclure les dépendances du pot, voir: Y compris les dépendances dans un bocal avec Maven)
Lorsque vous utilisez Maven pour créer une GUERRE ou d'un fichier EAR, vous pouvez configurer Maven pour regrouper des dépendances avec l'artefact généré, et vous pouvez également le configurer pour exclure certaines dépendances de la GUERRE de fichier à l'aide du champ d'application.
La commune la plus étendue — Compiler Portée — indique que la dépendance est disponible pour votre projet sur la compilation classpath, le test de l'unité de compilation et de l'exécution des chemins de classe, et l'éventuelle exécution classpath lors de l'exécution de votre application. Dans une application web Java EE, cela signifie que la dépendance est copié dans votre application déployée. Dans une .fichier jar cependant, les dépendances ne seront pas incluses dans la compilation portée..
Runtime Portée indique que la dépendance est disponible pour votre projet sur l'exécution des tests unitaires et d'exécution chemins de classe,
mais à la différence de compiler portée, il n'est pas disponible lorsque vous compilez votre application ou de ses tests unitaires. À l'Exécution de la Dépendance est copié dans votre application déployée, mais il n'est pas disponible lors de la compilation! C'est bon pour faire sûr que vous n'avez pas tort, dépendent d'une bibliothèque spécifique. (Voir, par exemple: http://www.tugay.biz/2016/12/apache-commons-logging-log4j-maven.html)
Enfin, Fourni Portée indique que le conteneur dans lequel l'exécution de votre application fournit la dépendance en votre nom. Dans une application Java EE, cela signifie que la dépendance est déjà sur le conteneur de Servlet ou du serveur d'application et de classpath n'est pas copié dans votre application déployée. Cela signifie également que vous avez besoin de cette dépendance pour l'élaboration de votre projet.
Vous avez besoin au moment de la compilation dépendances dont vous pourriez avoir besoin lors de l'exécution. Toutefois, de nombreuses bibliothèques de fonctionner sans tous ses éventuelles dépendances. c'est à dire une des bibliothèques qui peut utiliser quatre différents XML bibliothèques, mais un seul à travailler.
De nombreuses bibliothèques, besoin d'autres bibliothèques à son tour. Ces bibliothèques ne sont pas nécessaires au moment de la compilation, mais ils sont nécessaires à l'exécution. c'est à dire lorsque le code est exécuté.
Vous êtes généralement droit et probasbly c'est la situation idéale si moment de l'exécution et de la compilation des dépendances sont identiques.
Je vais vous donner 2 exemple lorsque cette règle est incorrect.
Si la classe A dépend de la classe B qui dépend de la classe C qui dépend de la classe D où Un est dans votre classe et de B, C et D sont des classes de différentes bibliothèques tierces, vous avez besoin seulement B et C au moment de la compilation et vous avez besoin aussi D au moment de l'exécution.
Souvent, les programmes de l'utilisation dynamique de chargement de classe. Dans ce cas, vous n'avez pas besoin classes chargé dynamiquement par la bibliothèque que vous utilisez au moment de la compilation. D'ailleurs souvent la bibliothèque choisit la mise en œuvre à utiliser lors de l'exécution. Par exemple SLF4J ou Commons Logging pouvez changer la cible du journal mise en œuvre lors de l'exécution. Vous avez seulement besoin de SSL4J lui-même au moment de la compilation.
Opposé exemple lorsque vous avez besoin de plus de dépendances au moment de la compilation que lors de l'exécution.
Pensez que vous êtes en développement d'application qui doit travailler à différents environnements ou des systèmes d'exploitation. Vous avez besoin de toute plate-forme de bibliothèques spécifiques au moment de la compilation et seules les bibliothèques nécessaires pour le courant de l'environnement lors de l'exécution.
J'espère que mes explications vous aider.
Généralement, la statique des dépendances graphe est un sous-graphe de la dynamique, de voir, par exemple,cette entrée de blog de l'auteur de NDepend.
Cela dit, il y a quelques exceptions, notamment les dépendances ajouter compilateur de soutien, qui devient invisible au moment de l'exécution. Par exemple, pour la génération de code via Lombok ou de vérifications supplémentaires, comme par le (enfichable type)Vérificateur Cadre.
Juste couru dans un problème qui répond à votre question.
servlet-api.jar
est un transitoire de la dépendance dans mon projet web et est nécessaire à la fois au moment de la compilation et de l'exécution. Maisservlet-api.jar
est également inclus dans ma bibliothèque Tomcat.La solution ici est de faire
servlet-api.jar
dans maven disponible uniquement au moment de la compilation et non emballés dans mon fichier war de sorte qu'il ne serait pas en contradiction avec leservlet-api.jar
contenues dans ma bibliothèque Tomcat.J'espère que c'est ce qui explique le temps de Compilation et d'Exécution de la dépendance.
compile
etprovided
étendues et non pas entrecompile
etruntime
.Compile scope
est à la fois nécessaire au moment de la compilation, et est offert dans votre application.Provided scope
n'est nécessaire au moment de la compilation, mais n'est pas emballé dans votre application de cause, il est fourni par d'autres signifie, par exemple, il est déjà dans le serveur Tomcat.compile
etruntime
maven étendues. Leprovided
champ d'application est le moyen maven gère le cas où au moment de la compilation de la dépendance ne doit pas être inclus dans le package d'exécution.Le général au moment de la compilation et de l'exécution des concepts et de l'Maven spécifiques
compile
etruntime
portée dépendances sont deux choses très différentes. Vous ne pouvez pas comparer directement entre eux que ceux-ci n'ont pas la même image : le général de compilation et d'exécution concepts sont larges, tandis que le mavencompile
etruntime
champ d'application de concepts est précisément les dépendances de la disponibilité et de la visibilité en fonction du temps : la compilation ou à l'exécution.N'oubliez pas que Maven est avant tout un
javac
/java
wrapper et qu'en Java, vous avez un moment de la compilation, celui que vous spécifiez avecjavac -cp ...
et à l'exécution, celui que vous spécifiez avecjava -cp ...
.Il serait erroné de considérer le Maven
compile
portée comme un moyen d'ajouter une dépendance à la fois dans le Java compiler et d'exécution classppath (javac
etjava
), tandis que le Mavenruntime
champ d'application peut être vu comme un moyen d'ajouter une dépendance seulement le Java runtime classppath (javac
).Ce que vous décrivez n'a aucun rapport avec
runtime
etcompile
portée.Il ressemble plus à la
provided
étendue que vous spécifiez pour une dépendance à dépendre de qui au moment de la compilation, mais pas au moment de l'exécution.Vous l'utilisez comme vous le besoin de la dépendance à la compilation, mais vous ne voulez pas inclure dans le package de composant (JAR, WAR ou autres), car la dépendance est déjà fourni par l'environnement : il peut être inclus dans le serveur ou tout le chemin de la chemin de classe spécifié que l'application Java est commencé.
Dans ce cas oui. Mais supposons que vous devez écrire du code portable, qui s'appuie sur slf4j comme façade en face de log4j pour être en mesure de passer à une autre implémentation de journalisation plus tard (log4J 2, logback ou autre).
Dans ce cas, vous pom vous devez spécifier slf4j comme un
compile
de dépendance (c'est la valeur par défaut), mais vous devrez spécifier le log4j dépendance comme unruntime
dépendance :De cette façon, les classes log4j n'a pas pu être référencé dans le code compilé, mais vous serez toujours en mesure de vous référer slf4j classes.
Si vous avez spécifié les deux dépendances avec le
compile
temps, rien ne vous empêchera de référencement de log4j classes dans le code compilé et vous pouvez donc créer une contrainte de couplage avec l'enregistrement de la mise en œuvre :Une utilisation courante de
runtime
champ d'application est le JDBC dépendance de la déclaration.Pour écrire du code portable, vous ne voulez pas que le code client peut consulter des classes du SGBD spécifique de dépendance (par exemple : JDBC PostgreSQL dépendance), mais vous souhaitez tout de même de l'inclure dans votre demande au moment de l'exécution, les classes sont nécessaires pour rendre l'API JDBC fonctionne avec le SGBD.
Au moment de la compilation vous permet de contrats/api que vous êtes attendus à partir de vos dépendances.
(par exemple: ici, vous venez de signer un contrat avec un fournisseur d'accès internet à large bande)
Au moment de l'exécution en fait, vous utilisez les dépendances.
(par exemple: ici, vous êtes réellement en utilisant l'internet à large bande)
Pour répondre à la question "comment un programme dépend pas de quelque chose au moment de l'exécution qu'il dépendait lors de la compilation?", regardons l'exemple d'un processeur d'annotation.
Supposons que vous avez écrit votre propre processeur d'annotation, et suppose qu'il a un moment de la compilation de la dépendance sur
com.google.auto.service:auto-service
afin qu'il puisse utiliser@AutoService
. Cette dépendance n'est requis pour compiler le processeur d'annotation, mais il n'est pas nécessaire à l'exécution: tous les autres projets en fonction de votre processeur d'annotation pour le traitement des annotations pas exiger la dépendance surcom.google.auto.service:auto-service
au moment de l'exécution (ni à la compilation ni à aucun autre moment).Ce n'est pas très fréquent, mais ça arrive.