You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 18:07:03