@within匹配类上自定义注解最简洁常用,需确保注解加@Retention(RUNTIME)和@Target(TYPE),表达式必须写全限定名,切面中可通过JoinPoint获取目标类并反射读取注解属性。

直接用 @within 匹配类上声明的自定义注解,是最简洁、最常用的方式。关键不是“怎么写”,而是“怎么配得准、用得稳”——尤其要注意注解作用范围、切面生效条件和参数获取逻辑。
确保自定义注解支持运行时保留
类级别注解必须在 JVM 运行期可见,否则 @within 无法识别:
- 注解需加
@Retention(RetentionPolicy.RUNTIME) - 建议加上
@Target(ElementType.TYPE)(明确只允许标注在类上) - 不需要
@Documented或@Inherited,除非有特殊需求
示例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiLog {
String value() default "";
String tag() default "default";
}@Pointcut 表达式写法要精确
表达式格式固定:@within(全限定类名),不能省略包路径,也不能用通配符代替注解名:
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- ✅ 正确:
@Pointcut("@within(com.example.annotation.ApiLog)") - ❌ 错误:
@within(ApiLog)(缺少包名) - ❌ 错误:
@within(*.ApiLog)(@within不支持通配符匹配注解类) - ❌ 错误:
@within(com.example.annotation.*)(这匹配的是类,不是注解)
切面方法中可直接获取注解实例
在 @Before、@Around 等通知方法中,可通过 JoinPoint 获取目标类,再反射拿到注解对象:
- 通过
joinPoint.getTarget().getClass()得到被代理类(非接口) - 调用
getAnnotation(ApiLog.class)即可读取注解属性 - 注意:Spring AOP 默认代理的是 Bean 实例,所以
getClass()是真实类型,不是 CGLIB 生成的子类
示例:
@Before("@within(com.example.annotation.ApiLog)")
public void logBefore(JoinPoint joinPoint) {
Class<?> targetClass = joinPoint.getTarget().getClass();
ApiLog apiLog = targetClass.getAnnotation(ApiLog.class);
System.out.println("类注解 tag: " + apiLog.tag());
}搭配 @Within 使用的常见组合场景
单用 @within 覆盖整个类所有 public 方法;若需进一步筛选,可与其它表达式组合:
- 只拦截 Controller 类中带特定注解的方法:
@within(org.springframework.web.bind.annotation.RestController) && @annotation(org.springframework.web.bind.annotation.PostMapping) - 排除某些包下的类:
@within(com.example.service.ApiLog) && !within(com.example.service.test..*) - 同时匹配多个类注解:
@within(com.example.annotation.ApiLog) || @within(com.example.annotation.Monitor)
注意:&& 和 || 必须用英文括号包裹整个表达式,如 @Before("(@within(...)) && execution(* *(..))")。

















