¿Por qué proyectar Jigsaw / JPMS?

79

El sistema de administración de paquetes de Java siempre me pareció simple y efectivo. Es muy utilizado por el propio JDK. Lo hemos estado usando para imitar el concepto de espacios de nombres y módulos.

¿Qué intenta completar Project Jigsaw (también conocido como Java Platform Module System )?

Desde el sitio oficial:

El objetivo de este proyecto es diseñar e implementar un sistema de módulos estándar para la plataforma Java SE, y aplicar ese sistema a la propia plataforma y al JDK.

John
fuente

Respuestas:

100

Jigsaw y OSGi están tratando de resolver el mismo problema: cómo permitir que los módulos de grano más grueso interactúen mientras protegen sus partes internas.

En el caso de Jigsaw, los módulos de grano más grueso incluyen clases de Java, paquetes y sus dependencias.

Aquí hay un ejemplo: Spring e Hibernate. Ambos dependen de un JAR CGLIB de terceros, pero utilizan versiones diferentes e incompatibles de ese JAR. ¿Qué puede hacer si confía en el JDK estándar? Incluir la versión que Spring quiere rompe Hibernate y viceversa.

Pero, si tiene un modelo de nivel superior como Jigsaw, puede administrar fácilmente diferentes versiones de un JAR en diferentes módulos. Piense en ellos como paquetes de nivel superior.

Si construye Spring desde la fuente de GitHub , también lo verá. Han rehecho el marco, por lo que consta de varios módulos: núcleo, persistencia, etc. Puede elegir el conjunto mínimo de dependencias de módulos que necesita su aplicación e ignorar el resto. Solía ​​ser un solo Spring JAR, con todos los archivos .class en él.

Actualización: Cinco años después, es posible que Jigsaw aún tenga algunos problemas que resolver.

duffymo
fuente
5
¿Qué pasa si todavía necesita usar exactamente el mismo módulo, pero dos versiones diferentes? ¿No deberían simplemente agregar algún tipo de soporte para que dos versiones de las mismas clases puedan coexistir?
Didier A.
7
esta publicación es engañosa dado lo que está programado para ser lanzado en Java 9. Es posible que haya sido precisa en el momento de escribir este artículo.
xenoterracide
1
mreinhold.org/blog/jigsaw-complete Proyecto completo y publicado para Java 9
Zasz
@xenoterracide, no puedes culpar a alguien por no ser clarividente. La publicación precedió a Java 9 por cinco años. ¿Estás revisando también todas las respuestas de Jon Skeet?
duffymo
Esta publicación no envejeció bien. Los módulos de Java no resuelven intencionalmente el problema del control de versiones, consulte este hilo . Todavía no hay una manera fácil de sortear a nuestros viejos amigos NoSuchMethodErrory NoClassDefFoundError.
Tamas Hegedus
45

AFAIK El plan es hacer que el JRE sea más modular. Es decir, tiene frascos más pequeños que son opcionales y / o puede descargar / actualizar solo la funcionalidad que necesita.

Es para hacerlo menos hinchado y darle la opción de eliminar módulos heredados que quizás la mayoría de la gente no usa.

Peter Lawrey
fuente
7
La respuesta aceptada es válida, pero esta respuesta es mejor porque explica los efectos deseados reales. +1, bien merecido.
Silviu Burcea
Tengo curiosidad, ¿esto también significa que si tengo Google Guava como dependencia, pero solo uso ImmutableList en él, entonces solo puedo importar dependencias de ImmutableList y dejar el resto de las clases de Guava fuera?
tmn
1
@ThomasN. cuando usa un, importtodo lo que hace es introducir esta clase en el espacio de nombres de la clase para el compilador. Si no lo usa, no aparecerá en el código de bytes creado. Si realmente usa la clase, necesita tener esa clase y todas las clases que usa en tiempo de ejecución. En teoría, podría crear una versión reducida de la API de guayaba que solo tuviera lo que necesita y usar ese JAR en su lugar. En realidad, esto es propenso a errores y no es muy útil en la mayoría de los casos, y termina agregando todo el JAR como se publicó.
Peter Lawrey
43

Sobre la base de la marca Reinhold 's discurso en Devoxx Bélgica , Proyecto de Jigsaw se va a abordar dos puntos débiles principales:

  1. Classpath
  2. JDK monolítico masivo

¿Qué pasa con Classpath?

Todos sabemos sobre el JAR Hell . Este término describe todas las diversas formas en que el proceso de carga de clases puede terminar sin funcionar. Las limitaciones más conocidas de classpath son:

  • Es difícil saber si hay conflictos. Las herramientas de compilación como maven pueden hacer un buen trabajo en función de los nombres de los artefactos, pero si los artefactos en sí tienen nombres diferentes pero el mismo contenido, podría haber un conflicto.
  • El problema fundamental de los archivos jar es que no son componentes. Son solo un montón de contenedores de archivos que se buscarán linealmente. Classpath es una forma de buscar clases independientemente de los componentes en los que se encuentren, los paquetes en los que se encuentren o su uso previsto.

JDK monolítico masivo

La gran naturaleza monolítica de JDK causa varios problemas:

  • No cabe en dispositivos pequeños. Aunque los dispositivos pequeños de tipo IoT tienen procesadores capaces de ejecutar una VM de clase SE, no tienen necesariamente la memoria para almacenar todo el JDK, especialmente, cuando la aplicación solo usa una pequeña parte de él.
  • Incluso es un problema en la nube. La nube se trata de optimizar el uso del hardware, si tiene miles de imágenes que contienen todo el JDK pero las aplicaciones solo usan una pequeña parte, sería un desperdicio.

Módulos: la solución común

Para abordar los problemas anteriores, tratamos los módulos como un nuevo tipo fundamental de componente de programa Java. Un módulo es una colección de código y datos autodescriptivos con nombre. Su código está organizado como un conjunto de paquetes que contienen tipos, es decir, clases e interfaces Java; sus datos incluyen recursos y otros tipos de información estática.

Para controlar cómo su código se refiere a tipos en otros módulos, un módulo declara qué otros módulos necesita para ser compilado y ejecutado. Para controlar cómo el código de otros módulos se refiere a los tipos de sus paquetes, un módulo declara cuál de esos paquetes exporta.

El sistema de módulos ubica los módulos requeridos y, a diferencia del mecanismo de ruta de clases, asegura que el código en un módulo solo puede hacer referencia a tipos en los módulos de los que depende. Los mecanismos de control de acceso del lenguaje Java y la máquina virtual Java evitan que el código acceda a tipos en paquetes que no son exportados por sus módulos de definición.

Además de ser más confiable, la modularidad podría mejorar el rendimiento. Cuando el código en un módulo se refiere a un tipo en un paquete, se garantiza que ese paquete se definirá en ese módulo o precisamente en uno de los módulos leídos por ese módulo. Cuando se busca la definición de un tipo específico, por lo tanto, no es necesario buscarlo en múltiples módulos o, peor aún, a lo largo de toda la ruta de clases.

JEP a seguir

Jigsaw es un proyecto enorme que se lleva a cabo durante varios años. Tiene una cantidad impresionante de JEP que son excelentes lugares para obtener más información sobre el proyecto. Algunos de estos PEC son los siguientes:

  • JEP 200: el JDK modular : utilice el sistema de módulo de plataforma Java (JPMS) para modularizar el JDK
  • JEP 201: Código fuente modular : reorganice el código fuente JDK en módulos, mejore el sistema de compilación para compilar módulos y haga cumplir los límites de los módulos en el momento de la compilación
  • JEP 261: Sistema de módulos : Implementar el sistema de módulos de la plataforma Java, según lo especificado por JSR 376, junto con los cambios y mejoras relacionados específicos de JDK
  • JEP 220: Imágenes modulares en tiempo de ejecución : reestructura las imágenes en tiempo de ejecución JDK y JRE para acomodar módulos y mejorar el rendimiento, la seguridad y la capacidad de mantenimiento
  • JEP 260: Encapsular la mayoría de las API internas : haga que la mayoría de las API internas del JDK sean inaccesibles de forma predeterminada, pero deje accesibles algunas API internas críticas y ampliamente utilizadas, hasta que existan reemplazos compatibles para todas o la mayoría de sus funciones.
  • PEC 282: JLINK: El Enlazador de Java : Crear una herramienta que puede montar y optimizar un conjunto de módulos y sus dependencias imagen en tiempo de ejecución en una costumbre como se define en la PEC 220

Palabras de clausura

En la edición inicial del informe El estado del sistema de módulos , Mark Reinhold describe los objetivos específicos del sistema de módulos de la siguiente manera:

  • Configuración confiable , para reemplazar el mecanismo de ruta de clases frágil y propenso a errores con un medio para que los componentes del programa declaren dependencias explícitas entre sí, junto con
  • Fuerte encapsulación , para permitir que un componente declare cuáles de sus tipos públicos son accesibles a otros componentes y cuáles no.

Estas características beneficiarán a los desarrolladores de aplicaciones, desarrolladores de bibliotecas e implementadores de la propia plataforma Java SE de forma directa y, también, indirectamente, ya que permitirán una plataforma escalable, una mayor integridad de la plataforma y un rendimiento mejorado.

Ali Dehghani
fuente
3
Mark Reinhold es el arquitecto jefe del Java Platform Group en Oracle, y esta respuesta es esencialmente su respuesta directa a esa pregunta exacta.
Jay
1
Para cuantificar eso, HelloWorld puede usar 15 MB en lugar de 553 MB; youtu.be/rFhhLXcOBsk?t=31m12s
user1133275
14

En aras del argumento, afirmemos que Java 8 (y versiones anteriores) ya tiene una "forma" de módulos (jar) y un sistema de módulos (la ruta de clases). Pero existen problemas bien conocidos con estos.

Al examinar los problemas, podemos ilustrar la motivación de Jigsaw. (Lo siguiente supone que no estamos utilizando OSGi, módulos JBoss, etc., que ciertamente ofrecen soluciones).

Problema 1: el público también público

Considere las siguientes clases (suponga que ambas son públicas):

com.acme.foo.db.api.UserDao
com.acme.foo.db.impl.UserDaoImpl

En Foo.com, podríamos decidir que nuestro equipo debería usar UserDaoy no usarUserDaoImpl directamente. Sin embargo, no hay forma de hacer cumplir eso en la ruta de clases.

En Jigsaw, un módulo contiene un module-info.javaarchivo que nos permite indicar explícitamente qué es público para otros módulos. Es decir, el público tiene matices. Por ejemplo:

// com.acme.foo.db.api.UserDao is accessible, but
// com.acme.foo.db.impl.UserDaoImpl is not 
module com.acme.foo.db {
    exports com.acme.foo.db.api;
}

Problema 2: la reflexión es desenfrenada

Dadas las clases en el n. ° 1, alguien aún podría hacer esto en Java 8:

Class c = Class.forName("com.acme.foo.db.impl.UserDaoImpl");
Object obj = c.getConstructor().newInstance();

Es decir: la reflexión es poderosa y esencial, pero si no se controla, puede usarse para llegar a lo interno de un módulo de formas indeseables. Mark Reinhold tiene un ejemplo bastante alarmante . (La publicación SO está aquí ).

En Jigsaw, encapsulado fuerte ofrece la capacidad de denegar el acceso a una clase, incluida la reflexión. (Esto puede depender de la configuración de la línea de comandos, pendiente de la especificación técnica revisada para JDK 9.) Tenga en cuenta que debido a que Jigsaw se usa para el propio JDK, Oracle afirma que esto permitirá al equipo de Java innovar las partes internas de la plataforma más rápidamente.

Problema 3: la ruta de clases borra las relaciones arquitectónicas

Un equipo suele tener un modelo mental sobre las relaciones entre los frascos. Por ejemplo, foo-app.jarpuede usar foo-services.jarwhich uses foo-db.jar. Podríamos afirmar que las clases en foo-app.jarno deben pasar por alto "la capa de servicio" y utilizarlas foo-db.jardirectamente. Sin embargo, no hay forma de hacer cumplir eso a través del classpath. Mark Reinhold menciona esto aquí .

En comparación, Jigsaw ofrece un modelo de accesibilidad explícito y confiable para módulos.

Problema 4: tiempo de ejecución monolítico

El tiempo de ejecución de Java es monolítico rt.jar. En mi máquina, son más de 60 MB con 20k clases. En una era de microservicios, dispositivos IoT, etc., no es deseable tener Corba, Swing, XML y otras bibliotecas en el disco si no se están utilizando.

Jigsaw divide el propio JDK en muchos módulos; por ejemplo, java.sql contiene las conocidas clases SQL. Esto tiene varios beneficios, pero uno nuevo es la jlinkherramienta. Suponiendo que una aplicación está completamente modularizada, jlinkgenera una imagen en tiempo de ejecución distribuible que se recorta para contener solo los módulos especificados (y sus dependencias). De cara al futuro, Oracle prevé un futuro en el que los módulos JDK se compilan con anticipación en código nativo. Aunque jlinkes opcional y la compilación de AOT es experimental, son indicaciones importantes de hacia dónde se dirige Oracle.

Problema 5: control de versiones

Es bien sabido que el classpath no nos permite usar múltiples versiones del mismo jar: por ejemplo bar-lib-1.1.jary bar-lib-2.2.jar.

Jigsaw no aborda este problema; Mark Reinhold expone la razón fundamental aquí . La esencia es que Maven, Gradle y otras herramientas representan un gran ecosistema para la gestión de la dependencia, y otra solución será más dañina que beneficiosa.

Cabe señalar que otras soluciones (por ejemplo, OSGi) sí abordan este problema (y otros, además de la # 4).

Línea de fondo

Éstos son algunos de los puntos clave para Jigsaw, motivados por problemas específicos.

Tenga en cuenta que explicar la controversia entre Jigsaw, OSGi, JBoss Modules, etc. es una discusión separada que pertenece a otro sitio de Stack Exchange. Hay muchas más diferencias entre las soluciones que las que se describen aquí. Además, hubo suficiente consenso para aprobar la Boleta de reconsideración de revisión pública para JSR 376.

Miguel Pascua
fuente
3

Este artículo explica en detalle los problemas que tanto OSGi como JPMS / Jigsaw intentan resolver:

"Java 9, OSGi y el futuro de la modularidad" [22 de septiembre de 2016]

También profundiza en los enfoques de OSGi y JPMS / Jigsaw. A partir de ahora, parece que los autores no enumeraron casi ningún pros práctico para JPMS / Jigsaw en comparación con OSGi maduro (16 años).

uvsmtid
fuente