Поле ввода Guice в классе, не созданном Guice - PullRequest
11 голосов
/ 04 августа 2010

У меня есть такой класс, что я создаю себя где-то в моем коде:

class StarryEyes {
   @Inject MyValidator validator;

   public StarryEyes(String name) {
      //..
   }

   public doSomething() {
      // validator is NULL
   }
}

Я хочу, чтобы Guice внедрил экземпляр валидатора, который имеет аннотацию @Singleton. У меня есть модуль, который загружается при запуске и содержит строку:

bind(MyValidator.class);

Однако, похоже, он не работает, так как «валидатор» всегда равен нулю. Я пробовал несколько вариантов, таких как:

bind(MyValidator.class)toInstance(new MyValidator());

или другие подобные вещи. Разве не так должен работать Guice?

1 Ответ

33 голосов
/ 04 августа 2010

Как правило, Guice нужно создавать объекты, чтобы вводить их. Если вы просто позвоните new StarryEyes(name), Guice никогда не увидит этот объект, поэтому он не сможет внедрить его. Одна вещь, которую вы можете сделать, это вызвать injector.injectMembers(obj) для объекта после того, как вы его создали. Однако я бы не рекомендовал это делать, так как вам следует избегать ссылки на инжектор в вашем коде.

То, что вы действительно, вероятно, хотите здесь, это Assisted Inject . С помощью Assisted Inject вы объявите конструктор для своего класса примерно так:

@Inject public StarryEyes(MyValidator validator, @Assisted String name)

Это означает, что validator - это параметр, который Guice должен внедрить, в то время как name должен быть "вспомогательным" (то есть предоставленным во время создания экземпляра).

Затем вы создаете такой интерфейс:

public interface StarryEyesFactory {
  StarryEyes create(String name);
}

С помощью Assisted Inject Guice может реализовать эту фабрику для вас. Вы связываете это так:

bind(StarryEyesFactory.class).toProvider(
    FactoryProvider.newFactory(StarryEyesFactory.class, StarryEyes.class));

Затем вы вводите StarryEyesFactory в любое место, где хотите создать его экземпляр. Там, где вы раньше звонили new StarryEyes(name), теперь вы звоните starryEyesFactory.create(name). Когда вы вызываете create(name) на фабрике, оно примет имя и передаст его конструктору и предоставит сам связанный ограничитель.

Начиная с Guice 3 , вы делаете это с помощью FactoryModuleBuilder :

install(new FactoryModuleBuilder().build(StarryEyesFactory.class));
...