SpringBoot应用中如何统计控制器端点近10天的调用次数?
统计Spring Boot端点近X天调用次数的几种实现方式
默认Actuator的metrics只能提供累计调用次数,要实现按时间窗口(比如近10天)统计,可从以下几个方向入手:
1. 基于Micrometer扩展时间维度统计
Micrometer是Spring Boot Metrics的底层实现,我们可以给指标加上时间标签,或按时间维度拆分指标:
方式1:按日期拆分Counter
每天创建带日期标签的Counter,统计当日调用次数,查询时累加近X天的Counter值:
@Component public class DailyEndpointCounter { private final MeterRegistry meterRegistry; public DailyEndpointCounter(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } public void incrementEndpointCall(String endpoint) { String today = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE); Counter.builder("endpoint.daily.requests") .tag("endpoint", endpoint) .tag("date", today) .register(meterRegistry) .increment(); } }
在拦截器里调用计数方法,查询时遍历近X天的日期标签累加数值:
public long getTotalRequestsInLastXDays(String endpoint, int days) { long total = 0; LocalDate current = LocalDate.now(); for (int i = 0; i < days; i++) { String date = current.minusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE); Counter counter = meterRegistry.find("endpoint.daily.requests") .tags("endpoint", endpoint, "date", date) .counter(); if (counter != null) { total += counter.count(); } } return total; }
方式2:结合时序存储的Timer记录
用Timer记录请求时间戳,将指标导出到InfluxDB、Prometheus等时序数据库,直接通过存储的查询语法过滤时间范围统计。比如PromQL查询近10天的端点调用次数:
sum(increase(endpoint.requests_count{endpoint="/api/user"}[10d]))
2. 自定义AOP + 持久化存储
如果需要保留调用明细或更精确的统计,用AOP拦截控制器请求,把调用记录存入数据库,再通过SQL查询时间范围:
步骤1:编写AOP切面
@Aspect @Component public class EndpointCallAspect { private final EndpointCallRepository repository; public EndpointCallAspect(EndpointCallRepository repository) { this.repository = repository; } @Around("execution(* com.yourpackage.controller..*(..))") public Object logEndpointCall(ProceedingJoinPoint joinPoint) throws Throwable { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); String endpoint = attributes.getRequest().getRequestURI(); EndpointCallRecord record = new EndpointCallRecord(); record.setEndpoint(endpoint); record.setCallTime(LocalDateTime.now()); repository.save(record); return joinPoint.proceed(); } }
步骤2:实体类与Repository
@Entity public class EndpointCallRecord { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String endpoint; private LocalDateTime callTime; // 省略getter/setter } public interface EndpointCallRepository extends JpaRepository<EndpointCallRecord, Long> { long countByEndpointAndCallTimeAfter(String endpoint, LocalDateTime startTime); }
步骤3:查询近X天次数
public long getEndpointCallsInLastXDays(String endpoint, int days) { LocalDateTime startTime = LocalDateTime.now().minusDays(days); return endpointCallRepository.countByEndpointAndCallTimeAfter(endpoint, startTime); }
3. 网关层统一统计(若用Spring Cloud Gateway)
如果服务有网关,可在网关添加全局过滤器,统一记录所有请求的端点和时间,再通过存储查询统计,无需每个服务单独实现:
@Component public class EndpointCallFilter implements GlobalFilter, Ordered { private final EndpointCallRepository repository; public EndpointCallFilter(EndpointCallRepository repository) { this.repository = repository; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String endpoint = exchange.getRequest().getPath().value(); EndpointCallRecord record = new EndpointCallRecord(); record.setEndpoint(endpoint); record.setCallTime(LocalDateTime.now()); repository.save(record); return chain.filter(exchange); } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } }
内容的提问来源于stack exchange,提问作者pixel
相关产品推荐
相关产品推荐

