Поставщик, связанный с Guice, не используется для выполнения зависимостей

Я пытаюсь использовать инъекцию провайдера для внедрения предварительно настроенного объекта в фабрику:

public class CacheBuilderProvider 
    implements Provider<CacheBuilder<Object, Object>> {
    public CacheBuilder<Object, Object> get () {
        //Log the cache builder parameters before creation

        CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder();
        //configure the cacheBuilder
        return cacheBuilder;
    }
}

public class MyCacheFactory {
    private final CacheBuilder<Object, Object> cacheBuilder;

    @Inject
    public MyFactory(CacheBuilder<Object, Object> cacheBuilder) {
        this.cacheBuilder = cacheBuilder;
    }
}

public class CacheModule extends AbstractModule {            
    @Override
    protected void configure() {
        bind(CacheBuilder.class)
            .toProvider(CacheBuilderProvider.class)
            .in(Singleton.class);
        bind(MyCacheFactory.class)
            .in(Singleton.class);
    }
}

Когда я использую инжектор для получения экземпляра MyCacheFactory, я не получаю вывод журнала и ненастроенный экземпляр CacheBuilder<Object, Object>; ни одна из моих настроек не применялась. Установка точек останова проверяет, что поставщик никогда не используется.

Я также пробовал применить @Named("MyCacheBuilder") к соответствующим частям:

public class CacheBuilderProvider 
    implements Provider<CacheBuilder<Object, Object>> {
    @Named("MyCacheBuilder")
    public CacheBuilder<Object, Object> get () { //... }
}

public class MyCacheFactory {
    //...

    @Inject
    public MyFactory(
        @Named("MyCacheBuilder") 
        CacheBuilder<Object, Object> cacheBuilder
    ) {
        //... 
    }
}

Когда я пытаюсь запустить этот код, я получаю CreationException:

1) No implementation for com.google.common.cache.CacheBuilder
annotated with @com.google.inject.name.Named(value=MyCacheBuilder) was bound.

Я также пробовал различные комбинации необработанных и универсальных ссылок на типы в объявлениях классов и конструкторов, но без особого успеха.

Я могу обойти это, просто создав поставщика и привязав экземпляр, возвращенный из get(), но я ожидаю (и надеюсь), что Guice сделает это за меня.

Есть ли что-то тонкое (или явное) не так с моей настройкой?


person Matt Mills    schedule 15.03.2012    source источник


Ответы (1)


Это может сработать:

bind(new TypeLiteral<CacheBuilder<Object, Object>>() {})
          .annotatedWith(Names.named("MyCacheBuilder"))
          .toProvider(CacheBuilderProvider.class)
          .in(Singleton.class);

Немного волшебства здесь — это класс TypeLiteral, чья документация по Javadoc вы должны прочитать. По сути, это способ привязки к универсальному типу (в вашем случае CacheBuilder<Object, Object>). Это волшебство необходимо, потому что Java реализует дженерики с использованием стирания, поэтому вы не можете просто написать CacheBuilder<Object, Object>.class.

person Simon Nickerson    schedule 15.03.2012
comment
Спасибо; это помогло. Не могли бы вы добавить некоторое объяснение основной разницы между этим и простой привязкой CacheBuilder.class? - person Matt Mills; 16.03.2012
comment
Я добавил еще немного пояснений. - person Simon Nickerson; 16.03.2012
comment
Спасибо за доп. Я признаю некоторое невежество по этому вопросу, хотя я прочитал эти javadocs; Я не смог больше узнать о различиях, прежде чем спросил. Еще раз спасибо. - person Matt Mills; 17.03.2012