可在不修改父类代码前提下,通过AOP对子类继承方法自动注入审计日志:需满足方法为public/protected、启用CGLIB代理,配合自定义@AuditLog注解与@within/@annotation切入点,统一在@AfterReturning等通知中记录日志。

“原型切面编程”并不是标准术语——你实际想问的,是**如何在不修改父类代码的前提下,对子类继承来的方法执行前后自动注入审计日志**。这本质属于 AOP(面向切面编程)的典型场景,核心在于:**切入点要能命中被继承的方法调用,且通知逻辑能正确捕获上下文(如参数、返回值、异常)**。
关键前提:方法必须可被代理拦截
不是所有继承方法都能被 AOP 拦截,需满足以下条件:
- 目标方法不能是 private 或 static —— 它们无法被动态代理或编译时织入捕获
- 若使用 JDK 动态代理(Spring 默认),目标类必须实现接口,且调用需通过接口引用发起;否则需启用 CGLIB 代理(
@EnableAspectJAutoProxy(proxyTargetClass = true)) - 在 Spring 中,直接在子类中重写父类方法后加
@AuditLog注解最可靠;若想无侵入地拦截“未重写”的继承方法,需确保该方法在父类中是 public/protected,且代理对象是子类实例(CGLIB 可代理)
用 Spring AOP 实现继承方法的审计日志
推荐以自定义注解 + 切面方式实现,兼顾清晰性与可维护性:
- 定义注解:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME),支持标注在类上(对整个类所有 public 方法生效)或方法上 - 切入点表达式要覆盖继承链:
@Pointcut("@within(com.example.audit.AuditLog) || @annotation(com.example.audit.AuditLog)")
其中@within能匹配类上标注的注解,从而让子类继承父类方法时,只要子类类名上有@AuditLog,其继承的 public 方法也会被拦截 - 在
@AfterReturning和@AfterThrowing中统一记录日志,用joinPoint.getSignature().getDeclaringTypeName()和.getName()精确识别是哪个类的哪个方法被调用(即使来自父类)
处理参数与返回值的注意事项
继承方法的参数和返回值获取方式与普通方法一致,但需注意:
-
joinPoint.getArgs()返回的是运行时传入的实际参数数组,与方法定义位置无关,无需关心是否继承 - 若需记录敏感字段(如密码、身份证号),应在封装日志实体前做脱敏,不要依赖父类方法签名做推断
- 异步方法(
CompletableFuture或WebFlux)需改用@Around通知,并手动控制执行流程,避免@AfterReturning拿不到最终结果
C# 中类似需求的实现要点
若项目基于 .NET,PostSharp 同样支持继承方法审计,但机制不同:
- 使用
OnMethodBoundaryAspect并设置AttributeTargetTypes = "MyNamespace.MyBaseClass*",可批量织入基类及其所有子类中的匹配方法 - 务必在子类方法上显式添加
[Audit],或确保基类方法本身已标注且AttributeInheritance = CustomAttributes.Inheritance.Multicast - 重新生成解决方案,检查输出窗口是否有
PostSharp: Entering post-compilation日志,确认织入成功
不需要改写父类,也不用在每个子类里重复写日志代码。只要代理机制到位、切入点覆盖准确、上下文提取得当,继承来的方法就能和本地方法一样被干净地审计。










