动态代理需在invoke中通过反射检查method的注解(如getannotation或isannotationpresent)来触发前置增强,注解必须声明为runtime保留策略;jdk代理仅支持接口方法注解,实现类注解需用cglib或移至接口。

动态代理本身不直接识别注解,但可以结合反射在 invoke 方法中读取被调用方法上的注解,从而决定是否执行、以及如何执行前置增强逻辑。关键在于:代理逻辑主动检查 method 对象的注解信息,再按需触发对应处理。
获取方法注解并判断是否需要增强
在 InvocationHandler.invoke() 中,通过 method.getAnnotation(XXX.class) 检查目标方法是否标注了特定注解(如 @Log、@RequireAuth)。只有存在该注解时,才执行相应前置逻辑。
- 注解需声明为 @Retention(RetentionPolicy.RUNTIME),否则运行时不可见
- 建议使用 isAnnotationPresent() 先做快速判断,避免空指针
- 可支持多个注解共存,例如同时检查权限与日志注解
典型实现结构示例
定义一个自定义注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreCheck {
String value() default "default";
}
在 invoke 中解析并响应:
- 调用 method.isAnnotationPresent(PreCheck.class)
- 若为真,取出注解实例:PreCheck ann = method.getAnnotation(PreCheck.class)
- 根据 ann.value() 决定执行哪类校验(如角色检查、参数非空验证等)
- 校验失败可直接抛出异常,中断后续业务方法调用
与 Spring AOP 的联动方式
Spring 并不直接让开发者手写 Proxy.newProxyInstance,而是通过 @Aspect + @Before/@Around 注解自动完成注解驱动的增强。其底层仍基于动态代理(JDK 或 CGLIB),但封装了注解扫描、切点匹配、增强织入等流程。
- 你只需写一个切面类,用 @Pointcut("@annotation(com.example.PreCheck)") 定义拦截规则
- 用 @Before 实现前置逻辑,Spring 自动将该逻辑织入所有带 @PreCheck 的方法调用前
- 实际代理对象由 Spring IOC 容器生成并管理,无需手动创建 Proxy 实例
注意事项与常见陷阱
直接用 JDK 动态代理读取注解时,必须确保被代理对象的方法是通过接口暴露的——因为 JDK 代理只能代理接口方法,而接口方法上的注解默认不会被继承到实现类中(除非显式重复声明)。
- 若注解只写在实现类方法上,JDK 代理无法获取;此时应改用 CGLIB,或把注解移到接口层
- 不要在 invoke 中反复调用 getAnnotation 做重复反射,可考虑缓存已解析的注解元数据
- 注意注解属性的默认值和空值处理,避免 NullPointerException











