NOTA: As seguintes palavras como "Bridge", "Conversão" e "encadernação" são basicamente o mesmo conceito.
Log4j-over-slf4j e slf4j-log4j12 são dois pacotes JAR relacionados ao sistema de log Java. Quando aparecem sob o caminho de classe ao mesmo tempo, podem causar exceções de transbordamento de pilha. As informações de exceção são aproximadamente as seguintes (extraído do documento oficial do site SLF4J detectou Log4j-over-slf4j.jar e Slf4j-Log4j12.jar no caminho da classe, preenectar StackOverflowerRor):
Exceção no tópico "Main" java.lang.stackoverflowerror
em java.util.hashtable.containskey (hashtable.java:306)
em org.apache.log4j.log4jloggerFactory.getLogger (log4jloggerFactory.java:36)
em org.apache.log4j.logmanager.getLogger (LogManager.java:39)
em org.slf4j.impl.log4jloggerFactory.getLogger (log4jloggerFactory.java:73)
em org.slf4j.loggerfactory.getLogger (LoggerFactory.java:249)
em org.apache.log4j.category.
em org.apache.log4j.logger .. <ingem> (Logger.java:35)
em org.apache.log4j.log4jloggerFactory.getLogger (log4jloggerFactory.java:39)
em org.apache.log4j.logmanager.getLogger (LogManager.java:39)
em org.slf4j.impl.log4jloggerFactory.getLogger (log4jloggerFactory.java:73)
em org.slf4j.loggerfactory.getLogger (LoggerFactory.java:249)
em org.apache.log4j.category .. <ingem> (category.java:53)
em org.apache.log4j.logger .. <ingem> (Logger.java:35)
em org.apache.log4j.log4jloggerFactory.getLogger (log4jloggerFactory.java:39)
em org.apache.log4j.logmanager.getLogger (LogManager.java:39)
Linhas subsequentes omitidas ...
Sistema de registro existente
Antes de analisar os motivos específicos para essa exceção, é necessário entender rapidamente o sistema de registro Java existente. A figura a seguir é um diagrama do sistema de registro Java existente:
A imagem acima não é muito precisa, mas pode exibir claramente a estrutura principal do sistema de log Java existente. O sistema de registro Java pode ser dividido aproximadamente em três partes: interface da fachada de log, ponte e estrutura de logwork de implementação específica.
Existem muitos tipos de estruturas de log Java. O mais simples é o próprio Java.util.Util.Logging, e o mais clássico é o Log4J. Mais tarde, um logback com melhor desempenho que o LOG4J apareceu, para que outras estruturas de log não sejam muito usadas. Certamente é possível que os aplicativos usem diretamente as APIs dessas estruturas de log específicas para atender aos requisitos de saída de log, mas como as APIs entre cada estrutura de log são geralmente incompatíveis, faz isso faz com que o aplicativo perca a flexibilidade de substituir a estrutura de log.
Uma opção mais razoável do que usar diretamente a API específica da estrutura de logs é usar a interface da fachada de log. A interface da fachada de log fornece um conjunto de APIs independentes de estruturas de log específicas. Os aplicativos podem se dissipar de estruturas de log específicas usando essas APIs independentes, que são semelhantes ao JDBC. A interface mais antiga da fachada de log foi lançada com o Commons, mas a mais popular no momento é o SLF4J.
A interface da fachada de log geralmente geralmente não possui o recurso de saída de log real. Ele ainda precisa chamar a API específica da estrutura de log na parte inferior, ou seja, ela realmente precisa ser usada em combinação com a estrutura de log específica. Como existem muitas estruturas de log específicas e são principalmente incompatíveis entre si, se a interface da fachada de log for combinada com qualquer estrutura de log, poderá exigir uma ponte correspondente, assim como a combinação entre JDBC e vários bancos de dados diferentes requer um driver JDBC correspondente.
Deve-se notar que, como mencionado anteriormente, a imagem acima não é precisa, essa é apenas a parte principal e a situação real nem sempre é uma linha única de ida de "interface da fachada de log-> ponte-> estrutura de log". De fato, as pontes independentes às vezes não são necessárias, e não é apenas uma ponte que converte a API da fachada de log em uma API específica da estrutura de log. Também existem pontes que convertem a API da estrutura de log na API da fachada de log.
Para ser franco, a chamada "ponte" nada mais é do que uma implementação pseudo de um certo conjunto de APIs. Esta implementação não conclui diretamente as funções declaradas pela API, mas chama outras APIs com funções semelhantes. Isso completa a transição de "um conjunto de APIs" para "outras APIs". Se houver duas pontes, a para b.jar e b-a-a.jar, você poderá imaginar o que acontecerá quando o aplicativo começar a chamar a API de A ou B. Este é o princípio básico da exceção de excesso de pilha que foi introduzida pela primeira vez.
Slf4j encaminhamento de encaminhamento
O exposto acima é apenas uma explicação geral do sistema de registro Java existente e não é possível explicar o problema em detalhes. Precisamos entender melhor a situação de ponte entre o SLF4J e a estrutura de log específica.
Slf4j Bridges para quadros de log específicos
A imagem a seguir vem do documento oficial do SLF4J, encadernação de documentos com uma estrutura de registro no momento da implantação:
Você pode ver que existem muitas soluções para o SLF4J combinar com estruturas de log específicas. Obviamente, a camada superior (camada de aplicação verde) de cada solução é unificada. Eles chamam diretamente a API fornecida pelo SLF4J (camada de API abstrata azul clara) e confiam no slf4j-api.jar. Então, se você fizer a API SLF4J para baixo, ela será muito gratuita e você poderá usar quase todas as estruturas de registro específicas. Observe que a segunda camada na figura é azul claro. Olhando para a lenda no canto inferior esquerdo, podemos ver que isso representa a API de log abstrata, o que significa que eles não são implementações concretas. Se a camada inferior não for combinada com nenhuma implementação específica da estrutura de log como a primeira solução à esquerda, o log não poderá ser emitido ( não tem certeza se pode ser emitido para saída padrão por padrão ).
A terceira camada na imagem obviamente não é tão arrumada quanto a primeira e a segunda camadas, porque a estrutura de log específica começou a estar envolvida aqui.
Primeiro, vamos olhar para os dois blocos azuis do lago no meio do terceiro andar, que são a camada adaptadora, ou seja, a ponte. A ponte SLF4J-LOG4J12.JAR, à esquerda, pode dizer que é uma ponte do SLF4J para LOG4J com base no nome. Da mesma forma, o SLF4J-JDK14.JAR à direita é uma ponte implementada pelo SLF4J para os logs nativos de Java. A próxima camada deles é a implementação da estrutura de log correspondente. O código de implementação do log4j é log4j.jar, e o código de implementação JUL já está incluído no tempo de execução da JVM e não requer um pacote de jar separado.
Vejamos os três blocos azuis escuros restantes no terceiro andar. Os três também são implementações específicas da estrutura de registro, mas não exigem pontes porque eles próprios implementam diretamente a API SLF4J. Escusado será dizer que slf4j-simple.jar e slf4j-nop.jar, você pode dizer que um é uma implementação simples do SLF4J e o outro é uma implementação vazia do SLF4J, que não é muito útil em tempos normais. A razão pela qual o Logback também implementa a API SLF4J é porque o Logback e o SLF4J são da mesma pessoa, que também é o autor de Log4J.
Todos os pacotes de jar cinza na terceira camada têm caixas vermelhas, o que significa que todas elas implementam diretamente a API SLF4J. No entanto, a implementação da API SLF4J pela Lake Blue Bridge não produz logs diretamente, mas chama a API de outras estruturas de log.
Outras API da estrutura de logs chamadas de volta ao SLF4J
Se apenas as pontes acima do SFL4J para outras estruturas de log existirem, pode não haver problemas. Mas, de fato, existe outro tipo de ponte, cujas funções são exatamente o oposto do exposto, elas convertem a API de outras estruturas de log na API SLF4J. A imagem a seguir vem do site oficial do SLF4J APIs Legacy Bridge:
A figura acima mostra todos os três casos que podem ligar com segurança ao SLF4J de outras APIs de estrutura de logs até agora.
Tomando o primeiro estojo no canto superior esquerdo como exemplo, quando o SLF4J subjacente é preenchido com a estrutura de logback, as APIs da estrutura de log que permitem que a camada superior volte para o SLF4J inclua log4j e Jul. Embora a JCL não seja uma implementação específica de uma estrutura de registro, sua API ainda pode ser chamada de volta ao SLF4J. Para implementar a conversão, o método é substituir o frasco original do quadro de log por um frasco de ponte específico listado na figura. Deve -se notar que a API de logback na API SLF4J não inclui a conversão da API de logback, porque o logback é originalmente uma implementação da API SLF4J.
Depois de ler as três situações, você descobrirá que quase todas as APIs de outras estruturas de log, incluindo a API da JCL, podem ser redirecionadas de volta ao SLF4J à vontade. Mas há uma única limitação de que a estrutura de log que recolhe ao SLF4J não pode ser a mesma que a estrutura de log para a qual o SLF4J está preenchendo atualmente. Essa limitação é para impedir que o a para b.jar e b-a-a.jar apareçam no caminho de classe ao mesmo tempo, resultando em A e B constantemente se chamando de forma recursiva e finalmente empilham o transbordamento. Atualmente, essa restrição não é garantida pela tecnologia, mas apenas pelo próprio desenvolvedor. É por isso que o site oficial do SLF4J enfatiza que todos os métodos razoáveis estão apenas nas três situações da imagem acima.
Nesse ponto, o princípio da exceção mostrado no início foi basicamente claro. Além disso, a partir da figura acima, podemos ver que pode haver combinações semelhantes às exceções não apenas LOG4J-over-slf4j e slf4j-log4j12. O site oficial do SLF4J também apontou outro par: jcl-over-slf4j.jar e slf4j-jcl.jar.
Exemplo de código
A análise anterior é teórica. Mesmo que o log4j-over-slf4j e slf4j-log4j12 sejam usados ao mesmo tempo no código real, as exceções podem não ocorrer necessariamente. O código a seguir chama a API do SLF4J para produzir o log, e o SLF4J é preenchido para Log4J:
teste de pacote; classe pública helloworld {public static void main (string [] args) {org.apache.log4j.basicconfigurator.configure (); org.slf4j.logger logger = org.slf4j.loggerFactorn.GetLogger (helloworld.cls);Configure o caminho de classe para configurar o pacote JAR (observe que o LOG4J é antes do log4j-over-slf4j):
Nesse caso, a execução do programa de teste pode gerar o log normalmente e não haverá exceção de estouro de pilha. Mas se você ajustar a ordem do jar no caminho de classe para:
A execução do programa de teste novamente fará com que uma exceção de estouro de pilha semelhante ao excesso de pilha inicial neste artigo. Você pode ver repetições periódicas óbvias:
Análise do gráfico de sequência
A imagem acima é um diagrama de coluna do programa de chamadas detalhado do transbordamento da pilha. A partir da chamada 1, ligue para 1.1, 1.1.1 ... finalmente, quando atinge 1.1.1.1.1 (a última chamada na figura), verifica -se que é exatamente o mesmo que 1, portanto o processo subsequente é completamente repetido.
Deve -se notar que o fusível inicial não é apenas LoggerFactory.getLogger () mostrado na figura. Existem várias outras chamadas diretas no aplicativo que podem desencadear exceções de transbordamento de pilhas. Por exemplo, no código de exemplo anterior, a primeira instrução org.apache.log4j.basicconfigurator.configure () é na verdade a primeira instrução org.apache.log4j.basicconfigurator.configure (), mas o número de chamadas de infinito mútuo subsequente é basicamente o mesmo como o figura anterior.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.