Guiceが一部のバインディングで機能していて、他のバインディングではまったく機能していないという状況があります。明らかに、私はAPIを誤って使用しています。
部分的には、Guiceの使い方に「夢中」になりすぎたことが原因かもしれません。私はModule
sの継承ツリーを作成しましたが、自分の利益のために賢くなりすぎた(または愚かだった!)と思います。
以下のコードを見る前に、JARに配置して複数のプロジェクト間で共有できる再利用可能なものを提供するという、私の意図を理解してください。Module
この抽象的で再利用可能なものは、実装が自動的に尊重Module
する、いわゆる「デフォルトのバインディング」を提供します。と呼ばれるModule
AOPのようなもので、注釈が付けられたメソッドを探し、そのメソッドの実行にかかった時間を自動的に記録します。MethodInterceptor
Profiler
@Calibrated
次の点に注意してください。
@Target({ ElementType.METHOD })
@RetentionPolicy(RetentionPolicy.RUNTIME)
@BindingAnnotation
public @interface Calibrated{}
public class Profiler implement MethodInterceptor {
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
// Eventually it will calculate and log the amount of time
// it takes an intercepted method to execute, hence "Profiler".
System.out.println("Intercepted!");
return arg0.proceed();
}
}
public abstract class BaseModule implements Module {
private Binder binder;
public BaseModule() {
super();
}
public abstract void bindDependencies();
@Override
public void configure(Binder bind) {
// Save the binder Guice passes so our subclasses can reuse it.
setBinder(bind);
// TODO: For now do nothing, down the road add some
// "default bindings" here.
// Now let subclasses define their own bindings.
bindDependencies();
}
// getter and setter for "binder" field
// ...
}
public abstract class AbstractAppModule extends BaseModule {
/* Guice Injector. */
private Injector injector;
// Some other fields (unimportant for this code snippet)
public AbstractAppModule() {
super();
}
// getters and setters for all fields
// ...
public Object inject(Class<?> classKey) {
if(injector == null)
injector = Guice.createInjector(this);
return injector.getInstance(classKey);
}
}
したがって、この小さなライブラリを使用するには、次のようにします。
public class DummyObj {
private int nonsenseInteger = -1;
// getter & setter for nonsenseInteger
@Calibrated
public void shouldBeIntercepted() {
System.out.println("I have been intercepted.");
}
}
public class MyAppModule extends AbstractAppModule {
private Profiler profiler;
// getter and setter for profiler
@Override
public void bindDependencies() {
DummyObj dummy = new DummyObj();
dummy.setNonsenseInteger(29);
// When asked for a DummyObj.class, return this instance.
getBinder().bind(DummyObj.class).toInstance(dummy);
// When a method is @Calibrated, intercept it with the given profiler.
getBinder().bindInterceptor(Matchers.any(),
Matchers.annotatedWith(Calibrated.class),
profiler);
}
}
public class TestGuice {
public static void main(String[] args) {
Profiler profiler = new Profiler();
MyAppModule mod = new MyAppModule();
mod.setProfiler(profiler);
// Should return the bounded instance.
DummyObj dummy = (DummyObj.class)mod.inject(DummyObj.class);
// Should be intercepted...
dummy.shouldBeIntercepted();
System.out.println(dummy.getNonsenseInteger());
}
}
これは多くのコードであるため、すべてを入力するときにいくつかのタイプミスを導入した可能性がありますが、このコードはコンパイルされ、実行時に例外がスローされないことを保証します。
何が起こるかです:
@Calibrated shouldBeIntercepted()
メソッドは傍受されません。しかし...- コンソール出力には、ダミーのナンセンス整数が...29!!!!と表示されます。
したがって、これがどれほど貧弱な設計であると思われるかにかかわらず、Guiceが実際に1つのバインディング(インスタンスバインディング)で機能していると主張することはできませんが、AOPメソッドのインターセプトでは機能していません。
インスタンスバインディングが機能していなかった場合は、喜んで自分のデザインを再検討します。しかし、ここでは別のことが起こっています。私の継承ツリーがBinder
どういうわけか捨てられているのだろうか?
そして、インターセプターをアノテーションに正しくバインドしていることを確認しました。Module
(この継承ツリーの代わりに)実装し、同じアノテーションを使用する別のパッケージを作成しましProfiler
た。これは完全に正常に機能します。
私は以前、すべてのバインディングのInjector.getAllBindings()
マップを文字列として出力していました。MyAppModule
このバグの明確な原因として何も現れていません。
何か案は?