Я пытаюсь настроить следующее Dagger 2:
EventFinder
имеет две части: TriggerFinder
и ArgFinder
каждый из которых имеют много различных реализаций, которые сами являются сложными объектами с большим количеством зависимостей. В приведенном ниже примере кода успешно создается EventFinder
с образцом TriggerFinder
и ArgFinder
, которые оба зависят от другого объекта, WordNet
. Однако WordNet
- очень большой, дорогой, постоянный объект, который я хотел бы разделить между моделями как одноэлементный. Текущая реализация WithWordNetEventFinderComponent
загружает WordNet
дважды. Если я пытаюсь маркировки метод @Provides
в WordNetModule
как @Singleton
, я получаю ошибку:Singleton прицелы в Dagger 2
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();
}
}
См. [Этот выпуск] (https://github.com/google/dagger/issues/107). – nhaarman
@nhaarman: Спасибо, это определенно кажется уместным, хотя я немного борюсь за то, чтобы довести поток до того, что я должен делать в этой конкретной ситуации. Тем не менее, поток в конечном итоге ссылается на будущую поддержку '@ Subcomponent' как лучшего решения; Я вижу, что '@ Subcomponent' существует, хотя документация разрежена, поэтому было бы здорово, если бы кто-то мог прокомментировать это. –