亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

從log4j切換到logback后項目無法啟動的問題及解決方法

 更新時間:2023年01月17日 14:45:03   作者:幻影  
這篇文章主要介紹了從log4j切換到logback后項目無法啟動的問題及解決方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

1、背景

有個舊項目之前使用的是log4j2來打印日志的,因為某些原因,同事想換成logback。

換成logback改動也很簡單,大致就一下2步:

1.刪除log4j2.xml配置,新增logback.xml配置。剔除掉log4j相關的jar

2.引入slf4j (其實之前使用log4j2的時候就已經引入了,只是有些地方寫法不規(guī)范),

代碼【import org.apache.log4j.Logger】改成【import org.slf4j.Logger】(以及其他類似修改)

2、現(xiàn)象

全部改了之后,按道理說,應該就可以正常打印了。

但是啟動發(fā)現(xiàn),日志報錯:

ERROR {org.springframework.web.context.ContextLoader:356} - Context initialization failed java.lang.NoClassDefFoundError: org/apache/log4j/Logger at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) at java.lang.Class.getDeclaredMethods(Class.java:1975) at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:612) at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:524) at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:510) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:241) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors(AbstractAutowireCapableBeanFactory.java:1069) ★小技巧: 報錯的日志比較多,甚至有些報錯看起來有點莫名其妙。 不要慌,先找到最早的案發(fā)現(xiàn)場日志,或者搜一下關鍵字。 因為我們改的是日志,所以可以在報錯信息中搜一下log/log4j 等關鍵字

3、問題排查

看到這里第一反應應該是有代碼沒改全了。全局搜一下log4j關鍵字,果然發(fā)現(xiàn)還有一處:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    ...
    <property name="filters" value="config,stat,log4j,wall" />    <!-- 這里的log4j 需要改成 slf4j -->
    ...
</bean>

DruidDatasource中定義了com.alibaba.druid.filter.logging.LogFilter,他有3個子類,分別對應不同的日志打印實現(xiàn)方式

  • com.alibaba.druid.filter.logging.Slf4jLogFilter
  • com.alibaba.druid.filter.logging.Log4jFilter
  • com.alibaba.druid.filter.logging.CommonsLogFilter

那我們怎么知道是配置成slf4j、Slf4j、還是Slf4jLogger呢?可以看這里druid源碼文件【META-INF/druid-filter.properties】

druid.filters.default=com.alibaba.druid.filter.stat.StatFilter
druid.filters.stat=com.alibaba.druid.filter.stat.StatFilter
druid.filters.mergeStat=com.alibaba.druid.filter.stat.MergeStatFilter
druid.filters.counter=com.alibaba.druid.filter.stat.StatFilter
druid.filters.encoding=com.alibaba.druid.filter.encoding.EncodingConvertFilter
druid.filters.log4j=com.alibaba.druid.filter.logging.Log4jFilter
druid.filters.slf4j=com.alibaba.druid.filter.logging.Slf4jLogFilter
druid.filters.commonlogging=com.alibaba.druid.filter.logging.CommonsLogFilter
druid.filters.commonLogging=com.alibaba.druid.filter.logging.CommonsLogFilter
druid.filters.wall=com.alibaba.druid.wall.WallFilter
druid.filters.config=com.alibaba.druid.filter.config.ConfigFilter

無意中發(fā)現(xiàn)commonlogging這一行寫重復了,哈哈,這個不是我拷貝重的,源碼druid-1.0.18就是搞重復了!

改完之后,再啟動項目,發(fā)現(xiàn)問題依舊?。?/p>

4、問題分析

估計還是有別的地方寫明了需要使用log4j,為了驗證猜想,我設置了NoClassDefFoundError異常斷點,再次debug啟動。

進入斷點的時候,就發(fā)現(xiàn)還有個 HttpSessionManager 代碼中寫死了【import org.apache.log4j.Logger;】

這個是個第三方的jar,代碼是改不了的。就只能另尋他法了。

其實像這種情況,代碼寫死了使用log4j,想統(tǒng)一成slf4j,slf4j已經提供了解決方法。那就是引入log4j-over-slf4j。

使用log4j-over-slf4j取代log4j,這樣log4j接口輸出的日志就會通過log4j-over-slf4j路由到SLF4J上,這樣即使系統(tǒng)(包含使用的第三方jar庫,比如dubbo)都可以將日志最終路由到SLF4J上,進而集中輸出

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.1</version>
</dependency>

引入log4j-over-slf4j之后,再啟動,就ok了~

5、問題延伸

再回過頭看一下,log4j-over-slf4j到底給我們做了什么?

1.定義了【org.apache.log4j.Logger】對象,確保使用了log4j的老項目代碼不至于編譯不通過

package org.apache.log4j;
import org.slf4j.Marker;

public class Logger extends Category {
    ...
}

2.將【org.apache.log4j.Logger】的打印動作偷偷轉移到slf4j上。

Logger繼承自Category,并且實現(xiàn)了info、warn、error等打印日志的方法

package org.apache.log4j;

import java.util.Enumeration;
import org.apache.log4j.helpers.NullEnumeration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import org.slf4j.spi.LocationAwareLogger;

public class Category {
    private static final String CATEGORY_FQCN = Category.class.getName();
    private String name;
    protected Logger slf4jLogger;
    private LocationAwareLogger locationAwareLogger;
    private static Marker FATAL_MARKER = MarkerFactory.getMarker("FATAL");

    Category(String name) {
        this.name = name;
        this.slf4jLogger = LoggerFactory.getLogger(name);
        if (this.slf4jLogger instanceof LocationAwareLogger) {
            this.locationAwareLogger = (LocationAwareLogger)this.slf4jLogger;
        }
    }
    
    public Level getEffectiveLevel() {
        if (this.slf4jLogger.isTraceEnabled()) {
            return Level.TRACE;
        } else if (this.slf4jLogger.isDebugEnabled()) {
            return Level.DEBUG;
        } else if (this.slf4jLogger.isInfoEnabled()) {
            return Level.INFO;
        } else {
            return this.slf4jLogger.isWarnEnabled() ? Level.WARN : Level.ERROR;
        }
    }
    
    public void info(Object message) {
        this.differentiatedLog((Marker)null, CATEGORY_FQCN, 20, message, (Throwable)null);
    }
    
    void differentiatedLog(Marker marker, String fqcn, int level, Object message, Throwable t) {
        String m = this.convertToString(message);
        if (this.locationAwareLogger != null) {
            this.locationAwareLogger.log(marker, fqcn, level, m, (Object[])null, t);
        } else {
            switch(level) {
            case 0:
                this.slf4jLogger.trace(marker, m);
                break;
            case 10:
                this.slf4jLogger.debug(marker, m);
                break;
            case 20:
                this.slf4jLogger.info(marker, m);
                break;
            case 30:
                this.slf4jLogger.warn(marker, m);
                break;
            case 40:
                this.slf4jLogger.error(marker, m);
            }
        }
    }            
} 

其實,類似的還有【jcl-over-slf4j】也是起到相同的作用。

例如:把Commons logging,log4j和java.util.logging橋接到SLF4J,底層使用logback的case。其他示例

到此這篇關于從log4j切換到logback后項目無法啟動的問題及解決方法的文章就介紹到這了,更多相關log4j切換到logback后項目無法啟動內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Netty學習之理解selector原理示例

    Netty學習之理解selector原理示例

    這篇文章主要為大家介紹了Netty學習之理解selector原理示例使用分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>
    2023-07-07
  • MyBatis?Mapper映射器的具體用法

    MyBatis?Mapper映射器的具體用法

    映射器是MyBatis中最重要的文件,映射器由Java接口和XML文件共同組成,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • 使用SpringBoot實現(xiàn)Redis多數(shù)據(jù)庫緩存

    使用SpringBoot實現(xiàn)Redis多數(shù)據(jù)庫緩存

    在我的系統(tǒng)中,為了優(yōu)化用戶行為數(shù)據(jù)的存儲與訪問效率,我引入了Redis緩存,并將數(shù)據(jù)分布在不同的Redis數(shù)據(jù)庫中,通過這種方式,可以減少單一數(shù)據(jù)庫的負載,提高系統(tǒng)的整體性能,所以本文給大家介紹了使用SpringBoot實現(xiàn)Redis多數(shù)據(jù)庫緩存,需要的朋友可以參考下
    2024-06-06
  • java項目導出為.exe執(zhí)行文件的方法步驟

    java項目導出為.exe執(zhí)行文件的方法步驟

    最近做了個項目,想要轉換成可執(zhí)行文件,那么java項目如何導出為.exe執(zhí)行文件,本文就介紹一下,主要使用jar2exe軟件,感興趣的可以了解一下
    2021-05-05
  • java中注解機制及其原理的詳解

    java中注解機制及其原理的詳解

    這篇文章主要介紹了java中注解機制及其原理的詳解的相關資料,希望通過本文能幫助到大家,讓大家理解掌握這部分內容,需要的朋友可以參考下
    2017-10-10
  • spring+springmvc整合mabytis時mapper注入失敗問題解決方法

    spring+springmvc整合mabytis時mapper注入失敗問題解決方法

    這篇文章主要介紹了spring+springmvc整合mabytis時mapper注入失敗問題解決方法 ,需要的朋友可以參考下
    2017-08-08
  • springboot結合maven配置不同環(huán)境的profile方式

    springboot結合maven配置不同環(huán)境的profile方式

    這篇文章主要介紹了springboot結合maven配置不同環(huán)境的profile方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 用Maven插件生成Mybatis代碼的實現(xiàn)方法

    用Maven插件生成Mybatis代碼的實現(xiàn)方法

    本文主要介紹 Maven插件生成Mybatis代碼,現(xiàn)在做開發(fā)的朋友有好多用Maven 來管理代碼,這里給大家舉個例子,有需要的同學可以看下
    2016-07-07
  • Mybatis實現(xiàn)增刪改查及分頁查詢的方法

    Mybatis實現(xiàn)增刪改查及分頁查詢的方法

    MyBatis是支持普通SQL查詢,存儲過程和高級映射的優(yōu)秀持 久層框架,通過本文給大家介紹Mybatis實現(xiàn)增刪改查及分頁查詢的方法,感興趣的朋友一起學習吧
    2016-01-01
  • JAVA中JSONObject對象和Map對象之間的相互轉換

    JAVA中JSONObject對象和Map對象之間的相互轉換

    這篇文章主要介紹了JAVA中JSONObject對象和Map對象之間的相互轉換,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01

最新評論