2015-06-23 3 views
1

Я пытаюсь настроить следующее 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(); 
    } 
} 
+0

См. [Этот выпуск] (https://github.com/google/dagger/issues/107). – nhaarman

+0

@nhaarman: Спасибо, это определенно кажется уместным, хотя я немного борюсь за то, чтобы довести поток до того, что я должен делать в этой конкретной ситуации. Тем не менее, поток в конечном итоге ссылается на будущую поддержку '@ Subcomponent' как лучшего решения; Я вижу, что '@ Subcomponent' существует, хотя документация разрежена, поэтому было бы здорово, если бы кто-то мог прокомментировать это. –

ответ

3

Вы обычно маркировать компонент верхней как @Singleton, а затем все подкомпонентов и provide*(), что это нужно. В конце концов, singleton может быть гарантирован только на уровне глобального графа.

Начиная с отметки @Singleton снизу приведет к нескольким ошибкам (как вы пережили), пока не доберетесь до самого верха. Поэтому, вероятно, будет проще откат и начать с вершины @Component