@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 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- ✅ 正确:
@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(* *(..))")。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










