六、集成全局AOP切面,进行访问时间与日志打印

小编 2026-06-29 阅读:1321 评论:0
本次开发环境为:系统:Windows 10 10.0JDK:JRE: 1.8.0_152-release-1136-b43 amd64 JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o开发工具...
本次开发环境为:
系统:Windows 10 10.0
JDK:JRE: 1.8.0_152-release-1136-b43 amd64 JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
开发工具:IntelliJ IDEA 2018.1.8
springboot框架:2.2.0

1、在pom.xml中增加包引用

        <!-- Springboot的AOP包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2、新建一个controller包用于本次测试使用

@RestController
public class HelloWorldAOPController {
    private Logger log = LoggerFactory.getLogger(HelloWorldAOPController.class);
    /**
     * hello请求测试 实例:http://localhost:8081/hello?name=world
     * @param name 打招呼的姓名
     * @return 返回打招呼的整体语句
     */
    @RequestMapping("/hello")
    public String hello(String name){
        StringBuffer hellos = new StringBuffer();
        hellos.append("Hello ");
        hellos.append(name);
        return hellos.toString();
    }


}

3、新建一个WebTimeAspect类,用于记录日志切面,这里需要注意截止记录是在retrun后的切入点,因其是对全局controller进行的切面,因此使用@AfterReturning更合适的一些,如果我们所有均切入则使用@After更合适一些。

@Aspect
@Component
@Order(1)
public class WebTimeAspect {

    private Logger log = LoggerFactory.getLogger(WebTimeAspect.class);
    /**
     * 声明一个线程,用于记录请求与响应整个周期期间在服务端消耗的时间
     */
    private ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * 在请求响应之前,即请求到达当前服务端
     * 所有demo3下的controller均经过该切面
     * @param joinPoint
     */
    @Before("within(com.cnhuashao.rapiddevelopment.core..*.*)")
    public void doBefore(JoinPoint joinPoint){
        log.info("----------- WebTimeAspect doBefore -----------------------------------------");
        startTime.set(System.currentTimeMillis());
    }

    /**
     * 在请求响应之后,即请求已经经过controller处理返回后
     * @param rvt
     */
    @AfterReturning(value = "within(com.cnhuashao.rapiddevelopment.core..*.*)",returning = "rvt")
    public void doAfterReturning(Object rvt){
        log.info("-----------Start WebTimeAspect doAfterReturning ------");
        log.info("本次处理请求耗费时间 : {}",(System.currentTimeMillis() - startTime.get()));
        log.info("-----------End WebTimeAspect doAfterReturning -------------------------------");
    }

}

4、进行测试请求响应处理时间

访问地址:http://localhost:8081/hello?name=cnHuaShao

image.png

5、新建一个WebLogAspect类,用于请求日志与响应日志的记录

@Aspect
@Component
@Order(2)
public class WebLogAspect {

    private Logger log = LoggerFactory.getLogger(WebLogAspect.class);

    /**
     * 访问localhost时打印的IP地址
     */
    private static final String IP_LOCALHOST ="0:0:0:0:0:0:0:1";

    /**
     * com.cnhuashao.rapiddevelopment.core包及所有子包下任何类的任何方法
     */
    @Pointcut("execution(* com.cnhuashao.rapiddevelopment.core..*.*(..))")
    public void webLog(){

    }

    /**
     * 在请求响应之前,即请求到达当前服务端
     * 所有demo3下的controller均经过该切面
     * @param joinPoint
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint){
        log.info("  ---------- WebLogAspect doBefore --------------");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //在系统启动时拦截器经过该位置时会触发空指针异常,这里需要进行非空判断
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();

            log.info("  地址: {}", request.getRequestURL().toString());
            log.info("  请求方式: ", request.getMethod());
            String ip = request.getRemoteAddr();
            if (!IP_LOCALHOST.equals(ip)){
                log.info("  客户端IP: {}", ip);
            }
            log.info("  请求参数: {}" + Arrays.toString(joinPoint.getArgs()));
        }
    }

    /**
     * 在请求响应之后,即请求已经经过controller处理返回后
     * @param rvt
     */
    @AfterReturning(pointcut = "webLog()",returning = "rvt")
    public void doAfterReturning(Object rvt){
        log.info("  ------------Start WebLogAspect doAfterReturning ------");
        log.info("  响应结果 : {}",rvt.toString());
        log.info("  ------------End WebLogAspect doAfterReturning ------");
    }

    /**
     * 异常切入
     * @param error
     */
    @AfterThrowing(pointcut = "webLog()",throwing = "error")
    public void doAfterThrowing(Throwable error){
        log.error("  ------------Start WebLogAspect doAfterThrowing ------");
        log.error("请求处理过程中发生异常:{}",error.getMessage());
        log.error("  ------------Start WebLogAspect doAfterThrowing ------");
    }
}

6、进行测试日志切面

访问地址:http://localhost:8081/hello?name=cnHuaShao

image.png

至此已经实现访问时间与日志的切面,里面有一些优化还需要更改一下

1、整合切面使用包

在上述代码中每个方法头均有一个切入扫描的包路径,这样在我们日常使用配置时无法统一化管理,为了解决该问题,特将这种统一的全局值提出来。 更改WebTimeAspect类如下

@Aspect
@Component
@Order(1)
public class WebTimeAspect {

    private Logger log = LoggerFactory.getLogger(WebTimeAspect.class);
    /**
     * 声明一个线程,用于记录请求与响应整个周期期间在服务端消耗的时间
     */
    private ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * com.cnhuashao.rapiddevelopment.core包及所有子包下任何类的任何方法
     */
    @Pointcut("execution(* com.cnhuashao.rapiddevelopment.core..*.*(..))")
    public void webTime(){

    }

    /**
     * 在请求响应之前,即请求到达当前服务端
     * 所有demo3下的controller均经过该切面
     * 暂存:@Before("within(com.cnhuashao.rapiddevelopment.core..*.*)")
     * @param joinPoint
     */
    @Before("webTime()")
    public void doBefore(JoinPoint joinPoint){
        log.info("----------- WebTimeAspect doBefore -----------------------------------------");
        startTime.set(System.currentTimeMillis());
    }

    /**
     * 在请求响应之后,即请求已经经过controller处理返回后
     * 暂存:@AfterReturning(value = "within(com.cnhuashao.rapiddevelopment.core..*.*)",returning = "rvt")
     * @param rvt
     */
    @AfterReturning(pointcut = "webTime()",returning = "rvt")
    public void doAfterReturning(Object rvt){
        log.info("-----------Start WebTimeAspect doAfterReturning ------");
        log.info("本次处理请求耗费时间 : {}",(System.currentTimeMillis() - startTime.get()));
        log.info("-----------End WebTimeAspect doAfterReturning -------------------------------");
    }

}

2、优先级设计

在上述代码中每个aspect类的顶部都有一个注释@Order,这个注释是标记整个切面类的运行优先级的,我们的@Before与@AfterReturning根据order值执行的顺序是不一样的。 @Before order越越优先 @AfterReturning order越越优先

3、日常使用时我们应该将全局相关的切面包与配置包放到base包中,这样有利于全局化的相关信息管理。

代码示例

本文的相关例子可以查看仓库中的RapidDevelopment-demo3目录: Gitee 地址

本文声明:

88x31.png

知识共享许可协议 本作品由 cn華少 采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
标签列表