1.创建自定义注解和创建一个接口相似,但是注解的 interface 关键字需要以 @ 符号开头。

2.注解方法不能带有参数;

3.注解方法返回值类型限定为:基本类型、String、Enums、Annotation 或者是这些类型的数组;

4.注解方法可以有默认值;

5.注解本身能够包含元注解,元注解被用来注解其它注解。

五条语法规则是定义注解的边界,但”实现功能”的关键不在注解本身——注解只是元数据,功能来自处理它的处理器。在 Spring 生态里处理器有四类形态:AOP 切面、BeanPostProcessor、ImportBeanDefinitionRegistrar、以及启动时扫描器。本文按”定义 → 选处理器 → 完整示例”给出可复制的套路。

定义回顾与 Spring 场景元注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
int permits() default 10; // 每秒许可
String key() default ""; // 限流维度 key(SpEL 可选)
}

Spring 场景常用元注解补充:

  • @Component 元标注:让自定义注解”继承”组件语义(标了它就等于 @Component,可被扫描)
  • @AliasFor:组合注解中属性别名透传(如 @Service(“x”) 与自定义注解属性互通)
  • @Inherited:类级注解可被子类继承(注意:方法级注解不继承)

处理器形态一:AOP 切面(方法级横切功能)

最适合:限流、日志、权限、缓存、重试等”包一层方法”的功能。

@Aspect @Component
public class RateLimitAspect {
private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();

@Around("@annotation(rl)")
public Object around(ProceedingJoinPoint pjp, RateLimit rl) throws Throwable {
String key = resolveKey(pjp, rl);
RateLimiter limiter = limiters.computeIfAbsent(key,
k -> RateLimiter.create(rl.permits()));
if (!limiter.tryAcquire()) throw new BizException("请求过频");
return pjp.proceed();
}
}

要点:@annotation(rl) 绑定注解实例直接注入通知参数,省去手动反射取注解;切面本身是 bean,可注入任何服务(Redis、配置中心)。

处理器形态二:BeanPostProcessor(bean 级加工)

最适合:按类/字段注解做容器级增强(注入配置、注册指标、包装代理)。

@Component
public class MetricProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String name) {
if (bean.getClass().isAnnotationPresent(Monitored.class)) {
metrics.register(name, bean); // 把 bean 注册进监控
}
return bean;
}
}

与切面的区别:切面增强”方法调用”,后处理器加工”bean 实例本身”(注册、替换、包装)。

处理器形态三:ImportBeanDefinitionRegistrar(定义级扩展)

最适合:类级注解驱动”自动注册一批 bean”(starter 的 EnableXxx 模式)。

@Target(ElementType.TYPE) @Retention(RUNTIME)
@Import(XxxRegistrar.class)
public @interface EnableXxx { String value() default "default"; }

public class XxxRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata meta, BeanDefinitionRegistry reg) {
Map<String, Object> attrs = meta.getAnnotationAttributes(EnableXxx.class.getName());
reg.registerBeanDefinition("xxxClient",
BeanDefinitionBuilder.genericBeanDefinition(XxxClient.class)
.addPropertyValue("mode", attrs.get("value")).getBeanDefinition());
}
}

使用者写 @EnableXxx("prod") 即获得定制 bean——这就是所有 Spring Boot starter 的开关原理。

处理器形态四:启动扫描器(离线分析)

ApplicationRunner 中扫描 classpath 注解做校验/文档生成(如启动时校验所有 @RestController 方法都有权限注解),属治理类功能。

选型决策表

功能形态 处理器 例子
包方法执行(前后/环绕) AOP 切面 限流、日志、缓存、重试
加工/注册 bean 实例 BeanPostProcessor 监控注册、字段注入
按开关注册新 bean ImportBeanDefinitionRegistrar @EnableXxx starter
全局校验/报表 启动扫描器 规范检查、API 文档

完整落地清单

  1. 定义注解:Target/Retention 选对(方法级 RUNTIME 最常见)
  2. 选处理器形态(上表)
  3. 处理器内取注解:切面用参数绑定;后处理器用反射 getAnnotation
  4. 边界测试:自调用不生效(切面形态)、非 public 不生效、注解漏 Retention=RUNTIME 时反射取不到(null)——三大调试起点

自定义注解实现功能 = 元数据声明 + 处理器执行的两段式;语法五条只是第一段,第二段选对处理器形态才是”实现功能”的全部秘密。