这并不是一个简单的问题,但肯定是一个好问题!你所提到的作用域绑定问题可以有一个测试工具。我认为我可以制作一个 Junit 运行器来生成错误绑定实践的警告。稍后我会在此帖子中更新它。
现在有一个获取绑定作用域的示例。
模块
public class ScopeTestModel extends ServletModule {
@Override
protected void configureServlets() {
super
.configureServlets();
bind(Key.get(Object.class, Names.named("REQ1"))).to(Object.class).in(ServletScopes.REQUEST);
bind(Key.get(Object.class, Names.named("REQ2"))).to(RequestScopedObject.class);
bind(Key.get(Object.class, Names.named("SINGLETON1"))).to(Object.class).asEagerSingleton();
bind(Key.get(Object.class, Names.named("SINGLETON2"))).to(Object.class).in(Scopes.SINGLETON);
bind(Key.get(Object.class, Names.named("SINGLETON3"))).to(SingletonScopedObject.class);
bind(Key.get(Object.class, Names.named("SESS1"))).to(Object.class).in(ServletScopes.SESSION);
bind(Key.get(Object.class, Names.named("SESS2"))).to(SessionScopedObject.class);
}
}
测试用例
public class TestScopeBinding {
private Injector injector = Guice.createInjector(new ScopeTestModel());
@Test
public void testRequestScope() throws Exception {
Binding<Object> req1 = injector.getBinding(Key.get(Object.class, Names.named("REQ1")));
Binding<Object> req2 = injector.getBinding(Key.get(Object.class, Names.named("REQ2")));
Scope scope1 = getScopeInstanceOrNull(req1);
Scope scope2 = getScopeInstanceOrNull(req2);
Assert.assertEquals(ServletScopes.REQUEST,scope1);
Assert.assertEquals(ServletScopes.REQUEST,scope2);
}
@Test
public void testSessionScope() throws Exception {
injector.getAllBindings();
Binding<Object> sess1 = injector.getBinding(Key.get(Object.class, Names.named("SESS1")));
Binding<Object> sess2 = injector.getBinding(Key.get(Object.class, Names.named("SESS2")));
Scope scope1 = getScopeInstanceOrNull(sess1);
Scope scope2 = getScopeInstanceOrNull(sess2);
Assert.assertEquals(ServletScopes.SESSION,scope1);
Assert.assertEquals(ServletScopes.SESSION,scope2);
}
@Test
public void testSingletonScope() throws Exception {
injector.getAllBindings();
Binding<Object> sng1 = injector.getBinding(Key.get(Object.class, Names.named("SINGLETON1")));
Binding<Object> sng2 = injector.getBinding(Key.get(Object.class, Names.named("SINGLETON2")));
Binding<Object> sng3 = injector.getBinding(Key.get(Object.class, Names.named("SINGLETON3")));
Scope scope1 = getScopeInstanceOrNull(sng1);
Scope scope2 = getScopeInstanceOrNull(sng2);
Scope scope3 = getScopeInstanceOrNull(sng3);
Assert.assertEquals(Scopes.SINGLETON,scope1);
Assert.assertEquals(Scopes.SINGLETON,scope2);
Assert.assertEquals(Scopes.SINGLETON,scope3);
}
private Scope getScopeInstanceOrNull(final Binding<?> binding) {
return binding.acceptScopingVisitor(new DefaultBindingScopingVisitor<Scope>() {
@Override
public Scope visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
throw new RuntimeException(String.format("I don't know how to handle the scopeAnnotation: %s",scopeAnnotation.getCanonicalName()));
}
@Override
public Scope visitNoScoping() {
if(binding instanceof LinkedKeyBinding) {
Binding<?> childBinding = injector.getBinding(((LinkedKeyBinding)binding).getLinkedKey());
return getScopeInstanceOrNull(childBinding);
}
return null;
}
@Override
public Scope visitEagerSingleton() {
return Scopes.SINGLETON;
}
public Scope visitScope(Scope scope) {
return scope;
}
});
}
}
作用域对象
@RequestScoped
public class RequestScopedObject extends Object {
}
@SessionScoped
public class SessionScopedObject extends Object {
}
@Singleton
public class SingletonScopedObject extends Object {
}
ProvisionListener
实现的方法。我尝试过TypeListener
,但似乎TypeListener
在Guice具有该类型依赖项的绑定之前被调用。这会导致异常,甚至在某些情况下死锁。private static class ScopeValidator implements ProvisionListener {
private @Inject Injector injector;
private @Inject WhateverScope scope;
@Override
public <T> void onProvision(ProvisionInvocation<T> provision) {
if (injector == null) {
// The injector isn't created yet, just return. This isn't a
// problem because any scope violations will be caught by
// WhateverScope itself here (throwing an OutOfScopeException)
return;
}
Binding<?> binding = provision.getBinding();
Key<?> key = binding.getKey();
if (Scopes.isSingleton(binding) && binding instanceof HasDependencies) {
Set<Dependency<?>> dependencies = ((HasDependencies) binding).getDependencies();
for (Dependency<?> dependency : dependencies) {
Key<?> dependencyKey = dependency.getKey();
Binding<?> dependencyBinding = injector.getExistingBinding(dependencyKey);
if (dependencyBinding != null && Scopes.isScoped(dependencyBinding, whateverScope, WhateverScoped.class)) {
throw new ProvisionException(String.format(
"Singleton %s depends on @WhateverScoped %s",
key, dependencyKey));
}
}
}
}
}
Scopes.isSingleton()
。我卡住的另一部分是拼图的另一部分。我已经找到了一个Guice 4的解决方案,即将发布,但如果可能的话,我仍然希望有一个Guice 3的解决方案。 - Tavian Barnes