¿Puede un progtwig depender de una biblioteca durante la comstackción pero no del tiempo de ejecución?

Entiendo la diferencia entre tiempo de ejecución y tiempo de comstackción y cómo diferenciar entre los dos, pero simplemente no veo la necesidad de hacer una distinción entre las dependencias en tiempo de comstackción y en tiempo de ejecución.

A lo que me estoy ahogando es a esto: ¿cómo puede un progtwig no depender de algo en tiempo de ejecución de lo que dependía durante la comstackción? Si mi aplicación Java usa log4j, necesita el archivo log4j.jar para comstackr (mi código integrando e invocando métodos miembro desde adentro log4j) así como el tiempo de ejecución (mi código no tiene absolutamente ningún control sobre lo que sucede una vez código dentro de log4j .jar se ejecutó).

Estoy leyendo herramientas de resolución de dependencia como Ivy y Maven, y estas herramientas hacen claramente la distinción entre estos dos tipos de dependencias. Simplemente no entiendo la necesidad de eso.

¿Alguien puede dar una explicación simple, tipo “King’s English”, preferiblemente con un ejemplo real que incluso una pobre savia como yo podría entender?

En general, se requiere una dependencia de tiempo de comstackción en tiempo de ejecución. En maven, se agregará una dependencia de ámbito de compile a classpath en tiempo de ejecución (por ejemplo, en wars se copiarán en WEB-INF / lib).

Sin embargo, no es estrictamente obligatorio; por ejemplo, podemos comstackr contra una cierta API, convirtiéndola en una dependencia en tiempo de comstackción, pero luego en el tiempo de ejecución incluimos una implementación que también incluye la API.

Puede haber casos adicionales en los que el proyecto requiera una cierta dependencia para comstackrse, pero luego el código correspondiente no es realmente necesario, pero estos serán raros.

Por otro lado, incluir dependencias de tiempo de ejecución que no son necesarias en tiempo de comstackción es muy común. Por ejemplo, si está escribiendo una aplicación Java EE 6, comstack en contra de la API de Java EE 6, pero en tiempo de ejecución, se puede usar cualquier contenedor Java EE; es este contenedor el que proporciona la implementación.

Las dependencias en tiempo de comstackción se pueden evitar utilizando el reflection. Por ejemplo, un controlador JDBC puede cargarse con un Class.forName y la clase real cargada puede configurarse a través de un archivo de configuración.

Cada dependencia de Maven tiene un scope que define en qué classpath esa dependencia está disponible.

Cuando crea un JAR para un proyecto, las dependencias no se incluyen con el artefacto generado; se usan solo para comstackción. (Sin embargo, aún puede hacer que maven incluya las dependencias en el jar construido, ver: Incluir dependencias en un jar con Maven )

Cuando utiliza Maven para crear un archivo WAR o EAR, puede configurar Maven para agrupar dependencias con el artefacto generado, y también puede configurarlo para excluir ciertas dependencias del archivo WAR utilizando el scope provisto.

El ámbito más común – Alcance de comstackción – indica que la dependencia está disponible para su proyecto en la ruta de clases de comstackción, las rutas de clases de comstackción y ejecución de unidades, y la ruta de clases de tiempo de ejecución final cuando ejecuta su aplicación. En una aplicación web Java EE, esto significa que la dependencia se copia en la aplicación desplegada. Sin embargo, en un archivo .jar, las dependencias no se incluirán con el ámbito de comstackción.

Runtime Scope indica que la dependencia está disponible para su proyecto en la ejecución de prueba unitaria y classpaths de ejecución, pero a diferencia del scope de comstackción no está disponible cuando comstack su aplicación o sus pruebas unitarias. Una dependencia de tiempo de ejecución se copia en la aplicación implementada, pero no está disponible durante la comstackción. Esto es bueno para asegurarse de no depender por error de una biblioteca específica. (Ver por ejemplo: http://www.tugay.biz/2016/12/apache-commons-logging-log4j-maven.html )

Finalmente, Alcance Proporcionado indica que el contenedor en el que se ejecuta su aplicación proporciona la dependencia en su nombre. En una aplicación Java EE, esto significa que la dependencia ya está en el classpath del servidor de aplicaciones o del servidor de aplicaciones y no se copia en la aplicación desplegada. También significa que necesita esta dependencia para comstackr su proyecto.

Necesita en tiempo de comstackción las dependencias que pueda necesitar en tiempo de ejecución. Sin embargo, muchas bibliotecas se ejecutan sin todas sus posibles dependencias. es decir, una biblioteca que puede usar cuatro bibliotecas XML diferentes, pero solo necesita una para trabajar.

Muchas bibliotecas necesitan otras bibliotecas a su vez. Estas bibliotecas no son necesarias en tiempo de comstackción, pero son necesarias en tiempo de ejecución. es decir, cuando el código realmente se ejecuta.

Por lo general, usted está en lo cierto y probasiblemente es la situación ideal si las dependencias de tiempo de ejecución y tiempo de comstackción son idénticas.

Le daré 2 ejemplos cuando esta regla es incorrecta.

Si la clase A depende de la clase B que depende de la clase C que depende de la clase D donde A es su clase y B, C y D son clases de diferentes bibliotecas de terceros, solo necesita B y C en el momento de la comstackción y también necesita D en tiempo de ejecución A menudo los progtwigs usan carga dinámica de clase. En este caso, no necesita clases cargadas dinámicamente por la biblioteca que está utilizando en tiempo de comstackción. Además, a menudo la biblioteca elige qué implementación usar en tiempo de ejecución. Por ejemplo, SLF4J o Commons Logging pueden cambiar la implementación del log de destino en tiempo de ejecución. Solo necesita SSL4J en tiempo de comstackción.

Ejemplo opuesto cuando necesita más dependencias en tiempo de comstackción que en tiempo de ejecución. Piensa que estás desarrollando una aplicación que debe funcionar en diferentes entornos o sistemas operativos. Necesita todas las bibliotecas específicas de plataforma en tiempo de comstackción y solo las bibliotecas necesarias para el entorno actual en tiempo de ejecución.

Espero que mis explicaciones ayuden.

Por lo general, el gráfico de dependencias estáticas es un sub-gráfico de la dinámica, ver, por ejemplo, esta entrada de blog del autor de NDepend .

Dicho esto, hay algunas excepciones, principalmente dependencias que agregan soporte de comstackdor, que se vuelve invisible en el tiempo de ejecución. Por ejemplo, para la generación de código a través de Lombok o comprobaciones adicionales como a través del marco Checker (tipo conectable) .

Acabo de toparme con un problema que responde a tu pregunta. servlet-api.jar es una dependencia transitoria en mi proyecto web y es necesaria tanto en tiempo de comstackción como en tiempo de ejecución. Pero servlet-api.jar también se incluye en mi biblioteca Tomcat.

La solución aquí es hacer que servlet-api.jar en maven esté disponible solo en tiempo de comstackción y no empaquetado en mi archivo war para que no entre en conflicto con el servlet-api.jar contenido en mi biblioteca Tomcat.

Espero que esto explique el tiempo de comstackción y la dependencia de tiempo de ejecución.

En tiempo de comstackción, habilita los contratos / api que se esperan de sus dependencias. (por ejemplo: aquí solo firmas un contrato con un proveedor de Internet de banda ancha) En tiempo de ejecución, en realidad estás usando las dependencias. (Por ejemplo: aquí en realidad estás usando Internet de banda ancha)

Para responder a la pregunta “¿cómo puede un progtwig no depender de algo en tiempo de ejecución de lo que dependía durante la comstackción?”, Veamos el ejemplo de un procesador de anotación.

Supongamos que ha escrito su propio procesador de anotaciones y suponga que tiene una dependencia en tiempo de comstackción en com.google.auto.service:auto-service para que pueda usar @AutoService . Esta dependencia solo es necesaria para comstackr el procesador de anotaciones, pero no es necesario en tiempo de ejecución: todos los demás proyectos que dependen de su procesador de anotación para procesar anotaciones no requieren la dependencia de com.google.auto.service:auto-service en el tiempo de ejecución ( ni en tiempo de comstackción ni en ningún otro momento).

Esto no es muy común, pero sucede.

Entiendo la diferencia entre tiempo de ejecución y tiempo de comstackción y cómo diferenciar entre los dos, pero simplemente no veo la necesidad de hacer una distinción entre las dependencias en tiempo de comstackción y en tiempo de ejecución.

Los conceptos generales de tiempo de compile y runtime y runtime dependencias de compile y del ámbito de runtime Maven son dos cosas muy diferentes. No se pueden comparar directamente ya que estos no tienen el mismo marco: los conceptos generales de comstackción y tiempo de ejecución son amplios, mientras que los conceptos de compile maven y del scope del runtime se refieren específicamente a la disponibilidad / visibilidad de las dependencias según el tiempo: comstackción o ejecución.
No olvide que Maven es sobre todo un contenedor javac / java y que en Java tiene un classpath en tiempo de comstackción que especifica con javac -cp ... y un classpath en tiempo de ejecución que especifica con java -cp ...
No sería erróneo considerar el ámbito de compile Maven como una forma de agregar una dependencia tanto en comstackción de Java como en classppath de tiempo de ejecución ( javac y java ) mientras que el ámbito de runtime Maven puede verse como una forma de agregar una dependencia solo en Java runtime classppath ( javac ).

A lo que me estoy ahogando es a esto: ¿cómo puede un progtwig no depender de algo en tiempo de ejecución de lo que dependía durante la comstackción?

Lo que describes no tiene ninguna relación con el runtime y el scope de compile .
Parece que el scope provided que especifica para una dependencia depende de eso en tiempo de comstackción pero no en tiempo de ejecución.
Lo usa como necesita la dependencia para comstackr, pero no desea incluirlo en el componente empaquetado (JAR, WAR u otros) porque la dependencia ya está proporcionada por el entorno: se puede incluir en el servidor o en cualquier otro ruta de acceso de la classpath especificada cuando se inicia la aplicación Java.

Si mi aplicación Java usa log4j, necesita el archivo log4j.jar para comstackr (mi código integrando e invocando métodos miembro desde adentro log4j) así como el tiempo de ejecución (mi código no tiene absolutamente ningún control sobre lo que sucede una vez código dentro de log4j .jar se ejecutó).

En este caso, sí. Pero supongamos que necesita escribir un código portátil que se base en slf4j como fachada frente a log4j para poder cambiar a otra implementación de registro más tarde (log4J 2, logback o cualquier otro).
En este caso, en tu pom necesitas especificar slf4j como una dependencia de compile (es la predeterminada) pero especificarás la dependencia de log4j como una dependencia de runtime :

  org.slf4j slf4j-api ...   org.slf4j slf4j-log4j12 ... runtime  

De esta forma, las clases log4j no pueden referenciarse en el código comstackdo, pero aún podrá referirse a las clases slf4j.
Si ha especificado las dos dependencias con el tiempo de compile , nada le impedirá hacer referencia a las clases log4j en el código comstackdo y podría crear un acoplamiento no deseado con la implementación del registro:

  org.slf4j slf4j-api ...   org.slf4j slf4j-log4j12 ...  

Un uso común del ámbito de runtime de runtime es la statement de dependencia JDBC. Para escribir código portátil, no desea que el código del cliente haga referencia a las clases de la dependencia específica de DBMS (por ejemplo, dependencia de PostgreSQL JDBC) pero igual quiere incluirlo en su aplicación, ya que en el tiempo de ejecución las clases son necesarias para hacer la API JDBC funciona con este DBMS.