spring aop无法拦截final、private、static方法及构造器,且仅支持调用时代理;byte buddy通过类加载时字节码增强,可无侵入覆盖任意方法,并借助advice安全织入权限逻辑。

为什么不用 Spring AOP 而选 Byte Buddy 做权限拦截?
Spring AOP 默认基于代理(JDK 动态代理或 CGLIB),对 final 类、private 方法、构造器、静态方法完全无能为力,且无法在类加载阶段介入。而权限校验常需覆盖 @Controller、@Service 中的任意方法(包括 final 工具方法或 static 工厂方法),此时必须用字节码增强——Byte Buddy 提供了比 ASM 更安全、比 Javassist 更可控的运行时类改写能力。
关键区别在于:Spring AOP 是「调用时拦截」,Byte Buddy 可做到「类加载时织入」,真正实现无侵入——业务代码里不需要任何 @Aspect、@Around 或接口继承。
如何用 Byte Buddy 织入权限检查逻辑到目标方法?
核心是用 Advice 实现方法级增强,而非重写整个方法体。Byte Buddy 的 Advice 机制允许你在目标方法前后插入字节码,且自动处理局部变量表、栈帧和异常传播,比直接用 MethodVisitor 安全得多。
- 定义一个
PermissionCheckAdvice类,用@OnMethodEnter和@OnMethodExit标记静态方法 - 在
@OnMethodEnter中调用权限校验服务(如permissionService.check(context)),校验失败抛出AccessDeniedException - 确保该 Advice 类不被 Spring 管理(避免被代理干扰),且类路径在 agent 加载前就可用
- 使用
new AgentBuilder.Default().type(...).transform(...)指定要增强的类匹配规则
示例片段:
new AgentBuilder.Default()
.type(ElementMatchers.nameContains("Service").or(ElementMatchers.nameContains("Controller")))
.transform((builder, typeDescription, classLoader, module) ->
builder.method(ElementMatchers.any())
.intercept(Advice.to(PermissionCheckAdvice.class)))
.installOn(instrumentation);
如何让权限上下文(如用户 ID、角色列表)在 Advice 中可用?
Byte Buddy 的 Advice 默认无法访问 Spring 上下文,也不能直接注入 Bean。常见错误是试图在 PermissionCheckAdvice 里写 @Autowired ——这会失败,因为 Advice 类由 JVM 直接加载,不走 Spring 生命周期。
- 正确做法是把上下文数据“带进来”:用
@Advice.AllArguments、@Advice.This或@Advice.Local传递参数或目标实例 - 对于用户身份,推荐从 ThreadLocal 获取(如 Spring Security 的
SecurityContextHolder.getContext().getAuthentication()),前提是你的应用已统一设置 - 如果必须依赖 Spring Bean,可提前在 agent 初始化时缓存
ApplicationContext到静态字段(注意线程安全与内存泄漏) - 避免在 Advice 中做耗时操作(如远程鉴权调用),应预加载或异步兜底
启动时加载 agent 还是运行时 attach?哪种更适合生产?
生产环境强烈建议用 JVM 启动参数 -javaagent:path/to/byte-buddy-agent.jar 方式加载。运行时 attach(如通过 VirtualMachine.attach())虽然灵活,但在容器化部署中受限于 PID 可见性、JVM 版本兼容性和 attach 权限(OpenJ9 / GraalVM 不支持)。
- agent jar 必须包含
META-INF/MANIFEST.MF,声明Premain-Class和Can-Redefine-Classes: true - premain 方法里调用
Instrumentation#addTransformer并注册AgentBuilder,否则类加载后无法再增强 - 若用 Spring Boot,可在
spring.factories中注册org.springframework.context.ApplicationRunner做二次校验,但别指望它触发字节码增强 - 注意 JDK 版本:Byte Buddy 1.14+ 支持 JDK 21,但旧版对 record、sealed class 的支持有限
最易被忽略的一点:增强逻辑必须幂等。同一个类可能被多次加载(如热部署、OSGi),AgentBuilder 默认不阻止重复 transform,需自行用 ElementMatcher 排除已处理类或加静态标记位。










