欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

面向切面编程的简单应用

程序员文章站 2022-06-05 13:48:51
...

​ 面向切片编程在很多项目中都有使用过,使用的场景也是较多。一个东西它之所以存在,肯定是解决了一些实际过程中的问题。要多去思考它存在的意义,就能理解的更深刻,才能举一反三。

​ 为什么会有面向切片编程。程序中最讨厌的事是复制代码,如果你发现同一段代码,或者相似的代码需要在多处出现,就会感觉到明显的“坏味道”。你不得不去维护散落在各个地方的同样逻辑,随着业务的不断复杂或者变更,这令人难以维护。这时有些人就提出来了,这不简单吗,我把这些相同的代码提取成一个方法,然后在需要的地方调用它,就可以减轻维护压力。对于相似的代码,抽象出一个方法兼容几个相似的逻辑,也可以提取出公共的方法。但是你还是需要在你使用的地方去显式的调用它,这对于公共方法的调用者类是耦合的。有没有一种无侵入式的方式,优雅的进行公共逻辑的调用呢,这就是面向切面编程要解决的问题。

​ 面向切面编程(AOP)专门用来解决各个模块中交叉关注点的问题,如事务管理、安全检查、缓存等。话不多说,今天我们讲下面向如何使用面向切片编程进行全局日志记录。

package com.xxx.xxx.component;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
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.util.Arrays;

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

    // 定义切入点的名称(如果多个增强处理,可以方便的使用名称)
    @Pointcut("execution(* com.xxx.xxx.controller.*.*(..))")
    public void webLog(){}

    @Around("webLog()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        logger.info("URL:{},请求开始", request.getRequestURL().toString());
        logger.info("Params : " + Arrays.toString(pjp.getArgs()));
        // result的值就是被拦截方法的返回值
        Object result = pjp.proceed();
        logger.info("URL:{},请求结束,result:{} ", request.getRequestURL().toString(), JSON.toJSONString(result));
        logger.info("Cost Time : {}ms" ,(System.currentTimeMillis() - startTime));
        return result;
    }
}

​ 增强处理类型:before,after,after-returning,after-throwing,around

​ 这里简单的举了一个全局日志的例子,实际中使用起来很简单方便。这里就会有同学又有疑问了:拦截器和AOP有什么区别呢?

​ 拦截器主要是拦截url的请求,进行请求的分发及路由,到真正的处理类。aop主要拦截spring中Bean的生命周期的访问,aop使用的是代理模式。