带有 Guice 的全局注入器

Global injectors with Guice

我正在创建一个库,为了帮助实现人体工程学,我将在应用程序启动时创建的注入器传递给库中的不同组件,以便用户可以在某些上下文中执行 getInstance() 而无需预先计划在哪里粘贴他们的 @Inject 注释。

这里有一个 API 设计的例子:

public static void main(String[] args) {
  // Main injector is created here behind the scenes. 
  ApexApplication app = new ApexApplication()

  app.get("/users/:id", context -> {
    // Users can do this instead of @Inject UserDAO dao
    UserDAO dao = context.getInstance(UserDao.class)
    User user = dao.findUserById(context.param("id"))
    //... 
  })
  app.start();
}

为清楚起见,以下是关键实施细节的链接:

我知道 Guice 注入器的最佳实践是在整个应用程序中只创建一个,用它来注入所有依赖项,然后将其丢弃;但是,考虑到我想要实现的目标,是否会推荐这种方法或者我应该研究另一种模式?

我认为将带有注入器的上下文发送给每个其他人 class 以访问注入器并不是一个好主意。

还有一种方法,其实和@Jameson的MyModuleHelper的思路很像。 DIContainer 对注入器进行静态初始化并提供 public static API getInjector()。这样你就可以拥有注入器,它只创建一次并且可以用于任何 class 没有样板代码的东西:

public final class DIContainer {
     private static final Injector injector;
     static {
         injector = Guice.createInjector(new AppModule());
     } 
     public static Injector getInjector() {
         return injector;
     }
     private DIContainer() {
     }
}

用法示例:

ServiceProvider service = DIContainer.getInjector().getInstance(ServiceProvider.class);

可能 this post 也很有用。

我听取了@asch 的建议,但对其进行了一些修改以允许用户设置自己的配置模块。

public class DependencyManager {
    private static Injector injector;
    private static Logger logger = LoggerFactory.getLogger(DependencyManager.class);

    public static Injector initializeWith(ApexConfiguration configuration) {
        if(injector == null) {
            logger.debug("Initializing injector")
            injector = Guice.createInjector(configuration);
        }
        return getInjector();
    }

    public static Injector getInjector() {
        if(injector == null) {
            logger.error("Application hasn't been configured yet.");
            return null;
        }
        return injector;
    }

    private DependencyManager() {}
}

我不完全确定它的线程安全性,但在我所有测试的执行过程中,日志消息 Initializing injector 只显示一次,我在调用 [= 时从未得到 NullPointerException 13=].

我认为这是因为库的结构,DependencyManager 必须在任何其他应用程序操作发生之前自动初始化。

欢迎任何comments/suggestions对此进行改进。