Java自定义注解通过“容器注解+正交子注解”分层构建可读、可维护、可扩展的策略元数据结构:@TenantScope、@TimePartition、@BusinessType各司一维,@Strategy统一聚合,支持SpEL动态解析与运行时校验缓存。

Java 自定义注解中通过组合多个注解实现复杂业务策略标记,核心不是简单叠加,而是用“容器注解 + 正交子注解”构建可读、可维护、可扩展的策略元数据结构。关键在于分层清晰、职责单一、运行时可解析。
设计正交的策略维度子注解
把多维策略(如租户、时间、业务类型、环境)拆成独立注解,每个只管一个维度,互不耦合:
-
@TenantScope:专注租户隔离逻辑,含
tenantId()、isolationMode()等字段 -
@TimePartition:只处理时间切片,支持
pattern="log_{yyyy_MM}"、timezone() -
@BusinessType:描述业务上下文,含
code()、version(),可声明为数组以支持多类型匹配 - 所有子注解都必须标注
@Retention(RetentionPolicy.RUNTIME)和明确@Target,确保反射可用
用容器注解聚合并统一调度
定义一个顶层注解(如 @Strategy)作为策略入口,它不实现逻辑,只声明各维度配置:
- 成员字段直接引用子注解类型,例如:
TenantScope tenant() default @TenantScope(); - 支持数组形式容纳多个同类型策略,如:
BusinessType[] types() default {}; - 避免嵌套过深——容器注解最多包含 2–3 层子注解,超过则需重构维度或引入表达式字段
预留动态能力,适配运行时上下文
纯静态值无法应对真实场景,需在子注解中嵌入轻量表达式支持:
立即学习“Java免费学习笔记(深入)”;
- 每个子注解加一个
String resolver() default "";或String spEL() default "";字段 - 配套编写统一解析器(如
StrategyResolver),结合ThreadLocal租户上下文、SpringEnvironment或 SpELEvaluationContext计算实际值 - 示例:
@Strategy(time = @TimePartition(pattern = "event_{yyyy_MM_dd}", spEL = "#{T(java.time.LocalDate).now().getYear()}"))
保障类型安全与运行健壮性
组合注解容易因配置缺失或冲突导致失效,需主动设防:
- 所有属性尽量提供合理默认值,减少必填项;枚举类用于状态标识(如
ExecutionPhase),避免字符串硬编码 - 在解析阶段做校验:检查必要维度是否非空、SpEL 表达式是否可编译、租户 ID 是否在白名单内
- 对高频访问的策略配置做缓存(如用
ConcurrentMap<Method, StrategyConfig>),避免重复反射解析 - 确保注解与 Spring AOP、JPA 或自定义拦截器协同工作,例如在切面中用
AnnotatedElementUtils安全获取容器注解及其嵌套内容


















