You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring中创建自定义调用计数器注解?

实现方案

完全可以实现,核心基于Spring AOP(面向切面编程) 能力,不用修改业务方法代码,只要给目标方法加自定义注解即可自动触发计数逻辑,具体步骤如下:

1. 定义自定义注解@InvocationCounter

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD) // 限定注解只能作用在方法上
@Retention(RetentionPolicy.RUNTIME) // 运行时生效
public @interface InvocationCounter {
    String path(); // 自定义统计路径参数
}

2. 引入AOP依赖

如果是Spring Boot项目,直接在pom.xml引入对应starter即可:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

普通Spring项目引入aspectjweaver等相关aspectj依赖即可。

3. 编写计数切面逻辑

切面用于拦截所有加了@InvocationCounter注解的方法,自动触发计数服务:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class InvocationCounterAspect {

    @Autowired
    private InvocationCounterService counterService;

    // 切点规则:匹配所有带@InvocationCounter注解的方法
    @Pointcut("@annotation(com.yourpackage.InvocationCounter)")
    public void counterPointcut() {}

    // 方法执行前触发计数逻辑
    @Before("counterPointcut()")
    public void doCount(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        InvocationCounter annotation = signature.getMethod().getAnnotation(InvocationCounter.class);
        // 拿到注解上配置的path参数传入计数服务
        counterService.count(annotation.path());
    }
}

注意把代码中的com.yourpackage替换成你实际存放@InvocationCounter注解的包路径。

4. 修正计数服务的线程安全问题

你提供的InvocationCounterService存在线程安全风险,优化为如下实现:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Service
public class InvocationCounterService {
    // 用ConcurrentHashMap保证多线程下的操作安全
    private final Map<String, AtomicInteger> counter = new ConcurrentHashMap<>();

    public void count(String path) {
        // computeIfAbsent是原子操作,避免多线程场景下重复初始化计数对象
        counter.computeIfAbsent(path, k -> new AtomicInteger()).incrementAndGet();
    }

    @Scheduled(fixedRate = 60000)
    public void persist() {
        // 可选逻辑:定时持久化或者处理统计数据
    }
}

5. 开启功能支持

  • Spring Boot项目默认已经开启AOP自动配置,只要在启动类加@EnableScheduling注解开启定时任务即可
  • 普通Spring项目需要额外在配置类加@EnableAspectJAutoProxy注解开启AOP支持

最终效果

你只要在目标Controller方法上加@InvocationCounter(path = "/test1")注解,每次接口被调用时都会自动触发计数逻辑,不需要修改业务方法内部的任何代码。

注意事项

如果是类内部调用本类的加注解方法,会因为绕过了代理对象导致AOP失效。你当前场景是Controller对外接口,都是外部请求触发,不会有这个问题。如果需要支持内部调用,可以用ApplicationContext手动获取代理对象调用,或者改用字节码增强的实现方式。

内容的提问来源于stack exchange,提问作者membersound

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 19:36:00