【问题标题】:Dropwizard and Guice: injecting EnvironmentDropwizard 和 Guice:注入环境
【发布时间】:2014-08-30 10:55:42
【问题描述】:

我目前正在构建一个基于 Dropwizard + Guice + Jersey 的应用程序,其中数据库访问暂时由 JDBI 处理。

我想要实现的是拥有典型的企业架构,其中资源访问服务类访问 DAO 类,而 DAO 类又访问数据库。以适当的 DI 方式将所有这些连接起来会很好,尽管我想如果其他所有方法都失败了,我可以在应用程序的 run() 方法中构建我的对象图。

所以,我遇到了这里提到的这个问题before:获取 DBIFactory 需要环境和配置,它们需要在 Guice 执行其注入魔法时可用,而不是在运行()时间。

作为一个 Dropwizard 和 Guice 菜鸟,到目前为止,我设法整合的是我的 DAO 对象需要一个 Provider,这与

public class UserDAOProvider implements Provider<UserDAO> {

    @Inject
    Environment environment;
    @Inject
    Configuration configuration;

    @Override
    public UserDAO get() {
        final DBIFactory factory = new DBIFactory();
        final (MyConfiguration) config = (MyConfiguration) configuration;
        DBI jdbi = null;
        try {
            jdbi = factory.build(environment, config.getDataSourceFactory(),
                    "mysql");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return jdbi.onDemand(UserDAO.class);
    }

}

将其注册为单例提供程序应该让我随后将 UserDAO 注入到我的服务中。

现在,我们如何真正将环境注入到 Provider 中?目前我被困在 Guice 抱怨没有为环境找到合适的构造函数,所以它试图实例化它而不是从 Dropwizard 本身获取它。

这似乎是可行的;有一个 dropwizard-guice 包,我认为它的 DropWizardEnvironmentModule 是我需要的。但我觉得我只是在这里错过了一些难题,以了解如何将事物组合在一起。到目前为止,我还没有找到一个完整的工作示例......

【问题讨论】:

  • 如果您接受答案(以及您的其他问题)也会对其他人有所帮助

标签: dependency-injection guice dropwizard jdbi


【解决方案1】:

我遇到了与 OP 相同的问题,但使用的是 Hibernate 而不是 JDBI。不过,我的简单解决方案适用于 JDBI - 只需将 DBIFactory 切换为 SessionFactory

首先在您的 Guice 模块中为单例 SessionFactory 添加一个注入提供程序:

public class MyModule extends AbstractModule {

    private SessionFactory sessionFactory;

    @Override
    protected void configure() {
    }

    @Provides
    SessionFactory providesSessionFactory() {

        if (sessionFactory == null) {
             throw new ProvisionException("The Hibernate session factory has not yet been set. This is likely caused by forgetting to call setSessionFactory during Application.run()");
        }

       return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
}

您需要在应用程序的 run() 方法中设置单例 SessionFactory。在您的情况下,使用 JDBI,您可以在将 DBIFactory 交给 Guice 模块之前创建和配置它:

public void run(MyConfiguration configuration, Environment environment) {

    myModule.setSessionFactory(hibernateBundle.getSessionFactory());
    ...
}

现在可以在任何需要的地方注入 SessionFactory。我现在对我的 DAO 类使用隐式绑定,只需使用 @Inject 注释构造函数并注入 SessionFactory 单例。我没有明确地为 DAO 类创建提供者:

@Singleton
public class WidgetDAO extends AbstractDAO<App> {

    @Inject
    public WidgetDAO(SessionFactory factory) {
        super(factory);
    }

    public Optional<Widget> findById(Long id) {
        return Optional.fromNullable(get(id));
    }
    ...
}

现在我可以将我的 DAO 单例实例注入到资源中:

@Path("/widgets")
@Produces(MediaType.APPLICATION_JSON)
public class WidgetsResource {

    private final WidgetDAO widgetDAO;

    @Inject
    public WidgetsResource(WidgetDAO widgetDAO) {
        this.widgetDAO = widgetDAO;
    }
    ...
}

请注意,此方法遵循 Guice 建议,即仅注入直接依赖项。不要尝试注入 Envrionment 和 Configuration 以便创建 DBI 工厂 - 注入预构建的 DBI 工厂本身。

【讨论】:

    【解决方案2】:

    这就是我在 Dropwizard 中使用 Guice 的方式。在你的 run() 方法中添加一行

    Guice.createInjector(new ConsoleModule()); 
    

    你不能注入 Environ

    创建类 ConsoleModule

    public class ConsoleModule extends AbstractModule {
    
        //configuration and env variable declaration
    
        public  ConsoleModule(ConsoleConfiguration consoleConfig, Environment env)
        {
            this.consoleConfig = consoleConfig;
            this.env= env;
        }
    
        protected void configure()
        {
            //You should not inject Configuration and Environment in your provider since you are mixing     
            //dropwizard framework stuff with Guice.Neverthless you will have to bind them in the below order
    
            bind(Configuration.class).toInstance(consoleConfig.class);
            bind(Environment.class).toInstance(env.class);
            bind(UserDAO.class).toProvider(UserDAOProvider.class).in(Singleton.class);
        }
    }
    

    【讨论】:

    【解决方案3】:

    我们有相同的配置 (dw-jdbi-guice),还有一个抽象的“基础”Application 类,这让事情变得更加复杂。

    由于run 方法期间发生了很多事情,而且很多事情都取决于配置对象,我们最终在 run 方法中创建了注入器。但是由于我们还需要来自 bootsrap 的对象(例如 ObjectMapper),所以我们最终在 Application 类中有一个 List&lt;Module&gt; 字段。不是最漂亮的解决方案,但可以处理各种场景。

    【讨论】:

    • 谢谢——我们已经决定完全摆脱 Dropwizard。开始使用它似乎很容易,但随着应用程序的增长,它只是在路上......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多