java注解本身不执行逻辑,仅作标记;真正实现无侵入增强依赖aop运行时识别注解并用动态代理织入代码,关键在切面如何响应注解、拦截时机及目标方法调用。

Java 中注解本身不执行逻辑,它只是标记;真正实现无侵入业务增强,靠的是 AOP 在运行时识别这些标记,并通过动态代理织入增强代码。关键不在注解怎么写,而在切面如何响应注解、何时拦截、怎样调用目标方法。
注解作为“开关”和“配置容器”
自定义注解(如 @LogTime、@DistributedLock)需满足两个基本要求:
- 声明为
@Retention(RetentionPolicy.RUNTIME),确保运行期可通过反射读取 - 标注在方法上(
@Target(ElementType.METHOD)),便于 AOP 切面按方法粒度拦截 - 支持属性传参,比如
value()指定日志前缀,timeout()控制锁超时,这些值会在切面中被 SpEL 解析或直接读取
AOP 切面解析注解并织入逻辑
切面类用 @Aspect 标记,配合 @Around 环绕通知,在目标方法执行前后插入共性行为:
- 通过
joinPoint.getSignature().getDeclaringTypeName()和.getName()定位当前方法 - 用
joinPoint.getTarget().getClass().getMethod(...)获取方法对象,再调用getMethod().getAnnotation(YourAnno.class)提取注解实例 - 根据注解属性决定是否执行增强:例如
@LogTime(enabled = false)就跳过耗时统计 - 在
proceed()前后插入逻辑,如记录开始时间、捕获异常、打印耗时、加锁/解锁等
代理机制让增强“看不见”
Spring 启动时自动为带切面的目标 Bean 创建代理对象,业务层调用的始终是这个代理:
- 如果目标类实现了接口,默认用 JDK 动态代理,生成接口实现类,只代理接口方法
- 如果目标类无接口或强制启用,用 CGLIB 生成子类,可代理具体类的方法(但不能代理 final 类或方法)
- 代理对象在调用链中完全透明,业务代码无需感知,也不需要修改原有方法签名或内容
典型增强场景的落地要点
不同用途的注解增强,侧重点略有差异:
-
日志/监控类(如 @LogTime):关注执行耗时、入参、返回值,建议用
@Around统一包裹,避免@Before/@After分离导致异常时漏记结束时间 -
权限/校验类(如 @RequireRole):适合用
@Before拦截,校验失败直接抛异常,阻止后续执行 -
分布式锁类(如 @Lock):必须用
@Around,且加锁成功才proceed(),finally 块中强制释放,防止锁泄露 - 若与
@Transactional共存,注意 @Order 控制顺序——锁应在事务外层,避免锁住未提交数据
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











