Nota: Las siguientes palabras como "puente", "conversión" y "vinculante" son básicamente el mismo concepto.
LOG4J-Over-SLF4J y SLF4J-LOG4J12 son dos paquetes JAR relacionados con el sistema de registro Java. Cuando aparecen debajo del ClassPath al mismo tiempo, pueden causar excepciones de desbordamiento de pila. La información de excepción es más o menos como sigue (extraída del documento del sitio web oficial de SLF4J detectado tanto log4j-over-slf4j.jar como slf4j-log4j12.Jar en la ruta de clase, adelantando a stackoverflowerror):
Excepción en el hilo "principal" java.lang.stackoverflowerror
en java.util.hashtable.containskey (hashtable.java:306)
en org.apache.log4j.log4jloggerFactory.getLogger (log4jloggerFactory.java:36)
en org.apache.log4j.logmanager.getlogger (logmanager.java:39)
en org.slf4j.impl.log4jloggerFactory.getLogger (log4jloggerFactory.java:73)
en org.slf4j.loggerFactory.getLogger (loggerFactory.java:249)
en org.apache.log4j.category. <Init> (categoría. Java:53)
en org.apache.log4j.logger .. <Init> (logger.java:35)
en org.apache.log4j.log4jloggerFactory.getLogger (log4jloggerFactory.java:39)
en org.apache.log4j.logmanager.getlogger (logmanager.java:39)
en org.slf4j.impl.log4jloggerFactory.getLogger (log4jloggerFactory.java:73)
en org.slf4j.loggerFactory.getLogger (loggerFactory.java:249)
en org.apache.log4j.category .. <itin> (category.java:53)
en org.apache.log4j.logger .. <Init> (logger.java:35)
en org.apache.log4j.log4jloggerFactory.getLogger (log4jloggerFactory.java:39)
en org.apache.log4j.logmanager.getlogger (logmanager.java:39)
Líneas posteriores omitidas ...
Sistema de registro existente
Antes de analizar las razones específicas de esta excepción, es necesario comprender rápidamente el sistema de registro Java existente. La siguiente figura es un diagrama del sistema de registro Java existente:
La imagen de arriba no es muy precisa, pero puede mostrar claramente la estructura principal del sistema de registro Java existente. El sistema de registro de Java se puede dividir aproximadamente en tres partes: interfaz de fachada de registro, puente e implementación específica del marco de registro.
Hay muchos tipos de marcos de registro de Java. El más simple es el propio java.util.logging, y el más clásico es log4j. Más tarde, apareció un logback con mejor rendimiento que LOG4J, por lo que otros marcos de registro no se usan muy comúnmente. Ciertamente es posible que las aplicaciones usen directamente las API de estos marcos de registro específicos para cumplir con los requisitos de salida del registro, pero dado que las API entre cada marco de registro generalmente son incompatibles, hacerlo hace que la aplicación pierda la flexibilidad de reemplazar el marco de registro.
Una opción más razonable que directamente utilizando la API de registro de registro específica es usar la interfaz de fachada de registro. La interfaz de fachada de registro proporciona un conjunto de API independientes de marcos de registro específicos. Las aplicaciones pueden desacoplarse de marcos de registro específicos utilizando estas API independientes, que es similar a JDBC. La primera interfaz de fachada de registro fue el registro de los bienes comunes, pero la más popular en la actualidad es SLF4J.
La interfaz de fachada de registro en sí generalmente no tiene la capacidad de salida de registro real. Todavía necesita llamar a la API específica del marco de registro en la parte inferior, es decir, en realidad debe usarse en combinación con el marco de registro específico. Dado que hay muchos marcos de registro específicos y en su mayoría son incompatibles entre sí, si la interfaz de fachada de registro se combina con cualquier marco de registro, puede requerir un puente correspondiente, al igual que la combinación entre JDBC y varias bases de datos diferentes requiere un controlador JDBC correspondiente.
Cabe señalar que, como se mencionó anteriormente, la imagen de arriba no es precisa, esta es solo la parte principal, y la situación real no siempre es una línea simple de "Interfaz de fachada de registro-> Bridge-> log Framework". De hecho, a veces no se necesitan puentes independientes, y no es solo un puente que convierte la API de fachada de registro en una API de marco de registro específica. También hay puentes que convierten la API del marco de registro en la API de fachada log.
Para decirlo sin rodeos, el llamado "puente" no es más que una pseudo implementación de un cierto conjunto de API. Esta implementación no completa directamente las funciones declaradas por la API, pero llama a otras API con funciones similares. Esto completa la transición de "un conjunto de API" a "otras API". Si hay dos puentes, A-to-B.jar y B-to-A.jar, entonces puede imaginar lo que sucederá cuando la aplicación comience a llamar a la API de A o B. Este es el principio básico de la excepción de desbordamiento de la pila que se introdujo por primera vez.
Atinción de reenvío SLF4J
Lo anterior es solo una explicación general del sistema de registro Java existente, y no es posible explicar el problema en detalle. Necesitamos comprender mejor la situación de puente entre SLF4J y el marco de registro específico.
puentes slf4j a marco de registro específico
La siguiente imagen proviene de la vinculación del documento del sitio web oficial de SLF4J con un marco de registro en el momento de la implementación:
Puede ver que hay muchas soluciones para que SLF4J se combine con marcos de registro específicos. Por supuesto, la capa superior (capa de aplicación verde) de cada solución está unificada. Llaman directamente a la API proporcionada por SLF4J (capa API abstracta azul claro) y confían en SLF4J-API.JAR. Luego, si realiza la API SLF4J hacia abajo, será muy gratuito y puede usar casi todos los marcos de registro específicos. Tenga en cuenta que la segunda capa de la figura es azul claro. Mirando la leyenda en la esquina inferior izquierda, podemos ver que esto representa la API de registro abstracta, lo que significa que no son implementaciones concretas. Si la capa inferior no se combina con ninguna implementación específica del marco de registro como la primera solución a la izquierda, entonces el registro no puede ser emitido ( no es seguro si puede salirse a la salida estándar de forma predeterminada ).
La tercera capa en la imagen obviamente no es tan ordenada como la primera y la segunda capas, porque el marco de registro específico ha comenzado a involucrarse aquí.
Primero, veamos los dos bloques azules del lago en el medio del tercer piso, que son la capa adaptadora, es decir, el puente. El puente SLF4J-LOG4J12.JAR a la izquierda puede decir que es un puente de SLF4J a LOG4J en función del nombre. Del mismo modo, el SLF4J-JDK14.Jar a la derecha es un puente implementado por SLF4J a Java Native Logs. La siguiente capa de ellos es la implementación del marco de registro correspondiente. El código de implementación de log4j es log4j.jar, y el código de implementación de JUL ya está incluido en el tiempo de ejecución JVM y no requiere un paquete JAR por separado.
Veamos los tres bloques azul oscuro restantes en el tercer piso. Los tres también son implementaciones específicas del marco de registro, pero no requieren puentes porque ellos mismos implementan directamente la API SLF4J. No hace falta decir que slf4j-simple.jar y slf4j-nop.jar, puede decir que uno es una implementación simple de slf4j y la otra es una implementación vacía de Slf4j, que no es muy útil en los tiempos normales. La razón por la cual Logback también implementa la API SLF4J se dice que Logback y Slf4j son de la misma persona, que también es autor de LOG4J.
Todos los paquetes de Gray JAR en la tercera capa tienen cajas rojas, lo que significa que todos implementan directamente la API SLF4J. Sin embargo, la implementación de la API SLF4J por el Puente Blue Lake no produce registros directamente, sino que llama a la API de otros marcos de registro.
Otras llamadas de API de registro de registro de regreso a SLF4J
Si solo existen los puentes anteriores de SFL4J a otros marcos de registro, puede no haber ningún problema. Pero de hecho, hay otro tipo de puente, cuyas funciones son exactamente lo opuesto a lo anterior, convierten la API de otros marcos de registro en la API SLF4J. La siguiente imagen proviene del documento oficial del sitio web de SLF4J, API Legacy Bridge:
La figura anterior muestra los tres casos que pueden volver a llamar de manera segura a SLF4J desde otras API del marco de registro hasta ahora.
Tomando el primer caso en la esquina superior izquierda como ejemplo, cuando el SLF4J subyacente está unido al marco logback, las API del marco de registro que permiten que la capa superior vuelva a unir a SLF4J incluye log4j y jul. Aunque JCL no es una implementación específica de un marco de registro, su API aún se puede volver a llamar a SLF4J. Para implementar la conversión, el método es reemplazar el frasco de cuadro de registro original con un frasco de puente específico en la figura. Cabe señalar que la API logback a la API SLF4J no incluye la conversión de la API logback, porque logback es originalmente una implementación de la API SLF4J.
Después de leer las tres situaciones, encontrará que casi todas las API de otros marcos de registro, incluida la API JCL, pueden redirigirse a SLF4J a voluntad. Pero hay una única limitación de que el marco de registro que vuelve a llamar a SLF4J no puede ser el mismo que el marco de registro al que SLF4J actualmente está uniendo. Esta limitación es evitar que A-to-B.jar y B-to-a.jar aparezcan en la clase de clases al mismo tiempo, lo que resulta en que A y B se llamen constantemente de manera recursiva, y finalmente apilando el desbordamiento. En la actualidad, esta restricción no está garantizada por la tecnología, sino solo por el desarrollador mismo. Es por eso que el sitio web oficial de SLF4J enfatiza que todos los métodos razonables están solo en las tres situaciones en la imagen de arriba.
En este punto, el principio de la excepción que se muestra al principio ha sido básicamente claro. Además, de la figura anterior, podemos ver que puede haber combinaciones similares a las excepciones no solo log4j-over-slf4j y slf4j-log4j12. El sitio web oficial de SLF4J también señaló otro par: jcl-over-slf4j.jar y slf4j-jcl.jar.
Ejemplo de código
El análisis anterior es teórico. Incluso si LOG4J-Over-SLF4J y SLF4J-LOG4J12 se usan al mismo tiempo en el código real, las excepciones pueden no ocurrir necesariamente. El siguiente código llama a la API de SLF4J para emitir el registro, y SLF4J se une a log4j:
prueba de paquete; public class HelloWorld {public static void main (string [] args) {org.apache.log4j.basicconfigurator.configure (); org.sslf4j.logger logger = org.sslf4j.loggerFactory.getLogger (hellowOrld.class); logger.info ("hello world");Configure el classpath para configurar el paquete JAR (tenga en cuenta que LOG4J es antes de log4j-over-slf4j):
En este caso, ejecutar el programa de prueba puede generar el registro normalmente y no habrá excepción de desbordamiento de pila. Pero si ajusta el pedido de jar en el classpath a:
Ejecutar el programa de prueba nuevamente causará una excepción de desbordamiento de pila similar al desbordamiento inicial de la pila en este artículo. Puedes ver repeticiones periódicas obvias:
Análisis de la tabla de secuencia
La imagen de arriba es un diagrama detallado de la columna del programa de llamadas del desbordamiento de pila. A partir de llamar al 1, llame a 1.1, 1.1.1 ... Finalmente, cuando alcanza 1.1.1.1.1 (la última llamada en la figura), se encuentra que es exactamente lo mismo que 1, por lo que el proceso posterior se repite por completo.
Cabe señalar que el fusible inicial no es solo loggerFactory.getLogger () que se muestra en la figura. Hay varias otras llamadas directas en la aplicación que pueden activar las excepciones de desbordamiento de pila. Por ejemplo, en el código de ejemplo anterior, la primera declaración org.apache.log4j.basicconfigurator.configure () es en realidad la primera declaración org.apache.log4j.basicconfigurator.configure (), pero el posterior proceso de llamada recursiva infinita mutua es básicamente el mismo que la figura anterior.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.