当前位置: 代码网 > it编程>编程语言>Java > SpringBoot中统计方法耗时的七种实现方式小结

SpringBoot中统计方法耗时的七种实现方式小结

2025年03月28日 Java 我要评论
一、手动使用stopwatch最直接的方法是使用spring提供的stopwatch类,这种方式简单直观,适合临时性的性能测试。import org.springframework.util.stop

一、手动使用stopwatch

最直接的方法是使用spring提供的stopwatch类,这种方式简单直观,适合临时性的性能测试。

import org.springframework.util.stopwatch;

@service
public class userservice {
    
    public user finduserbyid(long id) {
        stopwatch stopwatch = new stopwatch();
        stopwatch.start();
        
        // 业务逻辑
        user user = userrepository.findbyid(id).orelse(null);
        
        stopwatch.stop();
        system.out.println("finduserbyid方法耗时:" + stopwatch.gettotaltimemillis() + "ms");
        
        return user;
    }
}

优点:简单直观,无需额外配置

缺点:侵入业务代码,不够优雅,需要手动添加到每个需要监控的方法

二、使用aop实现全局方法耗时统计

aop(面向切面编程)是实现方法耗时统计的理想选择,它可以在不修改原有代码的情况下,统一处理耗时统计逻辑。

首先,添加aop依赖:

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-aop</artifactid>
</dependency>

然后,创建切面类:

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.springframework.stereotype.component;
import org.springframework.util.stopwatch;

@aspect
@component
public class methodtimeaspect {
    
    @pointcut("execution(* com.example.demo.service.*.*(..))")
    public void servicemethodpointcut() {}
    
    @around("servicemethodpointcut()")
    public object timearound(proceedingjoinpoint joinpoint) throws throwable {
        stopwatch stopwatch = new stopwatch();
        stopwatch.start();
        
        // 执行目标方法
        object result = joinpoint.proceed();
        
        stopwatch.stop();
        string methodname = joinpoint.getsignature().getname();
        system.out.println("方法[" + methodname + "]耗时:" + stopwatch.gettotaltimemillis() + "ms");
        
        return result;
    }
}

优点:代码无侵入,统一管理,配置灵活

缺点:对于特定方法的定制化需求不够灵活

三、自定义注解+aop实现更精细的控制

这种方法结合了自定义注解和aop,可以更精确地控制哪些方法需要进行耗时统计。

首先,创建自定义注解:

import java.lang.annotation.*;

@target(elementtype.method)
@retention(retentionpolicy.runtime)
@documented
public @interface timelog {
    string value() default "";
}

然后,创建切面类处理带有该注解的方法:

import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.annotation.around;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.reflect.methodsignature;
import org.springframework.stereotype.component;
import org.springframework.util.stopwatch;

@aspect
@component
public class timelogaspect {
    
    @around("@annotation(com.example.demo.annotation.timelog)")
    public object timelogaround(proceedingjoinpoint joinpoint) throws throwable {
        methodsignature signature = (methodsignature) joinpoint.getsignature();
        timelog timelog = signature.getmethod().getannotation(timelog.class);
        
        string methoddesc = timelog.value().isempty() ? 
                signature.getmethod().getname() : timelog.value();
        
        stopwatch stopwatch = new stopwatch();
        stopwatch.start();
        
        object result = joinpoint.proceed();
        
        stopwatch.stop();
        system.out.println("方法[" + methoddesc + "]耗时:" + stopwatch.gettotaltimemillis() + "ms");
        
        return result;
    }
}

使用示例:

@service
public class productservice {
    
    @timelog("查询商品详情")
    public product getproductdetail(long id) {
        // 业务逻辑
        return productrepository.findbyid(id).orelse(null);
    }
}

优点:更精细的控制,注解可携带更多信息,便于定制

缺点:需要手动在方法上添加注解

四、使用拦截器统计controller接口耗时

如果只关注controller层的接口耗时,可以使用spring的拦截器:

import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;

import org.springframework.stereotype.component;
import org.springframework.web.servlet.handlerinterceptor;
import org.springframework.web.servlet.modelandview;

@component
public class apitimeinterceptor implements handlerinterceptor {
    
    private threadlocal<long> starttime = new threadlocal<>();
    
    @override
    public boolean prehandle(httpservletrequest request, httpservletresponse response, object handler) {
        starttime.set(system.currenttimemillis());
        return true;
    }
    
    @override
    public void posthandle(httpservletrequest request, httpservletresponse response, object handler, modelandview modelandview) {
        long endtime = system.currenttimemillis();
        long executiontime = endtime - starttime.get();
        string uri = request.getrequesturi();
        system.out.println("接口[" + uri + "]耗时:" + executiontime + "ms");
        starttime.remove();
    }
}

注册拦截器:

import org.springframework.context.annotation.configuration;
import org.springframework.web.servlet.config.annotation.interceptorregistry;
import org.springframework.web.servlet.config.annotation.webmvcconfigurer;

@configuration
public class webconfig implements webmvcconfigurer {
    
    private final apitimeinterceptor apitimeinterceptor;
    
    public webconfig(apitimeinterceptor apitimeinterceptor) {
        this.apitimeinterceptor = apitimeinterceptor;
    }
    
    @override
    public void addinterceptors(interceptorregistry registry) {
        registry.addinterceptor(apitimeinterceptor).addpathpatterns("/api/");
    }
}

优点:专注于web接口性能,对接口进行统一监控

缺点:只能监控controller层方法,无法监控内部服务方法

五、使用actuator + micrometer实现细粒度监控

spring boot actuator提供了与micrometer的集成,可以实现更专业的性能指标收集:

添加依赖:

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-actuator</artifactid>
</dependency>
<dependency>
    <groupid>io.micrometer</groupid>
    <artifactid>micrometer-registry-prometheus</artifactid>
</dependency>

使用micrometer进行方法计时:

import io.micrometer.core.instrument.meterregistry;
import io.micrometer.core.instrument.timer;
import org.springframework.stereotype.service;

@service
public class orderservice {
    
    private final meterregistry meterregistry;
    
    public orderservice(meterregistry meterregistry) {
        this.meterregistry = meterregistry;
    }
    
    public order createorder(orderrequest request) {
        timer.sample sample = timer.start(meterregistry);
        
        // 业务逻辑
        order order = processorder(request);
        
        sample.stop(meterregistry.timer("order.creation.time"));
        
        return order;
    }
}

配置actuator暴露指标:

management:
  endpoints:
    web:
      exposure:
        include: metrics,prometheus
  metrics:
    export:
      prometheus:
        enabled: true

优点:专业的性能指标收集,可与prometheus、grafana等监控系统集成,适合生产环境

缺点:配置相对复杂,有一定学习成本

六、使用filter实现请求耗时统计

创建一个filter实现类,可以记录每次http请求的开始时间和结束时间,从而计算出请求的整体耗时。

import javax.servlet.filter;
import javax.servlet.filterchain;
import javax.servlet.filterconfig;
import javax.servlet.servletexception;
import javax.servlet.servletrequest;
import javax.servlet.servletresponse;
import java.io.ioexception;

@component
public class timingfilter implements filter {
    
    @override
    public void dofilter(servletrequest request, servletresponse response, filterchain chain) 
            throws ioexception, servletexception {
        long starttime = system.currenttimemillis();
        
        // 继续处理请求
        chain.dofilter(request, response);
        
        long endtime = system.currenttimemillis();
        long executiontime = endtime - starttime;
        string requesturi = ((httpservletrequest) request).getrequesturi();
        system.out.println("请求[" + requesturi + "]耗时:" + executiontime + "ms");
    }
    
    @override
    public void init(filterconfig filterconfig) throws servletexception {}
    
    @override
    public void destroy() {}
}

优点:可以全局监控所有web请求的耗时。

缺点:只提供整体请求的耗时,无法深入到具体业务逻辑的执行时间。

七、使用servletrequesthandledevent统计请求处理耗时

spring boot提供了servletrequesthandledevent事件,可以用来监控http请求的处理时间。这种方式适合于全局监控所有的请求。

首先,创建事件监听器:

import org.springframework.context.applicationlistener;
import org.springframework.web.context.request.servletrequesthandledevent;
import org.springframework.stereotype.component;

@component
public class requesttiminglistener implements applicationlistener<servletrequesthandledevent> {

    @override
    public void onapplicationevent(servletrequesthandledevent event) {
        system.out.println("请求[" + event.getrequesturl() + "]耗时:" + event.getprocessingtimemillis() + "ms");
    }
}

这种方法会自动监听处理结果,不需要在每个controller中进行显式的耗时统计。

优点:不需要修改现有代码,监控全局请求的耗时
缺点:不支持自定义请求的粒度控制

总结与对比

在springboot中,以上七种方法各有优缺点,可以根据不同的场景选择合适的方案:

  • stopwatch手动统计:适合临时测试,快速实现
  • 全局aop:适合对整个服务层进行性能监控
  • 自定义注解+aop:适合精细化控制,只监控关键方法
  • 拦截器:适合web接口监控
  • actuator+micrometer:适合生产环境,与专业监控系统集成
  • filter:适合全局请求监控,轻量级实现
  • servletrequesthandledevent:全局监控http请求处理时间,不需改动代码

以上就是springboot中统计方法耗时的七种实现方式小结的详细内容,更多关于springboot统计方法耗时的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com