【问题标题】:How to create scoped Guice providers for data objects?如何为数据对象创建范围内的 Guice 提供程序?
【发布时间】:2011-06-12 04:37:17
【问题描述】:

我的问题是,我如何将 guice 提供者的强大功能(他们限定实例范围的能力)用于数据对象?

原因如下:我有一个会话范围的类 WebPage,它根据来自数据库对象 DAO 的 Web 请求获取数据。

//Scope of WebPage: SESSION
class WebPage{
  Provider<DAO> daoProvider; //Scope of DAO: REQUEST

  WebPage(Provider<DAO> daoProvider){
     this.daoProvider = daoProvider;
  }

  public String getMyString(){
    return daoProvider.get().getMyString();
  }

  public int getMyInt(){
    return daoProvider.get().getMyInt();
  }
}

WebPage 对象是 Web 框架的一部分,它使所有页面对象保持在会话中。在每次请求时,getMyStringgetMyInt 方法都会被调用多次以获取值,然后再将它们显示给页面上的用户。假设DAO 对象附加到表中的一个特定行,并且只从该行获取数据。

出于性能原因,我需要daoProvider 始终返回相同的实例,以避免每次调用getMyStringgetMyInt 时都重新连接到数据库。另一方面,必须跨请求更新实例,以便在页面刷新后对数据库的任何更新对用户可见。

所以我正在寻找的是在会话范围的WebPage 对象内的DAO 的请求范围的提供者。问题是我不明白如何在 Guice 中连接它。我试过了,但没有用:

class DAO{
  Result row;

  DAO(int rowId){
    //opens DB connection and establishes a link
    //to the object in question
    this.row = attachRow(rowId);
  }

  String getMyString(){
    this.row.getData("mystring");
  }

  int getMyInt(){
    this.row.getIntData("myint");
  }
}

interface DAOProviderFactory {
  Provider<DAO> create(int rowId);
}

class DAOProviderFactoryImpl implements DAOProviderFactory {
  @Override
  public Provider<DAO> create(int rowId) {
    return new DAOProviderImpl(rowId);
  }
}

@RequestScoped
class DAOProviderImpl implements Provider<DAO> {
  int rowId;

  public DAOProviderImpl(int rowId) {
    this.rowId = rowId;
  }

  @Override
  public DAO get() {
    //I want this instance to be request-scoped!
    return new DAO(rowId);
  }
}

//Then bind it in the module
bind(DAOProviderFactory.class).to(DAOProviderFactoryImpl.class);

这不起作用,因为调用 daoProvider.get() 会在每次调用时返回一个新实例(无作用域)。我想这是因为我的 DAOProviderImpl 对象不是由 Guice 实际管理的。另一个问题是相当数量的样板。

如何使用请求范围的提供程序为具有特定 rowIdDAO 实例提供服务?

如果有人能让我走上正确的道路,我会非常感激!提前致谢。

【问题讨论】:

    标签: java guice


    【解决方案1】:

    这里有几个问题。一个是你有这个DAOProviderFactoryDAOProviderFactoryImpl,它们需要rowId 才能创建DAOProviderImpl,但你从不使用它们。我也不确定 Guice 是如何运行它的,因为 DAO 的构造函数上没有 @Inject,而且你没有任何实际的自定义 DAO 提供程序绑定在这里。

    无论如何,我认为您可以在这里做一些更简单的事情。只需像这样创建DAOFactory

    @RequestScoped
    public class DAOFactory {
      private final Map<Integer, DAO> daos = new HashMap<Integer, DAO>();
    
      public DAO getDao(int rowId) {
        DAO dao = daos.get(rowId);
        if (dao == null) {
          dao = new DAO(rowId);
          daos.put(rowId, dao);
        }
        return dao;
      }
    }
    

    如果你愿意,它当然可以实现一些接口。如果由于某种原因您在检索DAO 的每个地方都不知道rowId,则可以改为先通过设置rowId 来初始化工厂,然后让它返回在别处创建的DAO

    无论如何,您可以在您的WebPage 或任何地方注入一个Provider&lt;DAOFactory&gt;(请求范围)。

    说了这么多,我不禁认为可能会有更好的整体设计适合你,但不知道更多,我不确定那会是什么。

    【讨论】:

    • 确实,我不知道每个地方的rowId,所以我试图通过设置它的rowId 来初始化工厂,但找不到这样做的好方法。由于该工厂还需要初始化rowId,因此创建Provider&lt;DAOFactory&gt; 的方法并不容易。我可以用DAOFactory create(int rowId) 方法定义DAOFactoryFactory 而不是Provider&lt;DAOFactory&gt;。这行得通,但它不仅有点矫枉过正,而且没有重用Provider&lt;T&gt;,它似乎适合这种任务。还是我这样做完全错了?:((
    • @rodion:嗯,另一种选择是给你的DAO 类一个setRowId() 方法并让它初始化行。然后你可以在任何地方注入Provider&lt;DAO&gt;。您当然需要确保始终在任何 get 方法之前调用 setRowId()Provider 用于动态检索绑定在Injector 中的类型的实例。当某些东西需要仅在使用应用程序时才可用的信息(例如此处的行 ID)时,某种类型的工厂是必要的。
    • 谢谢。就个人而言,我不喜欢二传手,所以我宁愿避免这种方法。顺便说一句,我尝试让DAOFactory 实现Provider&lt;DAO&gt;,然后创建一个工厂,该工厂将基于rowId(即Provider&lt;DAO&gt; create(int rowId))创建Provider&lt;DAO&gt; 对象,但Guice 拒绝绑定它。但是,当我用相同的 MyProvider&lt;DAO&gt; 替换 Provider&lt;DAO&gt; 时,它起作用了。 Guice 中的Provider 接口似乎有一些限制。你知道有没有办法绕过这个限制?
    • @rodion:你会在哪里以及如何打电话给Provider&lt;DAO&gt; create(int rowId)?您将无法为每个请求动态绑定该提供程序。使用自定义范围,您可以使用 DAO(或行 ID)为范围设定种子。至于Provider 的事情,我猜你在需要使用bind(...).toProvider(provider) 时尝试bind(...).to(provider)
    • 例如:用户第一次登录时,登录请求调用Provider&lt;UserPageDAO&gt; create(int userId)方法并用它实例化WebPage(实际上WebPage不是Guice直接注入的,@ 987654367@注解有误)。 WebPage 对象保留在会话中,而 get() 上的 Provider&lt;UserPageDAO&gt; 请求将返回每个请求实例。至于第二个问题,我用的是rowId的辅助注入,所以我用的是FactoryModuleBuilder().implement(new TypeLiteral&lt;Provider&lt;DAO&gt;&gt;(){}, DAOFactory.class).build(ProviderDAOFactory.class)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-02
    • 1970-01-01
    • 1970-01-01
    • 2013-08-08
    • 2018-02-13
    • 2016-07-13
    相关资源
    最近更新 更多