【问题标题】:Pass Parameters to constructor in Guice with no modifications to the Interface/Impl class将参数传递给 Guice 中的构造函数,无需修改 Interface/Impl 类
【发布时间】:2016-03-02 12:08:43
【问题描述】:

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

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

  1. @Named/@Assisted - 两者都需要更改 Impl 的源代码(构造函数)以包含这些注释。 (我无权访问此代码)
  2. 实现 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>

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

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

如何在不使用 Providers 的情况下实现这一点?

【问题讨论】:

    标签: java spring dependency-injection guice


    【解决方案1】:

    我认为最好的选择是Provides methods 和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 上的魔法提供者。这需要一个实现类和依赖项列表(如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);
        }
    }
    

    【讨论】:

    • 我也是这么想的。我想除了提供者我别无选择。
    • 完美解决方案。一种在不创建多个提供程序类的情况下提供构造函数注入的通用方法。但是其中的一个问题是,为什么我们还需要实现 hasDependencies?它在这里意味着什么,因为我们使用泛型和提供者类。仅此一项就应该在这里工作。
    • 我个人认为魔法并不比提供者方法好多少。每个提供者方法只有 4 行,并且是类型安全的。
    • 好吧,我以前没用过hasDependencies。所以在我的生产代码中使用它有点犹豫。我尝试为 hasDependencies 搜索一些参考资料,但没有太大帮助。你能给我一些链接吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 2015-10-11
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    相关资源
    最近更新 更多