简体   繁体   English

全球喷油器与Guice

[英]Global injectors with Guice

I'm creating a library and to help with ergonomics, I'm passing the injector created at application startup to different components in the library so that users can do getInstance() from within certain contexts without having to pre-plan where to stick their @Inject annotations. 我正在创建一个库并帮助进行人机工程学设计,我将在应用程序启动时创建的注入器传递给库中的不同组件,以便用户可以在某些上下文中执行getInstance() ,而不必预先计划将其粘贴在哪里@Inject注解。

Here's an example of the API design: 这是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();
}

Here are links to the key implementation details for clarity: 为了清楚起见,以下是关键实现细节的链接:

  • #1 : Here is where I create the initial (and only) injector #1 :这是我创建初始(也是唯一)注射器的地方
  • #2 : I then pass it along to another library component as part of its constructor #2 :然后,将其作为构造函数的一部分传递给另一个库组件
  • #3 : The other component then delegates calls to getInstance() to the original injector #3 :然后其他组件将对getInstance()调用委托给原始注入器

I know that the best practice wrt Guice injectors is to create one and only one throughout the application, use it to inject all dependencies, then throw it away; 我知道,Guice注入器的最佳实践是在整个应用程序中创建一个并且只有一个,使用它注入所有依赖项,然后将其丢弃。 However, given what I am trying to achieve, would this approach be recommended or is there another pattern I should look into? 但是,考虑到我要实现的目标,是否建议使用此方法,或者我应该考虑其他模式吗?

I do not think that it is a good idea to send the context with injector to every other class in order to have the access to the injector. 我认为将带注入器的上下文发送给其他所有类以访问注入器不是一个好主意。

There is another approach, actually pretty similar to the idea of MyModuleHelper of @Jameson. 还有另一种方法,实际上与@Jameson的MyModuleHelper的想法相似。 The DIContainer does static initialization of the injector and provides the public static API getInjector(). DIContainer对注入器进行静态初始化,并提供公共静态API getInjector()。 This way you can have the injector, which is created only once and it is available to whatever class without boilerplate code: 这样,您就可以拥有仅创建一次的喷射器,并且该喷射器可以用于任何没有样板代码的类:

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

Usage example: 用法示例:

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

May be this post is useful as well. 可能这篇文章也很有用。

I took your advice @asch but changed it up a bit to allow the user to set his own configuration module. 我采纳了您的建议@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() {}
}

I'm not entirely certain about it's thread safety, but throughout the execution of all my tests, the logging message Initializing injector displays only once and I never get a NullPointerException when calling getInjector() . 我不能完全确定它的线程安全性,但是在执行所有测试的过程中,日志记录消息“ Initializing injector仅显示一次,并且在调用getInjector()时从未收到NullPointerException getInjector()

I believe this is because of how the library is structured where the DependencyManager must and is automatically initialized before any other application operations take place. 我相信这是因为库的结构是在任何其他应用程序操作发生之前DependencyManager必须且自动初始化的。

Any comments/suggestions to improve this are welcomed. 欢迎提出任何意见/建议以改善此情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM