1

我正在尝试在 Dagger 2 中设置以下内容:
AnEventFinder有两个部分:aTriggerFinder和 anArgFinder每个部分都有许多不同的实现,它们本身就是具有许多依赖关系的复杂对象。下面的代码示例成功构建了一个EventFinderwith 示例TriggerFinder,并且ArgFinder它们都依赖于另一个对象WordNet. 但是,WordNet它是一个非常大、昂贵、恒定的对象,我想在模型之间作为单例共享。当前的实现WithWordNetEventFinderComponent加载了WordNet两次。如果我尝试将@Provides方法标记WordNetModule为 as @Singleton,则会收到错误消息:

Error: ArgFinderUsingWordNetComponent (unscoped) may not reference scoped bindings:
      @Singleton @Provides WordNet WordNetModule.provideWordNet()

但是在组件树上向上传播@Singleton注释只会导致其他错误。如果这样做的正确方法怎么办?

完整代码:

import org.junit.Test;

import javax.inject.Inject;
import javax.inject.Named;

import dagger.Component;
import dagger.Module;
import dagger.Provides;

// WordNet - this is the expensive shared resource we would
// like to make a singleton
class WordNet {
  final String path;

  public WordNet(@Named("path") String path) {
    System.out.println("Loading Fake wordnet from " + path);
    this.path = path;
  }
}

@Module
class WordNetModule {
  final String path;

  public WordNetModule(String path) {
    this.path = path;
  }

  // uncommenting the line below causes errors
  //@Singleton
  @Provides
  public WordNet provideWordNet() {
    return new WordNet(path);
  }
}

interface TriggerFinder {

}

class TriggerFinderUsingWordnet implements TriggerFinder {
  WordNet wordNet;

  @Inject
  public TriggerFinderUsingWordnet(WordNet wordNet) {
    this.wordNet = wordNet;
  }
}

@Module(includes = WordNetModule.class)
class TriggerFinderWithWordnetModule {    
  @Provides
  public TriggerFinder provideTriggerFinder(TriggerFinderUsingWordnet triggerFinder) {
    return triggerFinder;
  }
}

interface ArgFinder {

}


class ArgFinderUsingWordnet implements ArgFinder {

  WordNet wordNet;

  @Inject
  public ArgFinderUsingWordnet(WordNet fakeWordNet) {
    this.wordNet = fakeWordNet;
  }
}
@Module(includes = WordNetModule.class)
class ArgFinderWithWordNetModule {

  @Provides
  public ArgFinder provideArgFinder(ArgFinderUsingWordnet argFinder) {
    return argFinder;
  }
}

// the composite object we wish to create
class EventFinder {

  private final TriggerFinder triggerFinder;
  private final ArgFinder argFinder;

  @Inject
  public EventFinder(TriggerFinder triggerFinder, ArgFinder argFinder) {
    this.triggerFinder = triggerFinder;
    this.argFinder = argFinder;
  }
}

// components to wire everything together
interface ArgFinderComponent {    
  ArgFinder argFinder();
}

interface TriggerFinderComponent {
  TriggerFinder triggerFinder();
}

@Component(modules = ArgFinderWithWordNetModule.class)
interface ArgFinderUsingWordNetComponent extends ArgFinderComponent {

}

@Component(modules = TriggerFinderWithWordnetModule.class)
interface TriggerFinderUsingWordNetComponent extends TriggerFinderComponent {

}

interface EventFinderComponent {
  EventFinder eventFinder();
}


@Component(dependencies = {ArgFinderUsingWordNetComponent.class,
    TriggerFinderUsingWordNetComponent.class})
interface WithWordNetEventFinderComponent extends EventFinderComponent {

}

public class DaggerComponentTest {
  @Test
  public void withWordNetTest() {
    final WordNetModule wordNetModule = new WordNetModule("myPath");

    DaggerWithWordNetEventFinderComponent.builder()
        .argFinderUsingWordNetComponent(
            DaggerArgFinderUsingWordNetComponent.builder().wordNetModule(wordNetModule).build())
        .triggerFinderUsingWordNetComponent(
            DaggerTriggerFinderUsingWordNetComponent.builder().wordNetModule(wordNetModule).build())
        .build().eventFinder();
  }
}
4

1 回答 1

3

您通常将顶部组件标记为@Singleton然后是所有provide*()需要它的子组件。毕竟,单例只能在全局图级别上得到保证。

从底部开始标记@Singleton将导致多个错误(正如您所经历的那样),直到您到达顶部。所以可能会更容易回滚并从顶部开始@Component

于 2015-07-16T13:02:37.893 回答