ByteBuddy代理实例的Guice依赖注入报错求助
问题排查:Guice注入ByteBuddy代理Bean失败
问题背景
服务采用Guice做依赖注入,需对某注入Bean的特定方法做Mock/代理。原CGLib实现正常,但CGLib弃用后换用ByteBuddy拦截方案,Guice注入器拒绝生成的代理Bean。
报错信息
Caused by: com.google.inject.CreationException: Unable to create injector, see the following errors: 1) [Guice/ErrorInCustomProvider]: IllegalStateException: Illegal interface class DependencyClientImpl for class DependencyClientImpl$ByteBuddy$EAI3cbku at ClientModule.getDependencyClient(ClientModule.java:146) at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Unknown Source) at com.google.inject.internal.InternalInjectorCreator.injectDynamically(Unknown Source) at com.google.inject.internal.InternalInjectorCreator.build(Unknown Source) at com.google.inject.Guice.createInjector(Unknown Source) at com.google.inject.Guice.createInjector(Unknown Source) at com.google.inject.Guice.createInjector(Unknown Source) at com.vegeta.myservice.MyService.main(MyService.java:55) ... 5 more Caused by: java.lang.IllegalStateException: Illegal interface class com.vegeta.dependencyservice.DependencyClientImplfor class com.vegeta.dependencyservice.DependencyClientImpl$ByteBuddy$EAI3cbku at net.bytebuddy.dynamic.scaffold.InstrumentedType$Default.validated(InstrumentedType.java:1572) at net.bytebuddy.dynamic.scaffold.MethodRegistry$Default.prepare(MethodRegistry.java:519) at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.toTypeWriter(SubclassDynamicTypeBuilder.java:212) at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.toTypeWriter(SubclassDynamicTypeBuilder.java:203) at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$UsingTypeWriter.make(DynamicType.java:4050) at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3734) at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3986) at com.vegeta.myservice.bytebuddy.ProxyBuilder.createProxy(ProxyBuilder.java:19) at com.vegeta.myservice.module.ClientModule.getDependencyClient(ClientModule.java:160) at com.vegeta.myservice.module.ClientModule$$FastClassByGuice$$5d163b.GUICE$TRAMPOLINE(<generated>) at com.vegeta.myservice.module.ClientModule$$FastClassByGuice$$5d163b.apply(<generated>) at com.google.inject.internal.ProviderMethod$FastClassProviderMethod.doProvision(Unknown Source) at com.google.inject.internal.ProviderMethod.doProvision(Unknown Source) at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.provision(Unknown Source) at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.get(Unknown Source) at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(Unknown Source) at com.google.inject.internal.SingletonScope$1.get(Unknown Source) at com.google.inject.internal.InternalFactoryToProviderAdapter.get(Unknown Source) at com.google.inject.internal.SingleParameterInjector.inject(Unknown Source) at com.google.inject.internal.SingleParameterInjector.getAll(Unknown Source) at com.google.inject.internal.ConstructorInjector.provision(Unknown Source) at com.google.inject.internal.ConstructorInjector.construct(Unknown Source) at com.google.inject.internal.ConstructorBindingImpl$Factory.get(Unknown Source) at com.google.inject.internal.FactoryProxy.get(Unknown Source) at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(Unknown Source) at com.google.inject.internal.SingletonScope$1.get(Unknown Source) at com.google.inject.internal.InternalFactoryToProviderAdapter.get(Unknown Source) at com.google.inject.internal.InternalInjectorCreator.loadEagerSingletons(Unknown Source)
实现代码
ClientModule.java
public class ClientModule extends AbstractModule { @Provides @Singleton DependencyClient getDependencyClient() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { DependencyClient rawObject = new ClientBuilder().newClient(); return ProxyBuilder.createProxy(rawObject, new DependencyInterceptorByteBuddy()); } }
ProxyInterceptorByteBuddy.java
public interface ProxyInterceptorByteBuddy { Object intercept(Callable<?> clazz, Method method) throws Exception; }
DependencyInterceptorByteBuddy.java
public class DependencyInterceptorByteBuddy implements ProxyInterceptorByteBuddy { @Override @RuntimeType public Object intercept(@SuperCall Callable<?> clazz, @Origin Method method) throws Exception { if ("foobar".equals(method.getName())) { return 33; } else { return clazz.call(); } } }
ProxyBuilder.java
public class ProxyBuilder { public static <T> T createProxy(T target, ProxyInterceptorByteBuddy interceptor) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException { return (T) new ByteBuddy() .subclass(target.getClass()) .implement(target.getClass()) .method(ElementMatchers.any()) .intercept(MethodDelegation.to(interceptor)) .make() // .load(ClassLoader.getSystemClassLoader()) .load(ProxyBuilder.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION) .getLoaded() .getDeclaredConstructor() .newInstance(); } }
触发错误的调用
final DependencyClient client = injector.getInstance(DependencyClient.class);
解决方案
1. 移除错误的implement调用
ByteBuddy的subclass(target.getClass())已经让代理类继承了目标类,implement方法仅支持传入接口类型,传入普通类会直接触发Illegal interface class错误。修改ProxyBuilder的createProxy方法,删除implement(target.getClass())这一行:
public static <T> T createProxy(T target, ProxyInterceptorByteBuddy interceptor) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException { return (T) new ByteBuddy() .subclass(target.getClass()) // 移除该行:.implement(target.getClass()) .method(ElementMatchers.any()) .intercept(MethodDelegation.to(interceptor)) .make() .load(ProxyBuilder.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION) .getLoaded() .getDeclaredConstructor() .newInstance(); }
2. 修复代理实例的状态传递(可选但关键)
当前代码调用无参构造器创建代理,原目标对象rawObject的状态不会被继承,导致代理调用父类方法时使用默认值而非原对象的属性。可以调整为让代理持有原对象引用,或继承父类构造器传递参数:
调整拦截器与代理构建逻辑
// 修改拦截器接口,增加目标对象参数 public interface ProxyInterceptorByteBuddy { Object intercept(Object target, @SuperCall Callable<?> superCall, @Origin Method method) throws Exception; } // 更新拦截器实现 public class DependencyInterceptorByteBuddy implements ProxyInterceptorByteBuddy { @Override @RuntimeType public Object intercept(Object target, @SuperCall Callable<?> superCall, @Origin Method method) throws Exception { if ("foobar".equals(method.getName())) { return 33; } else { // 可直接调用原对象方法,或执行父类逻辑 return superCall.call(); } } } // 更新ProxyBuilder,让代理持有原对象 public static <T> T createProxy(T target, ProxyInterceptorByteBuddy interceptor) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException { return (T) new ByteBuddy() .subclass(target.getClass()) // 定义私有字段存储原对象 .defineField("delegate", target.getClass(), Visibility.PRIVATE) // 生成接收原对象的构造器 .constructor(ElementMatchers.any()) .intercept(FieldAccessor.ofField("delegate").setsArgumentAt(0)) // 拦截所有方法,绑定原对象到拦截器 .method(ElementMatchers.any()) .intercept(MethodDelegation.to(interceptor) .withBinders(FieldBinder.Binder.install(target.getClass()))) .make() .load(ProxyBuilder.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION) .getLoaded() // 通过带参构造器传入原对象 .getConstructor(target.getClass()) .newInstance(target); }
3. 验证Guice注入兼容性
代理类是DependencyClientImpl的子类,而DependencyClient是接口,代理类会自动继承父类的接口实现,因此Guice可以正常识别并注入DependencyClient类型的实例。
内容的提问来源于stack exchange,提问作者Vegan Vegeta
相关产品推荐
相关产品推荐

