一、AOP日誌處理
AOP(Aspect-Oriented Programming,面向切面編程)是一種編程思想和技術,可以將一些與業務無關,卻在多個模塊或層中經常出現的重複操作,如日誌、事務、異常處理等,抽象為一些可重用的模塊,即切面(Aspect),並將其與業務模塊進行關聯。當業務模塊執行時,切面在特定的時機被織入到業務模塊中,從而達到了橫向抽取重複代碼的目的。
在使用AOP時,日誌處理是其中最常見的場景之一。我們可以使用AOP實現統一的日誌輸出、日誌記錄、日誌分析等功能,並且不對業務代碼進行侵入。
二、AOP日誌怎麼實現
AOP日誌的實現主要包括以下幾個步驟:
1.定義切面類
public class LogAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void pointCut(){}
@Before("pointCut()")
public void before(JoinPoint joinPoint){
System.out.printf("LogBefore... srcClass:%s,method:%s\n",joinPoint.getTarget().getClass(),joinPoint.getSignature().getName());
}
@After("pointCut()")
public void after(JoinPoint joinPoint){
System.out.printf("LogAfter... srcClass:%s,method:%s\n",joinPoint.getTarget().getClass(),joinPoint.getSignature().getName());
}
}
2.將切面類聲明為切面
@Aspect
@Component
public class LogAspect {
...
}
3.啟用AOP
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
...
}
三、AOP日誌記錄
日誌記錄是AOP日誌功能的重要組成部分。我們可以通過以下方式將日誌記錄到本地文件或其他數據存儲設備中。
1.使用Log4j2實現日誌記錄
@Configuration
public class LogConfig {
@Bean
public org.springframework.boot.logging.LoggingSystem loggingSystem() throws Exception {
return new Log4j2LoggingSystem();
}
}
2.配置Log4J2日誌輸出
%d %p %c{1.} [%t] %m%n
四、AOP日誌管理
對於大型項目,日誌管理十分重要。我們需要合理的管理日誌文件,對日誌進行分析和監控,保障系統的正常運行。
1.使用ELK Stack對日誌進行集中管理
ELK Stack指的是Elasticsearch、Logstash、Kibana三者的組合。其中,Elasticsearch用於存儲日誌數據,Logstash用於收集、處理和轉化數據,Kibana用於展示、查詢和分析數據。
2.配置Logstash收集日誌
input {
file {
path => "/var/log/my-app.log"
type => "my-app"
}
}
filter {
grok {
match => [ "message", "%{TIMESTAMP_ISO8601:timestamp} \[%{WORD:thread}\] %{LOGLEVEL:loglevel} %{GREEDYDATA:msg}" ]
}
}
output {
elasticsearch {
hosts => [ "localhost:9200" ]
index => "my-app-%{+YYYY.MM.dd}"
}
}
五、AOP日誌輸出
日誌輸出是AOP日誌功能中最常見的操作之一。我們可以通過以下方式將日誌輸出,方便進行調試和排查問題。
1.使用Logback實現日誌輸出
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
2.通過郵箱將日誌輸出
private void sendEmail(String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo("recipient@example.com");
message.setSubject(subject);
message.setText(content);
sender.send(message);
}
六、AOP日誌多線程
多線程是現在的主流編程方式之一,而AOP日誌同樣支持多線程。我們可以通過以下方式處理多線程的日誌輸出。
1.使用ThreadLocal保存線程上下文
public class ContextHolder {
private static ThreadLocal contextHolder = new ThreadLocal();
public static Context getContext() {
if (contextHolder.get() == null) {
contextHolder.set(new Context());
}
return contextHolder.get();
}
public static void clear() {
contextHolder.set(null);
}
}
2.在切面中處理線程上下文
@Around("@annotation(log)")
public Object process(ProceedingJoinPoint joinPoint, Log log) throws Throwable {
Context context = ContextHolder.getContext();
context.setUsername(log.username());
try {
Object result = joinPoint.proceed();
return result;
} finally {
ContextHolder.clear();
}
}
七、AOP記錄日誌
記錄日誌是AOP日誌的核心功能之一,可以為我們提供詳細的系統運行記錄,方便日後排查問題。
1.AOP方式實現日誌記錄
@Aspect
@Component
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Pointcut("execution(* com.example.service.*.*(..))")
public void pointCut(){}
@Before("pointCut()")
public void before(JoinPoint joinPoint){
logger.info("LogBefore... srcClass:{},method:{}",joinPoint.getTarget().getClass(),joinPoint.getSignature().getName());
}
@After("pointCut()")
public void after(JoinPoint joinPoint){
logger.info("LogAfter... srcClass:{},method:{}",joinPoint.getTarget().getClass(),joinPoint.getSignature().getName());
}
}
2.使用註解方式記錄日誌
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value();
}
@Service
public class UserService {
@Log("Add user")
public void addUser(User user) {
...
}
}
八、AOP註解方式
AOP註解方式是AOP日誌的一種實現方式,可以更加方便地為業務代碼添加切面。我們可以使用Spring AOP註解實現AOP日誌的功能
1.在切面類中添加註解
@Aspect
@Component
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Pointcut("execution(* com.example.service.*.*(..))")
public void pointCut(){}
@Before("pointCut()")
public void before(JoinPoint joinPoint){
logger.info("LogBefore... srcClass:{},method:{}",joinPoint.getTarget().getClass(),joinPoint.getSignature().getName());
}
@After("pointCut()")
public void after(JoinPoint joinPoint){
logger.info("LogAfter... srcClass:{},method:{}",joinPoint.getTarget().getClass(),joinPoint.getSignature().getName());
}
}
2.在業務類中添加註解
@Service
public class UserService {
@LogAnnotation
public void addUser(User user) {
...
}
}
九、AOP實現日誌功能步驟
1.定義切面類
@Aspect
@Component
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Pointcut("execution(* com.example.service.*.*(..))")
public void pointCut(){}
@Before("pointCut()")
public void before(JoinPoint joinPoint){
logger.info("LogBefore... srcClass:{},method:{}",joinPoint.getTarget().getClass(),joinPoint.getSignature().getName());
}
@After("pointCut()")
public void after(JoinPoint joinPoint){
logger.info("LogAfter... srcClass:{},method:{}",joinPoint.getTarget().getClass(),joinPoint.getSignature().getName());
}
}
2.聲明切面類
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
@Bean
public LogAspect logAspect() {
return new LogAspect();
}
}
3.使用切面類的日誌方法
@Service
public class UserService {
public void addUser(User user) {
LogAspect.logBefore();
...
LogAspect.logAfter();
}
}
十、Spring AOP的註解
在Spring中,我們可以使用註解的方式實現AOP功能。以下是Spring AOP中與AOP日誌相關的註解示例。
1.@Aspect註解:標明該類為切面類
2.@Pointcut註解:定義切點,通常使用execution表達式進行定義
3.@Before註解:在切點之前執行
4.@After註解:在切點之後執行
5.@Around註解:包含了@Before和@After的功能,可以精確控制執行時間點
6.@AfterReturning註解:在方法返回結果後執行
7.@AfterThrowing註解:在方法拋出異常時執行
十一、總結
AOP日誌是一個在現代開發中十分重要的功能,使用AOP方式實現日誌功能可以為我們提供更加簡潔、易讀的代碼和高效、精確的記錄和輸出方式。我們可以使用多種方式去實現AOP日誌,包括註解方式、XML配置方式以及Java配置方式等等。無論使用哪種方式,我們都需要深入了解AOP日誌的核心思想和實現方式,才能夠更加靈活地運用到業務場景之中。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/180157.html
微信掃一掃
支付寶掃一掃