Quarkus是否支持类似AspectJ的加载时织入?如何无源码修改加拦截器
Quarkus中的加载时织入与无源码修改的拦截方案
Quarkus本身支持字节码增强,类似AspectJ的加载时织入(LTW),可以通过以下几种方式实现无源码修改的拦截需求:
1. 使用Quarkus的Bytecode Transformer扩展
Quarkus提供了io.quarkus.transformer扩展,允许你在类加载阶段修改字节码,无需修改原始源码:
- 实现
BytecodeTransformer接口,定义对目标类(比如C或接口I)的增强逻辑 - 在Transformer中拦截
myMethod的调用,插入指标生成代码 - 注册Transformer到Quarkus的扩展机制中,测试时会自动生效
示例Transformer伪代码:
@Recorder public class MetricsTransformerRecorder { public BytecodeTransformer transform() { return new BytecodeTransformer() { @Override public byte[] transform(ClassLoader classLoader, String className, byte[] originalBytes) { if ("com.example.C".equals(className)) { // 使用ASM修改字节码,在myMethod前后插入指标逻辑 ClassReader cr = new ClassReader(originalBytes); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES); ClassVisitor cv = new ClassVisitor(Opcodes.ASM9, cw) { @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if ("myMethod".equals(name) && "()V".equals(descriptor)) { // 插入前置指标代码 mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/example/MetricsCollector", "recordStart", "()V", false); // 保留原方法逻辑 // 插入后置指标代码 mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/example/MetricsCollector", "recordEnd", "()V", false); } return mv; } }; cr.accept(cv, ClassReader.EXPAND_FRAMES); return cw.toByteArray(); } return originalBytes; } }; } }
2. 结合ByteBuddy实现动态增强
你可以直接在Quarkus测试中使用ByteBuddy,在测试启动时动态修改目标类:
- 在测试类的
@BeforeAll方法中,使用ByteBuddy重新定义C类,拦截myMethod - 这种方式无需编写Quarkus扩展,适合测试场景快速验证
示例测试代码:
import net.bytebuddy.ByteBuddy; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.matcher.ElementMatchers; public class CTest { @BeforeAll static void setup() { new ByteBuddy() .redefine(C.class) .method(ElementMatchers.named("myMethod")) .intercept(MethodDelegation.to(MetricsInterceptor.class)) .make() .load(C.class.getClassLoader()); } public static class MetricsInterceptor { public static void intercept(@SuperCall Runnable superCall) { // 前置指标逻辑 MetricsCollector.recordStart(); try { superCall.run(); } finally { // 后置指标逻辑 MetricsCollector.recordEnd(); } } } @Test void testMyMethod() { new C().myMethod(); // 验证指标生成 } }
3. 使用Quarkus的ArC扩展与CDI代理(限容器管理实例)
如果目标类能被CDI容器管理,也可以通过CDI拦截器实现:
- 编程式注册
C为CDI bean(无需修改源码,可通过自定义扩展或beans.xml配置) - 编写CDI拦截器,通过类/方法匹配规则指定切点,无需在目标方法上加注解
- 注意:这种方式要求实例通过CDI容器获取(比如
@Inject),而非直接new C()创建
注意事项
- 测试场景优先选ByteBuddy动态增强,实现简单快捷
- 字节码操作需确保符合JVM规范,避免破坏类结构
- Quarkus dev模式下,字节码增强的修改需重启服务才能生效
内容的提问来源于stack exchange,提问作者cnmuc
相关产品推荐
相关产品推荐

