在不修改 Interface/Impl class 的情况下将参数传递给 Guice 中的构造函数

Pass Parameters to constructor in Guice with no modifications to the Interface/Impl class

我想在使用 Guice 中的 Impl 绑定接口时传递构造函数参数。

有几个解决方案,但我没有这些 interfaces/Impl 的代码访问权限。 它们是由其他团队开发的,我已将它们包含在我的项目中。

  1. @Named/@Assisted - 两者都需要更改 Impl 的源代码(构造函数)以包含这些注释。 (我无权访问此代码)
  2. 实现 Provider - 通过加载所需的参数实现 Impl 的 returns 实例。 这有效。 但问题是我有 200 多个这样的现有 DI,我将不得不编写 200 多个提供程序。

目前我们正在使用 Spring DI 并且正在迁移到 Guice。 所以我需要定义类似

的东西
<bean name="clientWrapper" class="com.wrapper.client.ClientWrapper">
    <constructor-arg index="0" value="${server.ip}" />
    <constructor-arg index="1" value="${server.port}" />
</bean>

在 Guice 中。但是传递那些构造函数参数。

bind(IClientWrapper.class).to(ClientWrapper.class);

如何在不使用提供程序的情况下实现这一点?

我认为你最好的选择是Provides methods and toConstructor binding

当您的对象具有无法单独通过类型解决的依赖项时,请使用 @Provides 方法绑定。

public class ProvidesModule extends AbstractModule {
    @Provides
    IClientWrapper clientWrapper(@Named("server.ip") String ip,
                                 @Named("server.port") int port) {
       return new ClientWrapper(ip, port);
    }
}

在整体代码大小中,这并不比 Spring 多很多,而且类型安全。

当构造函数仅具有可以单独按类型计算的依赖项时,则使用 toConstructor 绑定

protected void configure() {
    try {
      bind(TransactionLog.class).toConstructor(
          DatabaseTransactionLog.class.getConstructor(DatabaseConnection.class));
    } catch (NoSuchMethodException e) {
      addError(e);
    }
}

最后一个选项:

我们的遗产:

interface LegacyThing {
}

class LegacyThingImp implements LegacyThing {
    public LegacyThingImp(String test) {
        System.out.println(test);
    }
}

GitHub 是我的魔术师。这需要一个实现 class 和依赖项列表(如 Keys),然后通过 Magic(或反射)找到正确的构造函数。

public class TestMagic {
    public static void main(final String... arg) {
        Guice.createInjector(
                new AbstractModule() {
                    @Override
                    protected void configure() {
                        bind(String.class).annotatedWith(Names.named("testString")).toInstance("Guice!");

                        bind(LegacyThing.class).toProvider(new MagicLegacyProvider<>(LegacyThingImp.class, Key.get(String.class, Names.named("testString"))));
                    }
                }).getInstance(LegacyThing.class);
    }
}