【Java Web】统一记录日志

【Java Web】统一记录日志_第1张图片
【Java Web】统一记录日志_第2张图片

  • joinpoint:连接点,定义了准备织入目标对象的位置;
  • pointcut:切点,定义当前的横切逻辑准备织入到哪些连接点上;
  • advice: 定义横切逻辑,在连节点上准备织入什么逻辑;
  • Aspect:用来封装pointcut和advice的组件。

一、什么是AOP

如果不理解面向切面编程,可以重点读被标记的文字。

在传统的面向对象编程中,我们将功能模块封装在类中,然后通过创建对象调用类中的方法来实现功能。然而,有些功能并不属于某个具体的类,它们涉及到多个类的共同关注点,比如日志记录、事务管理、权限控制等。如果将这些横切关注点直接嵌入到各个类的业务逻辑中,会导致代码重复、难以维护和扩展。

AOP通过将这些横切关注点从业务逻辑中抽离出来,形成一个独立的模块,称为切面(Aspect)。切面包含了需要横切的逻辑,比如日志记录、事务管理等。在AOP编程中,我们定义切点(Pointcut)表示在哪些地方应用切面,然后将切面与切点进行关联。当程序执行到切点时,切面中的逻辑就会被自动执行,从而实现了横切关注点的功能。

二、如何实现AOP

Spring AOPAspectJ都是常用的AOP框架,它们提供了丰富的AOP功能,但在实现方式和使用上有所区别。

2.1 AspectJ

  • AspectJ是语言级的实现,扩展了JAVA语法,定义了AOP语法
  • AspectJ在编译期织入代码,有一个专门的编译器,用来生成遵守Java字节码规范的class文件。

优势:功能强大,适合需要更细粒度控制和更复杂切面编程的场景;
缺点:需要专门去一门语言;

2.2 Spring AOP

  • Spring AOP使用纯Java实现,不需要专门的编译过程,也不需要特殊的类装载器;
  • Spring AOP在运行时通过代理的方式织入代码,只支持方法类型的连接点;
  • 支持对AspectJ的集成。

优势:更轻量级、对代码侵入性小。

补充:什么是代理?

  • JDK动态代理
    • java提供的动态代理技术,可以在运行时创建接口的代理实例;
    • Spring AOP默认采用此种方式,在接口的代理实例中织入代码。
  • CGLib动态代理
    • 采用底层的字节码技术,在运行时创建子类代理的实例;
    • 当目标对象不存在接口时,Spring AOP会采用此种方式,在子类实例中织入代码。

2.3 演示

2.3.1 演示1

package com.nowcoder.community.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AlphaAspect {

    @Pointcut("execution(* com.nowcoder.community.service.*.*(..))")
    public void pointcut(){

    }
    @Before("pointcut()")
    public void before(){
        System.out.println("before");
    }

    @After("pointcut()")
    public void after(){
        System.out.println("after");
    }

    @AfterReturning("pointcut()")
    public void afterReturning(){
        System.out.println("afterReturning");
    }

    @AfterThrowing("pointcut()")
    public void AfterThrowing(){
        System.out.println("AfterThrowing");
    }

    @Around("pointcut()")
    public Object AfterThrowing(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("around before");
        Object object = joinPoint.proceed();
        System.out.println("around after");
        return object;
    }

}

around before
before
2023-09-05 21:59:25,581 DEBUG [http-nio-8080-exec-1] c.n.c.d.U.selectById [BaseJdbcLogger.java:143] ==>  Preparing: select id, username, password, salt, email, type, status, activation_code, header_url, create_time from user where id = ? 
2023-09-05 21:59:25,581 DEBUG [http-nio-8080-exec-1] c.n.c.d.U.selectById [BaseJdbcLogger.java:143] ==> Parameters: 149(Integer)
2023-09-05 21:59:25,582 DEBUG [http-nio-8080-exec-1] c.n.c.d.U.selectById [BaseJdbcLogger.java:143] <==      Total: 1
around after
after
afterReturning

2.3.2 演示2

package com.nowcoder.community.aspect;


import org.apache.coyote.Request;
import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
@Aspect
public class ServiceLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);

    @Pointcut("execution(* com.nowcoder.community.service.*.*(..))")
    public void pointcut(){

    }

    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
        // 用户[1,2,3,4],在[xxx]时间,访问了[com.nowcoder.community.service.xxx()]
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String ip = request.getRemoteHost();
        String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        logger.info(String.format("用户[%s]在[%s]访问了[%s].", ip, now, target));
    }
}

2023-09-05 22:19:20,066 INFO [http-nio-8080-exec-8] c.n.c.a.ServiceLogAspect [ServiceLogAspect.java:38] 用户[0:0:0:0:0:0:0:1][2023-09-05 22:19:20]访问了[com.nowcoder.community.service.MessageService.findLetters].
2023-09-05 22:19:20,067 DEBUG [http-nio-8080-exec-8] c.n.c.d.M.selectLetters [BaseJdbcLogger.java:143] ==>  Preparing: select id, from_id, to_id, conversation_id, content, status, create_time from message where conversation_id = ? and status != 2 and from_id != 1 order by id desc limit ?, ? 
2023-09-05 22:19:20,067 DEBUG [http-nio-8080-exec-8] c.n.c.d.M.selectLetters [BaseJdbcLogger.java:143] ==> Parameters: 146_181(String), 0(Integer), 5(Integer)
2023-09-05 22:19:20,068 DEBUG [http-nio-8080-exec-8] c.n.c.d.M.selectLetters [BaseJdbcLogger.java:143] <==      Total: 1
2023-09-05 22:19:20,068 INFO [http-nio-8080-exec-8] c.n.c.a.ServiceLogAspect [ServiceLogAspect.java:38] 用户[0:0:0:0:0:0:0:1][2023-09-05 22:19:20]访问了[com.nowcoder.community.service.UserService.findUserById].
2023-09-05 22:19:20,068 DEBUG [http-nio-8080-exec-8] c.n.c.d.U.selectById [BaseJdbcLogger.java:143] ==>  Preparing: select id, username, password, salt, email, type, status, activation_code, header_url, create_time from user where id = ? 
2023-09-05 22:19:20,069 DEBUG [http-nio-8080-exec-8] c.n.c.d.U.selectById [BaseJdbcLogger.java:143] ==> Parameters: 181(Integer)
2023-09-05 22:19:20,070 DEBUG [http-nio-8080-exec-8] c.n.c.d.U.selectById [BaseJdbcLogger.java:143] <==      Total: 1
2023-09-05 22:19:20,070 INFO [http-nio-8080-exec-8] c.n.c.a.ServiceLogAspect [ServiceLogAspect.java:38] 用户[0:0:0:0:0:0:0:1][2023-09-05 22:19:20]访问了[com.nowcoder.community.service.UserService.findUserById].
2023-09-05 22:19:20,071 DEBUG [http-nio-8080-exec-8] c.n.c.d.U.selectById [BaseJdbcLogger.java:143] ==>  Preparing: select id, username, password, salt, email, type, status, activation_code, header_url, create_time from user where id = ? 
2023-09-05 22:19:20,071 DEBUG [http-nio-8080-exec-8] c.n.c.d.U.selectById [BaseJdbcLogger.java:143] ==> Parameters: 146(Integer)
2023-09-05 22:19:20,072 DEBUG [http-nio-8080-exec-8] c.n.c.d.U.selectById [BaseJdbcLogger.java:143] <==      Total: 1

你可能感兴趣的:(java,java,前端,开发语言)