了解最新公司動(dòng)態(tài)及行業(yè)資訊
在Spring Boot中可以集成第三方的框架如MyBatis、MyBatis-Plus和RabbitMQ等統(tǒng)稱為擴(kuò)展。每一個(gè)擴(kuò)展會(huì)封裝成一個(gè)集成,即Spring Boot的starter(依賴組件)。starter是一種非常重要的機(jī)制,不需要煩瑣的配置,開發(fā)者只需要在項(xiàng)目的依賴中加入starter依賴,Spring Boot就能根據(jù)依賴信息自動(dòng)掃描到要加載的信息并啟用相應(yīng)的默認(rèn)配置。starter的出現(xiàn)讓開發(fā)者不再需要查找各種依賴庫及相應(yīng)的配置。所有stater模塊都遵循著約定成俗的默認(rèn)配置,并允許自定義配置,即遵循“約定大于配置”的原則。
常用的starter及其說明如表6.1所示。
表6.1 Spring Boot的starter列表
項(xiàng)目的日志主要包括系統(tǒng)日志、應(yīng)用程序日志和安全日志。運(yùn)維人員和項(xiàng)目開發(fā)人員可以通過日志了解服務(wù)器軟/硬件信息,檢查配置過程中的錯(cuò)誤及錯(cuò)誤發(fā)生的原因。通過分析日志還可以了解服務(wù)器的負(fù)荷、性能安全性,從而及時(shí)采取措施解決發(fā)生的問題。
因此,項(xiàng)目人員需要在系統(tǒng)開發(fā)和運(yùn)行時(shí)保存日志。關(guān)于什么時(shí)候保存日志有以下幾個(gè)要點(diǎn):
(1)系統(tǒng)初始化時(shí):記錄系統(tǒng)和服務(wù)的啟動(dòng)參數(shù)。在核心模塊初始化過程中會(huì)依賴一些關(guān)鍵配置項(xiàng),根據(jù)參數(shù)不同提供不同的服務(wù),記錄當(dāng)前的參數(shù)有助于發(fā)生錯(cuò)誤后排除問題。
(2)系統(tǒng)提示異常:代碼中的異常捕獲機(jī)制,此類異常的錯(cuò)誤級(jí)別非常高,是系統(tǒng)在告知開發(fā)人員需要關(guān)注的錯(cuò)誤信息。一般用WARN或者ERROR級(jí)別來記錄當(dāng)前的錯(cuò)誤日志。
(3)業(yè)務(wù)流程預(yù)期不符:記錄與正常流程不同的業(yè)務(wù)參數(shù),如外部參數(shù)不正確、未知的請(qǐng)求信息等。
(4)系統(tǒng)核心角色和組件的關(guān)鍵動(dòng)作的記錄:包括核心業(yè)務(wù)的日志記錄,INFO級(jí)別的日志記錄,保存微服務(wù)各服務(wù)節(jié)點(diǎn)交互的數(shù)據(jù)日志記錄、系統(tǒng)核心數(shù)據(jù)表的增、刪、改操作的日志記錄,以及核心組件運(yùn)行情況的日志記錄等。
(5)第三方服務(wù)遠(yuǎn)程調(diào)用:對(duì)第三方的服務(wù)調(diào)用需要保存調(diào)用前后的日志記錄,方便在發(fā)生錯(cuò)誤時(shí)排查問題。
在Java項(xiàng)目開發(fā)過程中,最簡單的方式是使用System.out.println打印日志,但這種方式有很多缺陷,如I/O瓶頸,而且不利于日志的統(tǒng)一管理。目前市面上有很多日志組件可以集成到Spring Boot中,它們能夠快速地實(shí)現(xiàn)不同級(jí)別的日志分類,以及在不同的時(shí)間進(jìn)行保存。常用的日志框架有以下幾個(gè):
1. JUL簡介
JUL即java.util.logging.Logger,是JDK自帶的日志系統(tǒng),從JDK 1.4開始出現(xiàn)。其優(yōu)點(diǎn)是系統(tǒng)自帶,缺點(diǎn)是相較于其他的日志框架來說功能不夠強(qiáng)大。
2. Apache Commons Logging簡介
Apache Commons Logging是Apache提供的一個(gè)通用日志API,可以讓程序不再依賴于具體的日志實(shí)現(xiàn)工具。Apache Commons Logging包中還對(duì)其他日志工具(包括Log4j、JUL)進(jìn)行了簡單的包裝,可以讓應(yīng)用程序在運(yùn)行時(shí)直接將Apache Commons Logging適配到對(duì)應(yīng)的日志實(shí)現(xiàn)工具中。
提示:Apache Common Logging通過動(dòng)態(tài)查找機(jī)制,在程序運(yùn)行時(shí)會(huì)自動(dòng)找出真正使用的日志庫。這一點(diǎn)與SLF4J不同,SLF4J是在編譯時(shí)靜態(tài)綁定真正的Log實(shí)現(xiàn)庫。
3. Log4j簡介
Log4j是Ceki Gülcü實(shí)現(xiàn)出來的,后來捐獻(xiàn)給Apache,又被稱為Log4j1.x,它是Apache的開放源代碼項(xiàng)目。在系統(tǒng)中使用Log4j,可以控制日志信息輸送的目的地是控制臺(tái)、文件及數(shù)據(jù)庫等,還可以自定義每一條日志的輸出格式,通過定義每一條日志信息的級(jí)別,還可以控制日志的生成過程。
Log4j主要是由Loggers(日志記錄器)、Appender(輸出端)和Layout(日志格式化器)組成。其中:
Logger用于控制日志的輸出級(jí)別與是否輸出日志;
Appender用于指定日志的輸出方式(輸出到控制臺(tái)、文件等);Layout用于控制日志信息的輸出格式。
Log4j有7種不同的log級(jí)別,按照等級(jí)從低到高依次為TRACE、DEBUG、INFO、WARN、ERROR、FATAL和OFF。如果配置為OFF級(jí)別,表示關(guān)閉log。
Log4j支持兩種格式的配置文件:properties和XML。
4. Logback簡介
Logback是由log4j的創(chuàng)立者Ceki Gülcü設(shè)計(jì),是Log4j的升級(jí)版。
Logback當(dāng)前分成3個(gè)模塊:logback-core、logback- classic和logbackaccess。logback-core是另外兩個(gè)模塊的基礎(chǔ)模塊。logback-classic是Log4j的一個(gè)改良版本,目前依然建議在生產(chǎn)環(huán)境中使用。
5. Log4j2簡介
Log4j2也是由log4j的創(chuàng)立者Ceki Gulcu設(shè)計(jì)的,它是Log4j 1.x和Logback的改進(jìn)版。在項(xiàng)目中使用Log4j2作為日志記錄的組件,在日志的吞吐量和性能方面比log4j 1.x提高了10倍,并可以解決一些死鎖的Bug,配置也更加簡單、靈活。
6. SLF4J
SLF4J是對(duì)所有日志框架制定的一種規(guī)范、標(biāo)準(zhǔn)和接口,并不是一個(gè)具體框架。因?yàn)榻涌诓⒉荒塥?dú)立使用,需要和具體的日志框架配合使用(如Log4j2、Logback)。使用接口的好處是,當(dāng)項(xiàng)目需要更換日志框架時(shí),只需要更換jar和配置,不需要更改相關(guān)的Java代碼,SLF4J相當(dāng)于Java設(shè)計(jì)模式的門面模式。目前項(xiàng)目的開發(fā)中多使用SLF4J+Logback或者SLF4J+Log4J2的組合方式來記錄日志。
日志的輸出是分級(jí)別的,不同的日志級(jí)別在不同的場(chǎng)合打印不同的日志。常見的日志級(jí)別有以下4個(gè):DEBUG:該級(jí)別的日志主要輸出與調(diào)試相關(guān)的內(nèi)容,主要在開發(fā)、測(cè)試階段輸出。DEUBG日志應(yīng)盡可能詳細(xì),開發(fā)者會(huì)把各類詳細(xì)信息記錄到DEBUG里,起到調(diào)試的作用,包括參數(shù)信息、調(diào)試細(xì)節(jié)信息、返回值信息等,方便在開發(fā)、測(cè)試階段出現(xiàn)問題或者異常時(shí)對(duì)問題進(jìn)行分析和修改。
INFO:該級(jí)別的日志主要記錄系統(tǒng)關(guān)鍵信息,用來保留系統(tǒng)正常工作期間的關(guān)鍵信息指標(biāo)。開發(fā)者可以將初始化系統(tǒng)配置、業(yè)務(wù)狀態(tài)變化信息或者用戶業(yè)務(wù)流程中的核心處理記錄到INFO日志中,方便運(yùn)維及錯(cuò)誤回溯時(shí)進(jìn)行場(chǎng)景復(fù)現(xiàn)。當(dāng)在項(xiàng)目完成后,一般會(huì)把項(xiàng)目日志級(jí)別從DEBUG調(diào)成INFO,對(duì)于不需要再調(diào)試的日志,將通過INFO級(jí)別的日志記錄這個(gè)應(yīng)用的運(yùn)行情況,如果出現(xiàn)問題,根據(jù)記錄的INFO級(jí)別的日志來排查問題。
WARN:該級(jí)別的日志主要輸出警告性質(zhì)的內(nèi)容,這類日志可以預(yù)知問題的發(fā)生,如某個(gè)方法入?yún)榭栈蛘邊?shù)的值不滿足運(yùn)行方法的條件時(shí)。在輸出WARN級(jí)別的日志時(shí)應(yīng)輸出詳盡的提示信息,方便開發(fā)者和運(yùn)維人員對(duì)日志進(jìn)行分析。
ERROR:該級(jí)別主要指系統(tǒng)錯(cuò)誤信息,如錯(cuò)誤、異常等。例如,在catch中抓獲的網(wǎng)絡(luò)通信和數(shù)據(jù)庫連接等異常,若異常對(duì)系統(tǒng)的整個(gè)流程影響不大,可以輸出WARN級(jí)別的日志。在輸出ERROR級(jí)別的日志時(shí),要記錄方法入?yún)⒑头椒▓?zhí)行過程中產(chǎn)生的對(duì)象等數(shù)據(jù),在輸出帶有錯(cuò)誤和異常對(duì)象的數(shù)據(jù)時(shí),需要將該對(duì)象全部記錄,方便后續(xù)的Bug修復(fù)。
日志的等級(jí)由低到高分別是DEBUG<INFO<WARN<ERROR,日志記錄一般會(huì)記錄設(shè)置級(jí)別及其以下級(jí)別的日志。例如,設(shè)置日志的級(jí)別為INFO,則系統(tǒng)會(huì)記錄INFO和DEBUG級(jí)別的日志,超過INFO級(jí)別的日志不會(huì)記錄。
綜上所述,在項(xiàng)目中保存好日志有以下好處:
打印調(diào)試:用日志記錄變量或者邏輯的變化,方便進(jìn)行斷點(diǎn)調(diào)試。
問題定位:程序出現(xiàn)異常后可根據(jù)日志快速定位問題所在,方便后期解決問題。
用戶行為日志:記錄用戶的關(guān)鍵操作行為。重要系統(tǒng)邏輯日志記錄:方便以后問題的排查和記錄。
本小節(jié)將新建一個(gè)項(xiàng)目,實(shí)現(xiàn)使用日志組件和Spring的AOP記錄所有Controller入?yún)⒌墓δ埽敬问褂肧LF4J+log4j2的方式實(shí)現(xiàn)日志的記錄。
(1)新建一個(gè)項(xiàng)目spring-extend-demo,在pom.xml中添加Web、Log4j2、SLF4J和AOP的依賴坐標(biāo),具體如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-extend-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-extend-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter
logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter
logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
添加完依賴后,可以查看項(xiàng)目的依賴庫,部分依賴庫如圖6.1和圖6.2所示,當(dāng)前項(xiàng)目中已經(jīng)引入了SLG4J和Log4j2依賴。
圖6.2 SLF4J的依賴
(2)在resources目錄下新建一個(gè)log4j2.xml配置文件,配置日志的記錄如下:
<?xml version="1.0" encoding="UTF-8"?>
<!--
Configuration后面的配置,用于設(shè)置log4j2內(nèi)部的信息輸出,可以不設(shè)置。當(dāng)設(shè)置成
trace時(shí)可以看到log4j2內(nèi)部的各種詳細(xì)輸出。
-->
<!--
monitorInterval:Log4j能夠自動(dòng)檢測(cè)、修改配置文件,并設(shè)置間隔秒數(shù)。
-->
<configuration status="error" monitorInterval="30">
<!--先定義所有的Appender-->
<appenders>
<!--這個(gè)輸出控制臺(tái)的配置-->
<Console name="Console" target="SYSTEM_OUT">
<!--控制臺(tái)只輸出level及以上級(jí)別的信息(onMatch),其他的直接拒絕
(onMismatch)-->
<ThresholdFilter level="trace" onMatch="ACCEPT"
onMismatch="DENY"/>
<!--輸出日志的格式-->
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level
%class{36} %L%M - %msg%xEx%n"/>
</Console>
<!--文件會(huì)打印出所有信息,該日志在每次運(yùn)行程序時(shí)會(huì)自動(dòng)清空,由append屬性
決定,適合臨時(shí)測(cè)試用-->
<File name="log" fileName="log/test.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level
%class{36} %L%M - %msg%xEx%n"/>
</File>
<!-- 打印出所有的信息,如果大小超過size,則超出部分的日志會(huì)自動(dòng)存入按年
份-月份建立的文件夾下面并進(jìn)行壓縮作為存檔-->
<RollingFile name="RollingFile" fileName="D:/log/log.log"
filePattern="D:/log/log-${date:yyyy-MM}/log-
%d{MM-dd-yyyy}-%i.log">
<PatternLayout pattern="%d{yyyy-MM-dd at HH:mm:ss z}
%-5level%class{36} %L %M - %msg%xEx%n"/> <!-- 如果一個(gè)文件超過50 MB,就會(huì)生成下一個(gè)日志文件 -->
<SizeBasedTriggeringPolicy size="50MB"/>
<!-- 如不設(shè)置DefaultRolloverStrategy屬性,則默認(rèn)同一文件夾下最多
有7個(gè)文件,這里設(shè)置為20 -->
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</appenders>
<!--定義logger,只有定義了logger并引入上面配置的Appender,當(dāng)前的Appender
才會(huì)生效-->
<loggers>
<!--建立一個(gè)默認(rèn)用戶的logger,將其作為日志記錄的根配置-->
<root level="info">
<appender-ref ref="RollingFile"/>
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
(3)配置保存成功后,每天會(huì)根據(jù)前面的配置生成一個(gè)日志文件,一個(gè)日志文件的最大容量為50MB,超過50MB就再新建一個(gè)日志文件。新建一個(gè)Web入口類HelloController,代碼如下:
package com.example.springextenddemo.controller;
import com.example.springextenddemo.vo.UserVO;
import org.springframework.web.bind.annotation.*;
@RestController
public class HelloController {
@GetMapping("/hi")
public String hi(@RequestParam("name")String name){
return "hi "+name;
}
@PostMapping("/hi-post")
public String hiPost(@RequestBody UserVO userVO){ return "hi-post "+userVO;
}
}
Hellocontroller中的參數(shù)接收實(shí)體類UserVO如下:
package com.example.springextenddemo.vo;
import java.util.StringJoiner;
public class UserVO {
private String name;
private String address;
private int age;
//省略GET和SET方法
}
(4)新建一個(gè)AOP類記錄日志:
package com.example.springextenddemo.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.Extended
ServletRequestDataBinder;
import javax.servlet.http.HttpServletResponseWrapper;import java.util.HashMap;
import java.util.Map;
/**
* 第一個(gè)執(zhí)行
*/
@Order(1)
/**
* aspect 切面
*/
@Aspect
@Component
public class RequestParamLogAop {
private static final Logger log =
LoggerFactory.getLogger(RequestParamLogAop.class);
/**
* Controller層切點(diǎn)
*/
@Pointcut("execution (*
com.example.springextenddemo.controller..*.*(..))")
public void controllerAspect() {
}
/**
* 環(huán)繞通知
*
* @param joinPoint
* @throws Throwable
*/
@Around(value = "controllerAspect()")
public Object around(ProceedingJoinPoint joinPoint) throws
Throwable {
Signature signature = joinPoint.getSignature();
methodBefore(joinPoint,signature);
Object result = joinPoint.proceed();
methodAfterReturn(result, signature);
return result;
} /**
* 方法執(zhí)行前執(zhí)行
*
* @param joinPoint
* @param signature
*/
private void methodBefore(JoinPoint joinPoint, Signature
signature) {
//在兩個(gè)數(shù)組中,參數(shù)值和參數(shù)名的個(gè)數(shù)和位置是一一對(duì)應(yīng)的
Object[] objs = joinPoint.getArgs();
// 參數(shù)名
String[] argNames = ((MethodSignature)
signature).getParameterNames();
Map<String, Object> paramMap = new HashMap<String, Object>();
for (int i = 0; i < objs.length; i++) {
if (!(objs[i] instanceof ExtendedServletRequestDataBinder)
&& !(objs[i] instanceof
HttpServletResponseWrapper)) {
paramMap.put(argNames[i], objs[i]);
}
}
log.info("請(qǐng)求前-方法:{} 的請(qǐng)求參數(shù):{}", signature, paramMap);
}
/**
* 方法執(zhí)行后的返回值
*/
private void methodAfterReturn(Object result, Signature signature)
{
log.info("請(qǐng)求后-方法:{} 的返回參數(shù)是:{}", signature, result);
}
}
(5)新建一個(gè)Spring Boot啟動(dòng)類:
package com.example.springextenddemo;
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringExtendDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringExtendDemoApplication.class,
args);
}
}
(6)修改配置文件application.properties,將日志配置文件添加到Spring Boot中:
logging.config=classpath:log4j2.xml
(7)啟動(dòng)項(xiàng)目,可以在控制臺(tái)看到新的日志格式,如圖6.3所示。
在瀏覽器中訪問localhost:8080/hi?name= cc,結(jié)果如圖6.4所示。
再訪問localhost:8080/hi-post,結(jié)果如圖6.5所示。
查看日志的配置目錄,打開D:\log可以看到日志文件,如圖6.6所示,日志內(nèi)容如圖6.7所示,控制臺(tái)的輸出日志和保存日志文件內(nèi)容一樣,如圖6.8所示。
圖6.7 log日志內(nèi)容
圖6.8 控制臺(tái)打印的日志
過AOP簡單地完成了對(duì)所有Controller入口的請(qǐng)求參數(shù)的記錄,這個(gè)功能一般在項(xiàng)目中必須要有,請(qǐng)求入?yún)⒈仨氝M(jìn)行記錄,以方便問題的回溯。
上面定義的日志配置使用的是Log4j2自帶的日志Appender,在Log4j2中常用的Appender如表6.2所示,它們有不同的功能。
表6.2 Log4j2常用的Appender
在項(xiàng)目開發(fā)中可以直接使用上面的Appender,也可以自定義一個(gè)Appender。下面完成一個(gè)自定義的Appender,在打印的日志前面加上自定義的內(nèi)容,完成自定義日志的開發(fā)。
(1)新建一個(gè)Appeder的實(shí)現(xiàn)類,此類需要繼承自類AbstractAppender,代碼如下:
package com.example.springextenddemo.appender;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
import java.io.Serializable;
/**
* 自定義實(shí)現(xiàn)Appender
* @Plugin注解:在log4j2.xml配置文件中使用,指定的Appender Tag
*/
@Plugin(name = "myAppender", category = "Core", elementType =
"appender",
printObject = true)
public class MyLog4j2Appender extends AbstractAppender {
String printString;
/**
*構(gòu)造函數(shù) 可自定義參數(shù) 這里直接傳入一個(gè)常量并輸出
*
*/
protected MyLog4j2Appender(String name, Filter filter, Layout<?
extends Serializable> layout,
String printString) {
super(name, filter, layout);
this.printString = printString;
}
/**
* 重寫append()方法:在該方法里需要實(shí)現(xiàn)具體的邏輯、日志輸出格式的設(shè)置
* 自定義實(shí)現(xiàn)輸出
* 獲取輸出值:event.getMessage().toString()
* @param event
*/
@Override
public void append(LogEvent event) {
if (event != null && event.getMessage() != null) {
//格式化輸出
System.out.print("自定義appender"+printString + ":" +
getLayout().toSerializable(event));
}
} /**
* 接收log4j2-spring.xml中的配置項(xiàng)
* @PluginAttribute 是XML節(jié)點(diǎn)的attribute值,如<book name="sanguo">
</book>,這里的name是attribute
* @PluginElement 表示XML子節(jié)點(diǎn)的元素,例如:
* <book name="sanguo">
* <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l -
%m%n"/>
* </book>
* 其中,PatternLayout是{@link Layout}的實(shí)現(xiàn)類
*/
@PluginFactory
public static MyLog4j2Appender createAppender(
@PluginAttribute("name") String name,
@PluginElement("Filter") final Filter filter,
@PluginElement("Layout") Layout<? extends Serializable>
layout,
@PluginAttribute("printString") String printString) {
if (name == null) {
LOGGER.error("no name defined in conf.");
return null;
}
//默認(rèn)使用 PatternLayout
if (layout == null) {
layout = PatternLayout.createDefaultLayout();
}
//使用自定義的Appender
return new MyLog4j2Appender(name, filter, layout, printString);
}
@Override
public void start() {
System.out.println("log4j2-start方法被調(diào)用");
super.start();
}
@Override
public void stop() {
System.out.println("log4j2-stop方法被調(diào)用"); super.stop();
}
}
重寫的start()方法為初始時(shí)調(diào)用,在數(shù)據(jù)庫入庫、連接緩存或者M(jìn)Q時(shí),可以在這個(gè)方法里進(jìn)行初始化操作。stop()方法是在項(xiàng)目停止時(shí)調(diào)用,用來釋放資源。
(2)將之前項(xiàng)目中的日志配置文件log4j.xml修改為log4j.xm.bak,再新建一個(gè)自定義的Appender的log4j2的配置文件。注意,自定義的Appender的名稱要和Java代碼中的Appender的名字相同,其配置文件的內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="INFO" monitorInterval="30"
packages="com.example.
springextenddemo">
<!--定義Appenders-->
<appenders>
<myAppender name="myAppender" printString=":start log:">
<!--輸出日志的格式-->
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l -
%m%n"/>
</myAppender>
</appenders>
<!--自定義logger,只有定義了logger并引入appender,appender才會(huì)生效-->
<loggers>
<!--spring和mybatis的日志級(jí)別為info-->
<logger name="org.springframework" level="INFO"></logger>
<logger name="org.mybatis" level="INFO"></logger>
<!-- 如果在自定義包中設(shè)置為INFO,則可以看見輸出的日志不包含debug輸出了
-->
<logger name="com.example.springextenddemo" level="INFO"/>
<root level="all">
<appender-ref ref="myAppender"/>
</root> </loggers>
</configuration>
(3)重新啟動(dòng)項(xiàng)目,在瀏覽器中訪問http://localhost:8080/hi?name=cc,可以看到控制臺(tái)顯示的自定義日志如圖6.9所示。日志前已經(jīng)加上了前綴自定義appender:start log,達(dá)到了本次自定義Appender的目的。
圖6.9 自定義Appender輸出
24小時(shí)免費(fèi)咨詢
請(qǐng)輸入您的聯(lián)系電話,座機(jī)請(qǐng)加區(qū)號(hào)