我有一个带有构造函数的类,例如:
@Inject
public ClassTest(ITestInterface testInterface, Class<?> clazz){
...
}
问题是我如何将一个类绑定到一个可以注入到这个构造函数中的实现,并且ClassTest
绑定会选择正确的类吗?
我想在不同的时间点注入不同的类。当我试图解决它时,Guice 给出了一个错误,它找不到任何合适的构造函数java.lang.Class
。
我有一个带有构造函数的类,例如:
@Inject
public ClassTest(ITestInterface testInterface, Class<?> clazz){
...
}
问题是我如何将一个类绑定到一个可以注入到这个构造函数中的实现,并且ClassTest
绑定会选择正确的类吗?
我想在不同的时间点注入不同的类。当我试图解决它时,Guice 给出了一个错误,它找不到任何合适的构造函数java.lang.Class
。
我认为你必须使用Guice 的辅助注入扩展。
基本上,您ClassTest
按原样定义您的,但将“变化”的依赖项标记为@Assisted
:
@Inject
public ClassTest(ITestInterface testInterface, @Assisted Class<?> clazz){
...
}
然后为接受参数并返回s的ClassTest
对象创建一个工厂接口:Class
ClassTest
public interface ClassTestFactory {
ClassTest create(Class<?> clazz);
}
然后你安装特殊类型的模块,它会为你创建工厂:
// Inside your module
install(new FactoryModuleBuilder().build(ClassTestFactory.class));
然后,无论您需要ClassTest
实例,都应该注入ClassTestFactory
接口:
@Inject
YourLogicClass(ClassTestFactory ctFactory) {
this.ctFactory = ctFactory;
}
ClassTest
最后,您使用它为您想要的每个类对象创建s:
ClassTest ct1 = ctFactory.create(SomeClass.class);
ClassTest ct2 = ctFactory.create(AnotherClass.class);
但如果我是你,我真的会重新考虑整个类的架构,以避免需要这些东西。
即使没有辅助注入也可以解决这个问题,只需TypeLiteral
在创建绑定时使用 a :
import javax.inject.Inject;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
public class ClassTest
{
static interface ITestInterface {}
@Inject
public ClassTest(ITestInterface testInterface, Class<?> clazz)
{
System.err.println("testInterface=" + testInterface);
System.err.println("clazz=" + clazz);
}
public static void main(String... argument)
{
ITestInterface testObject = new ITestInterface() {};
Module module = new AbstractModule()
{
@Override
protected void configure()
{
binder().bind(ITestInterface.class).toInstance(testObject);
binder().bind(new TypeLiteral<Class<?>>() {}).toInstance(testObject.getClass());
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
};
Injector injector = Guice.createInjector(module);
injector.getInstance(ClassTest.class);
}
}
运行此代码时的输出类似于:
testInterface=ClassTest$1@3d921e20
clazz=class ClassTest$1
不过,我必须同意@VladimirMatveev 的观点,这是一个有点不寻常的用例,并且需要注入java.lang.Class
对象可能表明存在设计缺陷。我遇到的这种注入的唯一看似有效的情况是用于类型检查,其中注入的类需要Class
对象来检查其他对象的类型(通过Class.isInstance(...)
),但不希望注入实例(! ) 的那个类(例如,因为它不是一个单例并且可能产生各种其他不希望的对象创建)。尽管如此,即使是这种情况也有些棘手,可能会以更好的方式解决。至少,我会使用更具体的类型参数,例如Class<? extends ITestInterface>
(我怀疑这是 OP 的意图)。
要随时间更改注入的值,您可以使用 Provider bindings。然后它可能看起来像这样:
模块配置:
public class SomeModule extends AbstractModule{
@Override
protected void configure() {
bind(Class.class).toProvider(SomeProvider.class);
}
}
提供者(不是很优雅,但可能是一个开始......):
public class SomeProvider implements Provider<Class<?>>{
private static Class<?> myClazz;
public static void setClass(Class<?> clazz){
myClazz = clazz;
}
@Override
public Class<?> get() {
return myClazz;
}
}
一些不同的类:
public class SomeClass{
public int itWorks;
}
public class SomeOtherClass{
public int itWorksGreat;
}
示例客户端代码:
public static void main(String[] args){
SomeProvider.setClass(SomeClass.class);
Injector injector = Guice.createInjector(new SomeModule());
printFields(injector.getInstance(Class.class));
SomeProvider.setClass(SomeOtherClass.class);
printFields(injector.getInstance(Class.class));
}
private static void printFields(Class clazz) {
Field[] declaredFields = clazz.getDeclaredFields();
for(Field field : declaredFields){
System.out.println(field.getName());
}
}
最后是结果:
itWorks
itWorksGreat