secuencia
Este artículo estudia principalmente algunas precauciones para migrar a Java9.
Tipos de migración
Algunas cosas a tener en cuenta
Clases ilegibles
Por ejemplo, Sun.security.x509 se clasifica en el módulo Java.Base en Java9, pero el módulo no exporta el paquete.
Puede modificar la configuración de exportaciones agregando --Add-Exports java.base/sun.security.x509 = All-Unnamed cuando se ejecuta
Clase interna
Por ejemplo, Sun.misc.unsafe originalmente quería usar el equipo de Oracle JDK, pero debido a que estas clases son demasiado utilizadas, Java9 ha hecho compromisos para ser compatibilidad con retroceso, pero solo clasificó estas clases en el módulo JDK.Unsupported, y no limitó su lectura.
➜ ~ java -d jdk.unsupportedjdk.unsupported@9exports com.sun.nio.fileExports Sun.Miscexports Sun.Reflectrectires java.Base ordenado con sol.miscopens sol.reflect
Clase eliminada
Java9 eliminó a Sun.misc.Base64Encoder, en este caso, solo puede usar otras API, como Java.util.Base64
classpath vs módulo
Java9 introdujo un sistema de módulos, y su propio JDK también se modularizó, y se introdujo el ritmo de módulo para bloquear classpath. Es decir, el ritmo de módulo se prefiere en Java9. Después de todo, JDK en sí es modular. Si la aplicación en sí no es modular, Java9 se modulariza implícitamente a través de módulos sin nombre y mecanismos de módulos automáticos. Por supuesto, ClassPath puede continuar utilizándose en Java9, como el uso de módulos.
Un frasco sin modularidad se clasificará como módulos no identificados en classpath; En Module-Path, se creará automáticamente como módulos automáticos (un módulo automático declarará que Transitive depende de todos los módulos nombrados y sin nombre, y luego exportará su propio paquete)
El nombre de un paquete no puede aparecer en varios módulos (paquetes divididos)
Debido a que las exportaciones se pueden especificar a otros módulos en módulos, si múltiples módulos exportan el mismo nombre del paquete, causará confusión. Especialmente si hay otras bibliotecas de clase que requieren estos dos módulos al mismo tiempo, no sabe a qué módulo debe ser referenciado.
Dependencias transitivas
Si los parámetros de la interfaz o el tipo de retorno de un módulo usan las clases de otros módulos, se recomienda requerir módulos transitivos de los que depende.
Tenga cuidado con las dependencias circulares
Al diseñar módulos, considere si habrá dependencias circulares tanto como sea posible. Si es así, debe rediseñarlos.
Utilice servicios para implementar dependencias opcionales
Los servicios son particularmente adecuados para desacoplar las dependencias de las personas que llaman y las clases de implementación. Si la interfaz tiene múltiples clases de implementación, la persona que llama no necesita requerir todas las clases de implementación, pero solo requiere la interfaz Requerir, y usar el tipo de servicios para cargar instancias de la clase de implementación. El desacoplamiento se logra agregando dinámicamente módulos de implementación en el ritmo de módulo.
Administración de versiones del módulo
Module-Info.java no admite declarar números de versión, pero al crear paquetes JAR, puede configurarlos a través de--Module-Version. Sin embargo, cuando el sistema del módulo busca módulos, todavía usa el nombre del módulo para buscar (si hay múltiples módulos duplicados en el ritmo de módulo, el sistema de módulos sabrá usar el primero encontrado e ignorar automáticamente el módulo posterior con el mismo nombre). El problema de dependencia de la versión no está dentro del alcance de la solución del sistema del módulo, y se deja en las herramientas de gestión de dependencias como Maven para administrar.
Acceso de recursos del módulo
Después de la modularización, el archivo de recursos también está protegido, y el módulo solo puede acceder al archivo de recursos del módulo en sí. Si se requiere acceso al módulo cruzado, también debe usar el Modulelayer para encontrar el módulo de destino y luego llamar al módulo de destino para cargar el archivo de recursos del módulo.
Uso de la reflexión
Esto implica el problema de reflexión profunda. La llamada reflexión profunda es llamar al elemento no público de una clase a través de la reflexión. Las exportaciones de Module-Info.Java declaran que el paquete solo permite la clase a la que el paquete pertenece directamente para permitir el acceso a su elemento público, y no permite las llamadas de reflexión a elementos no públicos.
La reflexión necesita declaraciones especiales que se permitan en el sistema de módulos (utilizando declaraciones de apertura para permitir una reflexión profunda), lo que conduce a muchas bibliotecas de clase que usan reflexión como Spring, que requiere una configuración adicional para migrar a Java9. Hay dos soluciones: una es abrir el nombre del paquete a los módulos que necesitan reflexión, como Spring.Beans, etc.; El otro es abrir directamente todo el módulo.
El permiso predeterminado --leLegal-access = permiso, y esta configuración solo se aplica a los paquetes antes de Java9 que no se les permite acceder en Java9, y no es aplicable a nuevos paquetes a los que no se les permite acceder en Java9. (Se recomienda establecer negar cuando migra a un sistema modular)
Sin embargo, en el sistema de módulos, los nombres de los paquetes son diferentes y no hay una relación de herencia. Por ejemplo, com.service.func1 y com.service.func2 son paquetes diferentes. No puede simplemente abrir com.service, pero debe especificarlos por separado, lo que conduce a más paquetes que requieren apertura. Por lo tanto, abrir todo el módulo puede ser más fácil de usar, pero también es un enfoque relativamente aproximado.
El método anterior es hacer cambios en el módulo original-Info.java. Otro método es modificar la relación original a través del comando especificado al ejecutar Java o Javac. Por ejemplo
java ... --Add-opens fource-módulo/fuente-paquete = módulo de destino
Si necesita exportar a módulos no identificados, el módulo objetivo está completamente sin nombre
Por supuesto, si es un sistema nuevo, no se recomienda usar la reflexión. Se pueden usar Methodhandles y VarHandles.
Preguntas frecuentes y medidas
ClassNotFoundException/NoclassDefFoundError
Por ejemplo, javax.xml.bind.jaxbexception, Jaxb se ha clasificado en el módulo java.xml.bind y se agrega después del nombre de Java.
-Add-Modules java.xml.bind
Si desea ahorrar problemas, agregue $ java_home y toda la biblioteca de terceros al ritmo de módulo, y luego haga
-Add-Modules All-Module-Path
Acceso reflexivo ilegal por xxx al método java.lang.classloader.defineeclass
Las causas de la reflexión, porque el sistema anterior no tiene módulo-info, agregue parámetros al nombre de Java y modifíquelo.
--add-opens java.base/java.lang = All-Unnamed
Determinar el módulo de dependencia
Análisis a través de IDE o JDEPS
jdeps -classs -path 'classes/lib/*' -Cursive -Summary App.jar
JDEPS es solo un análisis de código estático. Si hay una clase que usa reflexión, no puede analizarla. Necesitas requerirlo manualmente. Si la dependencia es opcional, puede requerir estática.
Problemas de legibilidad para pruebas unitarias de módulo
Si se utiliza un módulo para la prueba unitaria, el módulo de prueba unitario se puede otorgar capacidades de legibilidad y reflexión del módulo de destino a través de --Add-Exports o --add-Opens en tiempo de ejecución. Además, debido a los problemas de paquetes divididos, el nombre del paquete de la clase de prueba unitaria no se puede duplicar con el nombre del paquete del módulo de destino. Resulta que la prueba del proyecto Maven
resumen
Puedes moverte a Java9 en dos pasos. Primero, no eres modular primero, solo estás ejecutando en JDK9 primero; Entonces eres modular.