将参数传递给 Guice 中的构造函数,无需修改 Interface/Impl 类

Ban*_*ore 3 java spring dependency-injection guice

我想在 Guice 中将接口与 Impl 绑定时传递构造函数参数。

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

  1. @Named/@Assisted - 两者都需要更改 Impl 的源代码(构造函数)以包含这些注释。(我无权访问此代码)
  2. Implement Provider - 通过加载所需的参数返回该 Impl 的实例。这有效。但问题是我有 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>
Run Code Online (Sandbox Code Playgroud)

在吉斯。但传递那些构造函数参数。

bind(IClientWrapper.class).to(ClientWrapper.class);
Run Code Online (Sandbox Code Playgroud)

如何在不使用 Provider 的情况下实现这一目标?

Mic*_*mlk 6

Provides我认为你最好的选择是方法toConstructor绑定的组合。

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

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

就整体代码大小而言,这并不比 Spring 大很多,而且是类型安全的。

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

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

最后一个选择:

我们的遗产:

interface LegacyThing {
}

class LegacyThingImp implements LegacyThing {
    public LegacyThingImp(String test) {
        System.out.println(test);
    }
}
Run Code Online (Sandbox Code Playgroud)

是我在GitHub上的魔法提供者。这需要一个实现类和依赖项列表(如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);
    }
}
Run Code Online (Sandbox Code Playgroud)