Как задать параметры в инъекциях Guice, не нарушая перехват метода Guice-AOP? - PullRequest
3 голосов
/ 10 сентября 2011

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

Например:

public class Foo {
    public Foo(Bar bar, Baz baz) {...}
}

Я хочу, чтобы Guice ввел параметр Bar, но я не узнаю Baz, пока мне не понадобится Foo. Значение также не зависит от области действия (например, RequestScope).

Единственная причина, по которой я хочу, чтобы этот объект был полностью создан Guice, заключается в том, что мне нужен перехват методов. В Guice «созданные вручную экземпляры не участвуют в AOP».

Я пытался сделать это с Provider<Foo>, но это позволяет мне public Foo get() { ... }.

Конфигурационный кошмар был бы необходим для создания провайдера для каждого возможного значения Baz, поэтому я не могу просто определить Baz в конструкторе FooProvider.

Я чувствую, что мне здесь не хватает чего-то фундаментального. Возможно, это потому, что это последнее, что я делаю в пятницу. Любые идеи будут оценены.

Редактировать: Ответ ниже, чтобы использовать «вспомогательную инъекцию», кажется, работает только если у вас есть возможность редактировать источник Foo. Foo может на самом деле быть вне моего контроля в некоторых случаях. И если я сам создаю экземпляры (то есть реализую свою собственную фабрику), то перехватчики метода Guice-AOP, похоже, никогда не узнают об объекте.

Ответы [ 2 ]

4 голосов
/ 10 сентября 2011

Похоже, что «вспомогательная инъекция» может быть решением:

http://google -guice.googlecode.com / SVN / багажник / последнего Javadoc / COM / Google / впрыснуть / assistedinject / FactoryModuleBuilder.html

За исключением того, что это не работает, если у вас нет доступа, чтобы аннотировать конструктор Foo.

РЕДАКТИРОВАТЬ: я обнаружил, что я могу добавить аннотации вспомогательной инъекции, расширив тип и добавив их в конструктор, который я хочу использовать:

public class AssistedFoo extends Foo {
    @AssistedInject
    public AssistedFoo(
        Bar bar,
        @Assisted Baz baz) {
        super(bar, baz);
    }
}

Затем используйте эту расширенную реализацию при регистрации вспомогательной инъекции:

public interface FooFactory {
    Foo create(Baz baz);
}

//...

install(new FactoryModuleBuilder()
    .implement(Foo.class, AssistedFoo.class)
    .build(FooFactory.class));

Дополнительный класс наследования необходим только тогда, когда у вас нет доступа к изменениям Foo. Очевидно, что этот обходной путь не будет работать, если класс final.

1 голос
/ 12 сентября 2011

Если вы не можете использовать Assisted Inject для создания фабрики, вы можете просто написать собственную реализацию фабрики:

// same as for Assisted Inject
public interface FooFactory {
  Foo createFoo(Baz baz);
}

public class FooFactoryImpl implements FooFactory {
  private final Bar bar;

  @Inject
  public FooFactoryImpl(Bar bar) {
    this.bar = bar;
  }

  public Foo createFoo(Baz baz) {
    return new Foo(bar, baz);
  }
}

Затем просто bind(FooFactory.class).to(FooFactoryImpl.class) и ввести FooFactory везде, где вам нужно создатьFoo с.

Редактировать:

Чрезвычайно неуклюжий обходной путь, который вы могли бы сделать (что позволило бы перехватить метод на Foo):

  • bind(Foo.class).toConstructor(...)
  • Определите и привяжите описанную область действия SimpleScope здесь .
  • bind(Baz.class).in(BatchScoped.class)
  • Введено Provider<Foo> иSimpleScope в класс, который хочет создать Foo s.

Тогда:

public Foo someMethod(Baz baz) {
  simpleScope.enter();
  try {
    simpleScope.seed(Baz.class, baz);
    /*
     * We're in the scope for Baz, so it can be injected normally into Foo
     * right now.
     */
    return fooProvider.get();
  } finally {
    scope.exit();
  }
}

Вы даже можете использовать перехват метода для такого метода для обработки области видимости,если метод не private ... хотя это может быть не очень хорошей идеей, так как это может сбить с толку, если вы вообще не используете параметр в методе, но он должен быть там для работы.

...