本文介绍了Dropwizard和Guice:注入环境的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在构建一个基于Dropwizard + Guice + Jersey的应用程序,该应用程序暂时由JDBI处理.

I am currently building a Dropwizard + Guice + Jersey-based application where the database access is being handled by JDBI for the time being.

我要实现的目标是拥有典型的企业体系结构,其中资源访问服务类访问DAO类,而DAO类又访问数据库.最好以正确的DI方式进行所有连接,尽管我想如果所有其他方法都失败了,我可以在应用程序的run()方法中构建对象图.

What I am trying to achieve is to have your typical enterprise architecture, where Resources access Service classes accessing a DAO class that in turn accesses the database. It would be nice to get all this wired up in a proper DI way, although I guess I can build my object graph in the run() method of the application if all else fails.

因此,我遇到了在这里提到的这个问题:获取DBIFactory既需要环境,又需要配置,这在Guice进行注入魔术时而不是在run()时需要以某种方式可用.

So, I'm running into this problem that has been mentioned here before: Getting a DBIFactory requires both the Environment and the Configuration, which somehow need to be available at the time when Guice does its injection magic and not at run()-time.

作为Dropwizard和Guice的菜鸟,到目前为止,我已经设法将我的DAO对象提供给Provider,这很像

Being a Dropwizard and Guice noob, what I've managed to put together so far is that I need a Provider for my DAO objects, something to the tune of

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注入我的服务中.

Registering this as a singleton provider should let me then inject the UserDAO into my Services.

现在,我们如何真正将环境注入提供者?目前,我一直在Guice抱怨无法为环境找到合适的构造函数,因此它正在尝试实例化它,而不是从Dropwizard本身中获取它.

Now, how do we actually get the environment injected into the Provider? Currently I am stuck at Guice complaining about not finding a suitable constructor for the Environment, so it is trying to instantiate it and not grab it from Dropwizard itself.

看来这是可行的;我有一个 dropwizard-guice 包,该包的DropWizardEnvironmentModule是我所需要的.但是我觉得我只是想了解如何将事物组合在一起而在这里遗漏了一些难题.到目前为止,我还没有找到一个完整的工作示例...

It seems like this is doable; there is the dropwizard-guice package whose DropWizardEnvironmentModule is, I think, what I need. But I feel like I'm just missing some piece of the puzzle here for an understanding of how to put things together. I've not managed to find a complete working example so far...

推荐答案

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

I had the same issue as OP but using Hibernate rather than JDBI. My simple solution is applicable to JDBI, though - just switch DBIFactory for SessionFactory.

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

First add an injection provider for a singleton SessionFactory in your Guice module:

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模块:

You need to set the singleton SessionFactory from your application's run() method. In your case, using JDBI, this is where you would create and configure your DBIFactory before handing it over to the Guice module:

public void run(MyConfiguration configuration, Environment environment) {

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

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

Now SessionFactory can be injected wherever it is needed. I now use implicit binding for my DAO classes by just annotating the constructor with @Inject and injecting the SessionFactory singleton. I don't explicitly create providers for DAO classes:

@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单例实例注入资源中了:

Now I can inject my DAO singleton instances into resources:

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

    private final WidgetDAO widgetDAO;

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

请注意,此方法遵循Guice建议,即仅注入直接依赖项.不要只是为了注入环境和配置而创建一个DBI工厂-而是注入预先构建的DBI工厂本身.

Note that this approach follows the Guice recommendation of injecting direct dependencies only. Don't try to inject Envrionment and Configuration just so that you can create a DBI factory - inject the prebuilt DBI factory itself.

这篇关于Dropwizard和Guice:注入环境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 02:08