如何在Guice注射中提供参数,同时不破坏Guice-AOP方法拦截?

时间:2011-09-10 00:49:15

标签: java aop guice factory-pattern

我有一种情况需要使用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的每个可能值创建一个提供程序,这是一个配置噩梦,所以我不能简单地在FooProvider的构造函数中定义Baz

我觉得我在这里缺少一些基本的东西。也许是因为这是我在星期五做的最后一件事。任何想法都将不胜感激。

编辑:如果您能够编辑Foo的来源,则以下答案似乎只能使用“辅助注射”。在某些情况下,Foo实际上可能超出了我的控制范围。如果我自己创建实例(即实现我自己的工厂),那么Guice-AOP方法拦截器似乎并不知道该对象。

2 个答案:

答案 0 :(得分:4)

看起来“辅助注射”可能是一种解决方案:

http://google-guice.googlecode.com/svn/trunk/latest-javadoc/com/google/inject/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 :(得分:1)

如果您不能使用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 s的地方注入Foo

修改

你可以做的非常尴尬的解决方法(允许在Foo上拦截方法):

  • bind(Foo.class).toConstructor(...)
  • 定义并绑定SimpleScope描述的范围here
  • 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 ...虽然它可能不是一个好主意,因为如果你没有& #39; t在方法中根本使用参数,但必须在那里工作。