问答平台(3),统一记录日志

问题背景

记录日志-图示

  • 记录日志,不是业务需求,是系统需求,需要分离。

AOP

AOP的术语-图示

1
2
- Aspect Oriented Programing, 即面向切面编程。
- AOP 是一种编程思想,是对 OOP 的补充,可以提高编程的效率。

AOP的实现

AspectJ

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

Spring AOP

1
2
3
- Spring AOP 使用纯Java实现,它不需要专门的编译过程,也不需要特殊的类装载器。
- Spring AOP 在运行时通过(代理)的方式织入代码,只支持方法类型的连接点。
- Spring 支持对 AspectJ 的集成。
1
2
3
4
5
6
7
Spring AOP 追求的是高性价比,不是一个全面的解决方案。
1JDK 动态代理
Java 提供的动态代理技术,可以在运行时创建接口的代理实例。
Spring AOP 默认采用此种方式,在接口的代理实例中织入代码。
2)CGLib 动态代理
采用底层的字节码技术,在运行时创建子类代理实例。
当目标对象不存在接口时,Spring AOP 会采用此种方式,在子类实例中织入代码。

aspect 包

  • 示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    // AlphaAspect.java
    @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 around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("around before");
    Object obj = joinPoint.proceed();
    System.out.println("around after");
    return obj;
    }
    }
  • 正式的业务逻辑
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // ServiceLogAspect.java
    @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();
    if (attributes == null) {
    return;
    }
    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));
    }
    }

问答平台(3),统一记录日志
https://lcf163.github.io/2020/05/19/问答平台(3),统一记录日志/
作者
乘风的小站
发布于
2020年5月19日
许可协议