1. 程式人生 > >SpringMVC使用Maven配置SLF4J和LOG4J2

SpringMVC使用Maven配置SLF4J和LOG4J2

本篇的重點在於LOG4J2,它與LOG4J 第一版區別很大。我將教程放在後面,將一些知識放在前面,所以想看教程的直接拉到後面即可。

理論知識

關於兩版的區別

兩版的不同,直接的表現是在Maven倉庫中log4j 表示第一版,org.apache.logging.log4j 表示第二版。另外應當注意:

  1. Log4J2.4及更高版本需要Java 7,版本2.0-alpha1至2.3需要Java 6
  2. XML配置已被簡化,與Log4j 1.x不相容
  3. 版本2.4開始支援通過屬性檔案進行配置,但與Log4j 1.x不相容
  4. 支援通過JSON或YAML進行配置,但這些格式需要額外的執行時依賴關係
  5. 雖然Log4j 2與Log4j不直接相容1.x,但提供了橋接依賴可以減少程式碼的修改

尋找配置檔案的原理

log4j2允許使用log4jConfiguration 上下文引數在web.xml中指定配置檔案。Log4j2將通過以下方式搜尋配置檔案

  1. 如果提供了一個位置,它將搜尋servlet上下文資源,即配置log4jConfiguration
  2. 如果沒有定義位置,Log4j2將搜尋以WEB-INF目錄中以log4j2 開頭的檔案。如果找到多個檔案,並且如果存在以log4j2 開頭的檔案。如果找到多個檔案,並且如果存在以log4j2-name 開頭的檔案,其中name是Web應用程式的名稱,則將使用它。否則將使用第一個檔案。
  3. 使用類路徑和檔案URL的正常搜尋序列用於定位配置檔案

Tomcat版本的差異

出於效能原因,容器經常忽略已知不包含TLDServletContainerInitializer的某些JAR,並且不掃描它們的Web片段和初始化器。重要的是,Tomcat 7 <7.0.43將忽略名為log4j * .jar的所有JAR檔案,從而阻止此功能的工作。這在Tomcat 7.0.43,Tomcat 8和更高版本中已經修復。在Tomcat 7 <7.0.43中,您將需要更改catalina.properties,並從jarsToSkip 屬性中刪除”log4j * .jar”。如果他們跳過掃描Log4j JAR檔案,您可能需要在其他容器上執行類似的操作。

關於log4j-web的重要性

Log4j2-web.jar檔案是配置為在應用程式中的任何其他Web片段之前的Web片段。它包含容器自動發現和初始化的ServletContainerInitializerLog4jServletContainerInitializer)。這將Log4jServletContextListener和 Log4jServletFilter新增到ServletContext中。這些類正確初始化並初始化Log4j配置。

對於某些使用者,自動啟動Log4j是有問題的或不合需要的。您可以使用isLog4jAutoInitializationDisabled上下文引數輕鬆禁用此功能。只需將其新增到您的部署描述符,值為“true”即可禁用自動初始化。您必須在web.xml中定義context引數。如果以程式設計方式設定,Log4j將檢測到設定為時已晚。

    <context-param>
        <param-name> isLog4jAutoInitializationDisabled </ param-name>
        <param-value> true </ param-value>
    </context-param>

禁用自動初始化後,您必須像Servlet 2.5 Web應用程式一樣初始化Log4j 。您必須這樣做,以便在執行任何其他應用程式程式碼(如Spring Framework啟動程式碼)之前進行此初始化。

您可以自定義偵聽器的行為並使用log4jContextName, log4jConfiguration和/或isLog4jContextSelectorNamed上下文引數進行過濾。在下面的“ 上下文引數”部分中閱讀更多資訊。您不得在部署描述符(web.xml)中或在Servlet 3.0或更高版本應用程式中的其他初始化程式或偵聽器中 手動配置Log4jServletContextListener或Log4jServletFilter,除非禁用了使用 isLog4jAutoInitializationDisabled 自動初始化。這樣做會導致啟動錯誤和未指定的錯誤行為。

教程開始

編寫pom.xml

<properties>        
    <slf4j.version>1.7.25</slf4j.version>
    <log4j.version>2.8.2</log4j.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>${slf4j.version}</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>${log4j.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>${log4j.version}</version>
    </dependency>
    <!--用於與sfl4j保持橋接-->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>${log4j.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-web</artifactId>
        <version>${log4j.version}</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

注意log4j-web是很重要的,在Java EE Web應用程式中使用Log4j或任何其他日誌記錄框架時,必須特別小心。由於Web應用程式中的類載入器的性質,Log4j資源無法通過正常方式進行清理。為了避免這些問題,務必包含log4j-web

設定web.xml

Servlet 3.0或更高版本是無需配置web.xml的,它預設指定配置檔案應命名為log4j2.xml,並要求放置在classpath中,所以在maven專案裡,只要在resources目錄下新建log4j2.xml檔案即可,否則要設定

<context-param>
    <param-name>log4jConfiguration</param-name>
    <param-value>classpath:config/log4j2.xml</param-value>
</context-param>

如果專案還是基於Servlet 2.x的,官方宣告上Log4j2是不支援Servlet 3.0以下版本的,網上有教程稱設定監聽器和過濾器,這裡給出其參考配置

<listener>
    <listener-class>org.apache.logging.log4j.web.Log4jServletFilter
</listener>
<filter>
    <filter-name>log4jServletFilter</filter-name>
    <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>log4jServletFilter</filter-name>
    <url-pattern>/*<url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

設定配置檔案

Log4j2支援properties,xml,json以及yaml。這裡給出xml的參考配置

注意命名為log4j2.xml

<?xml version="1.0" encoding="utf-8" ?>
<Configuration status="off" monitorInterval="1800">
    <properties>
        <property name="LOG_HOME">F:\logs</property>
        <property name="ERROR_LOG_FILE_NAME">error</property>
    </properties>

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p (%F:%L) - %m%n" />
        </Console>
        <RollingRandomAccessFile name="ErrorLog"
                                 fileName="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log"
                                 filePattern="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log.%d{yyyy-MM-dd}.gz">
            <PatternLayout pattern="%d %-5p (%F:%L) - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100MB"/>
            </Policies>
            <DefaultRolloverStrategy max="20"/>
        </RollingRandomAccessFile>
    </Appenders>

    <Loggers>
        <logger name="org.springframework.core" level="info"/>
        <logger name="org.springframework.beans" level="info"/>
        <logger name="org.springframework.context" level="info"/>
        <logger name="org.springframework.web" level="info"/>
        <logger name="org.newcih" level="error" includeLocation="true" additivity="false">
            <appender-ref ref="ErrorLog"/>
            <appender-ref ref="Console"/>
        </logger>

        <root level="info" includeLocation="true">
            <appender-ref ref="Console"/>
        </root>
    </Loggers>
</Configuration>

測試

一般的log4j程式碼正常使用即可,由於使用到slf4j,這裡推薦了lombok,一款簡化程式碼的外掛,其實是一個jar包,eclipse和idea有各自的外掛可以使用。給出程式碼如下

import lombok.extern.slf4j.Slf4j;
import org.newcih.teacher.service.TeacherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Slf4j
@Controller
@RequestMapping("/teacher")
public class TeacherManager {
    @Autowired
    private TeacherService teacherService;

    @ResponseBody
    @RequestMapping(value = "/test")
    public String test(){
        log.info("hello world");
        log.error("Hello World");
        return "Success";
    }
}

在上述程式碼中,控制檯和日誌檔案只會列印Hello World,這裡因為在配置檔案log4j2.xml中配置到這個包路徑下的日誌level是error,也就是隻記錄error級別的日誌