Dependency injection Dropwizard和Guice:注入环境

Dependency injection Dropwizard和Guice:注入环境,dependency-injection,guice,dropwizard,jdbi,Dependency Injection,Guice,Dropwizard,Jdbi,我目前正在构建一个基于Dropwizard+Guice+Jersey的应用程序,其中数据库访问暂时由JDBI处理 我试图实现的是让您具有典型的企业架构,其中资源访问服务类访问DAO类,而DAO类又访问数据库。以适当的DI方式将所有这些连接起来会很好,尽管我想如果其他方法都失败了,我可以在应用程序的run()方法中构建我的对象图 因此,我遇到了这里提到的这个问题:获取DBIFactory需要环境和配置,它们需要在Guice执行注入魔法时可用,而不是在run()时可用 作为一个Dropwizard和

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

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

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

作为一个Dropwizard和Guice noob,到目前为止,我已经设法将它们组合在一起,我需要一个DAO对象的提供者,这是一个非常好的东西

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);
    }

}
public类UserDAOProvider实现提供程序{
@注入
环境;
@注入
配置;
@凌驾
公共用户dao get(){
最终DBIFactory工厂=新DBIFactory();
最终(MyConfiguration)配置=(MyConfiguration)配置;
DBI-jdbi=null;
试一试{
jdbi=factory.build(环境,config.getDataSourceFactory(),
“mysql”);
}catch(classnotfounde异常){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
返回jdbi.onDemand(UserDAO.class);
}
}
将其注册为单例提供者应该让我将UserDAO注入到我的服务中

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


这似乎是可行的;我认为,有一个包的DropWizardEnvironmentModule就是我所需要的。但我觉得我只是缺少了一些理解如何把东西组合在一起的难题。到目前为止,我还没有找到一个完整的工作示例…

这就是我如何在Dropwizard中使用Guice。在run()方法中添加行

Guice.createInjector(new ConsoleModule()); 
你不能注射环境

创建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);
    }
}

我们有相同的配置(dw jdbi GUI),还有一个抽象的“基本”
应用程序
类,这使事情更加复杂


由于在
run
方法期间发生了很多事情,并且许多事情取决于配置对象,因此我们最终在run方法中创建了注入器。但是,由于我们还需要
bootsrap
中的对象(例如ObjectMapper),因此在应用程序类中有一个
List
字段。这不是最漂亮的解决方案,但可以处理各种场景。

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

首先在GUI模块中为singleton 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;
    }
}
public void run(MyConfiguration configuration, Environment environment) {

    myModule.setSessionFactory(hibernateBundle.getSessionFactory());
    ...
}
您需要从应用程序的run()方法设置singleton
SessionFactory
。在您的案例中,使用JDBI,您可以在将DBIFactory移交给Guice模块之前创建并配置它:

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;
    }
}
public void run(MyConfiguration configuration, Environment environment) {

    myModule.setSessionFactory(hibernateBundle.getSessionFactory());
    ...
}
现在SessionFactory可以在任何需要的地方注入。现在,我通过使用@Inject注释构造函数和注入SessionFactory singleton,为我的DAO类使用隐式绑定。我没有为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));
    }
    ...
}

注意,这种方法遵循Guice的建议,即只注入直接依赖项。不要为了创建DBI工厂而尝试注入环境和配置—注入预构建的DBI工厂本身。

我不太确定我只是“不能”注入环境,因为谷歌给了我很多相反的提示—看起来人们真的在这么做,dropwizard guice包包含一个模块,我相信,就是为了这个目的。我只是不知道如何实际使用它。这就是您所指的可能需要使用提供注释的原因吗?我正在考虑使用它:我非常确定这在某种程度上是可用的,让我来做环境注入。。。我希望避免在run()方法中创建DAO,然后将它们交给同样需要手动创建的服务。但如果由于环境不可用而无法通过注入创建DBI,那么我将采用这种方法。我想这就是您想要的。谢谢——我们已经决定完全摆脱Dropwizard。开始使用它似乎很容易,但随着应用程序的发展,它只是一种阻碍……如果您接受答案(以及您的其他问题),对其他人也会有帮助