【问题标题】:How to provide components from a library, for consumption by multiple DI frameworks如何从库中提供组件,供多个 DI 框架使用
【发布时间】:2019-12-05 05:18:52
【问题描述】:

我的团队拥有一个库,该库提供的组件必须可由使用该库的代码引用。我们的一些消费者使用 Spring 来实例化他们的应用程序;其他人使用Guice。我们想要一些关于如何提供这些组件的最佳实践的反馈。出现的两个选项是:

  1. 让我们的库提供一个 Spring Configuration 供消费者使用 @Import 和一个 Guice Module 供他们使用 install
  2. 让我们的库提供一个 ComponentProvider 单例,它提供了获取库提供的相关组件的方法。

这些会是什么样子的快速草图:

两种方法都存在

// In their code
@AllArgsConstructor(onConstructor = @__(@Inject))
public class ConsumingClass {
  private final FooDependency foo;
  ...
}

第一种方法

// In our code
@Configuration
public class LibraryConfiguration {
  @Bean public FooDependency foo() {...}
  ...
}

---

public class LibraryModule extends AbstractModule {
  @Provides FooDependency foo() {...}
  ...
}

========================
========================

// In their code
@Configuration
@Import(LibraryConfiguration.java)
public class ConsumerConfiguration {
  // Whatever initiation logic they want - but, crucially, does
  // *not* need to define a FooDependency
 ...
}

---

// *OR*
public class ConsumerModule extends AbstractModule {
  @Override
  public void configure() {
    // Or, simply specify LibraryModule when creating the injector
    install(new LibraryModule());
    ...
    // As above, no requirement to define a FooDependency
  }
}

第二种方法

// In our code
public class LibraryProvider {
  public static final INSTANCE = buildInstance();
  private static LibraryProvider buildInstance() {...}
  private static LibraryProvider getInstance() {return INSTANCE;}
}

========================
========================

// In their code
@Configuration
public class ConsumerConfiguration {
  @Bean public FooDependency foo() {
    return LibraryProvider.getInstance().getFoo();
  }
  ...
}
// or equivalent for Guice

对于这种情况是否有公认的最佳实践?如果不是,那么每种方法的优缺点是什么,或者我还没有想到的另一种选择?第一种方法的优点是消费者不需要编写任何代码来初始化依赖项,并且 DI 框架可以覆盖依赖项(例如,使用模拟依赖项进行测试);而第二种方法的优点是与 DI 框架无关(例如,如果一个新消费者想使用 Dagger 来实例化他们的应用程序,我们根本不需要更改库)

【问题讨论】:

    标签: java spring dependency-injection guice


    【解决方案1】:

    我认为第一个选项更好。如果您的库在 bean 之间存在相互依赖关系,那么在第二种方法中使用 spring 的情况下,@Configuration 的代码将是:

    1. 脆弱(如果应用程序不知道应该创建某个 bean 怎么办)
    2. 重复 - 此代码将出现在每个消费者的模块中
    3. 当您的库的新版本发布并且消费者想要升级时 - 消费者的配置可能会发生变化(该库可能会公开一个新 bean、弃用甚至删除一些旧的东西等)

    一个小建议:

    您可以使用 Spring 工厂,然后在 Spring Boot 的情况下甚至不需要创建 @Import。只需添加一个 Maven 依赖项,它就会自动加载配置。

    现在,请确保在这种方法的情况下正确处理依赖项。 由于您的代码将包含 spring 和 Juice 相关代码,因此您将为库的 maven/gradle 模块添加两者的依赖项。这意味着,使用 guice 的消费者会因为你的库而获得所有的 spring 东西。有很多方法可以解决这个问题,具体取决于您选择的构建系统,只是想提出来

    【讨论】:

    • 感谢您的回复,谢谢!我们实际上使用的是内部构建系统,因此“maven 依赖项”无关紧要——但我们将研究 Spring 工厂,以建议消费者如何使用。至于我们的消费者在依赖于我们时同时获得 Spring 和 Guice 依赖 - 适当地指出,谢谢,但我们的构建系统有办法排除不必要的依赖,所以应该有办法解决。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多