Java Guice:从XML文件设置绑定
我正在尝试使用Guice并在XML文件的帮助下进行所有绑定。在我的模块(比方说“CustomModule”)中,我想加载一个XML文件并对其进行解析以设置所有绑定 我能够加载XML文件并检索所需的所有值(下面是我的XML文件的一个示例),但我无法使用这些值来Java Guice:从XML文件设置绑定,java,xml,dependency-injection,guice,dynamic-binding,Java,Xml,Dependency Injection,Guice,Dynamic Binding,我正在尝试使用Guice并在XML文件的帮助下进行所有绑定。在我的模块(比方说“CustomModule”)中,我想加载一个XML文件并对其进行解析以设置所有绑定 我能够加载XML文件并检索所需的所有值(下面是我的XML文件的一个示例),但我无法使用这些值来bind(interfaceValue).to(implementationValue) 到目前为止,我所尝试的: 加载XML文件,检索所有值并将其用作: bind(Class.fromName(Ivalue)).to(Class.fromN
bind(interfaceValue).to(implementationValue)代码>
到目前为止,我所尝试的:
加载XML文件,检索所有值并将其用作:
bind(Class.fromName(Ivalue)).to(Class.fromName(Value))代码>其中Ivalue
是InterfaceFoo
和Value
是Foo
将XML文件作为属性文件加载,并使用Names.bindProperties(binder(),Properties)代码>
手动绑定,这不是我想要的
结果:
不起作用,因为Guice无法验证该实现是否是接口的实现
给出错误未绑定接口的实现
工作正常,但不需要,因为我必须编辑我的CustomModule
来更改绑定(如果我希望Bar
成为interfacefo
的实现)
,但由于没有太多关于它的文档,因此没有太多的成功。我也在这里寻找解决方案,但大多数时候问题都是关于属性或注释的使用
是否有一种简单的方法来指定文件中的接口/实现,并将其作为“配置”提供给Guice
我的XML文件:
据我对Guice的了解,大多数绑定的一致性检查都是在编译时进行的,所以way#1无法正常工作。我认为您可以尝试使用即时绑定()和/或提供程序(),但最终我认为您无法实现目标。在我看来,最大的限制是您必须在源代码中明确指定要绑定的接口,然后您可以(可能)创建一个提供程序来解析xml并通过Class.forName返回正确的实现。我不知道这是否能满足您的需求,但也许这是一个起点。Guice并不是专门为此而设计的。
其思想是,通过在类中执行,您可以获得在类中执行的所有功能和灵活性/@提供了
方法、提供程序
实现、AOP等等。正如你所观察到的,它确实存在,但这并不是你所说的原因所要做的
但是,如果您愿意使用原始类型,您实际上可以执行方法1,然后自己检查类。这不是最干净的代码,但请注意,您的问题是类中的泛型类型,而不是Guice。下面是一个示例,注释掉的伪代码指出了要使此代码在生产中正常工作所需的更改。我想如果你已经走到了这一步,你可以自己解决这个问题。下面是说明该想法的代码:
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class DynamicBinding {
static final String interfaceExample = "DynamicBinding$Foo";
static final String implementationExample = "DynamicBinding$FooBar";
public static void main(String... args) throws ClassNotFoundException {
Injector inj = Guice.createInjector(new CustomModule());
Foo blue = inj.getInstance(Foo.class);
blue.doSomething();
}
static class CustomModule extends AbstractModule {
@Override
protected void configure() {
// for (Entry<interface, implementation> : xml file) {
bindFromStrings(interfaceExample, implementationExample);
// }
}
private void bindFromStrings(String interfaceClass, String implClass) {
try {
Class fooClass = Class.forName(interfaceClass);
// I recommend defining a custom exception here with a better message
if (!fooClass.isInterface()) {
throw new Exception("fooClass must be an interface!");
}
Class fooBarClass = Class.forName(implClass);
// I recommend defining a custom exception here with a better message
if (!fooClass.isAssignableFrom(fooBarClass)) {
throw new Exception("classes must be in same inheritance hierarchy");
}
bind(fooClass).to(fooBarClass);
} catch (Exception e) {
// Logger.getLogger().log(blah);
e.printStackTrace();
}
}
}
public static interface Foo {
void doSomething();
}
public static class FooBar implements Foo {
@Override
public void doSomething() {
System.out.println(this.getClass());
}
}
}
我找到了问题的解决方案,正如durron597所说,问题来自泛型类,而不是直接来自Guice。我设法让一些东西起作用,但它有它的局限性。以下是注释的代码,以便于理解
自定义模块类
@Override
protected void configure() {
// for each entry we got in the xml file
for(Entry<String, String> entry : classNames.entrySet()){
try {
// we create the interface-typed class
Class<IInterface> itf = (Class<IInterface>) Class.forName(entry.getKey());
// and the implementation-typed class
Class<IImplementation> concrete = (Class<IImplementation>) Class.forName(entry.getValue());
// to finally bind them together
bind(itf).to(concrete);
} catch (ClassNotFoundException ex) {
Logger.getLogger(GuiceModule.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
谢谢你的建议。即时绑定并不适合我的情况,因为这意味着我的接口将只由特定类实现,这是错误的,因为它可以根据choosen配置进行更改。最好的解决方案是只根据提供的XML文件使用动态绑定。我将更深入地了解供应商,谢谢。欢迎来到StackOverflow!我很高兴你决定开始发布问题和答案;这是你第一个写得非常好的问题。坚持下去!旁白:请注意,这是一个专家问答的网站,而不是一个论坛——说“我是初学者”或“这是我的第一个问题”之类的话通常是不受欢迎的,因为它们有损于问题本身,所以我将其删除。好的,谢谢你!在接下来的问题中,我会记住这一点。谢谢你的回答@durron597。的确,它提供了更多的灵活性,提供者
非常有趣,但似乎我们必须“硬编码”我们想要提供的东西。我想要一种库,只需向它传递一个配置文件,库就可以进行神奇的绑定。我找到了另一个解决办法,但我会接受你的,因为它更干净。再次感谢您,如果我对提供者
说错了什么,请告诉我。我已经看过了您所说的提供者
,您是对的。我现在明白了为什么您要谈论灵活性和功能,它们可以提供大量的实现,所有这些实现都来自一个接口(借助于保存在某处的一些配置)。如果我能让它工作起来,我会发布一个例子,但是你的回答帮助我理解Guice是如何以及为什么如此强大。如果你不像我在回答中那样检查是否可从中识别,你就有风险了。试着用不在同一层次结构中的类运行模块,看看会发生什么。你是对的@durron597,我知道你污染堆的意思。另外,我的解决方案有点“危险”:它意味着要完全了解类/接口及其关系。最后,我放弃了这个解决方案,改用Providers/ProvidedBy注释。如果有人仍然在寻找关于“动态guice绑定”的解决方案,我会在这里发布。
public class ServiceProvider {
// declaration of the services available [FOR NOW]
@Inject IReaderService iReaderService;
@Inject IReportService iReportService;
@Inject ISerializerService iSerializerService;
@Inject ILoggerService iLoggerService;
public ServiceProvider(){
}
// getters of the services injected
public IReaderService getReaderService() {
return iReaderService;
}
public IReportService getReportService() {
return iReportService;
}
public ISerializerService getSerializerService() {
return iSerializerService;
}
public ILoggerService getLoggerService() {
return iLoggerService;
}
}
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class DynamicBinding {
static final String interfaceExample = "DynamicBinding$Foo";
static final String implementationExample = "DynamicBinding$FooBar";
public static void main(String... args) throws ClassNotFoundException {
Injector inj = Guice.createInjector(new CustomModule());
Foo blue = inj.getInstance(Foo.class);
blue.doSomething();
}
static class CustomModule extends AbstractModule {
@Override
protected void configure() {
// for (Entry<interface, implementation> : xml file) {
bindFromStrings(interfaceExample, implementationExample);
// }
}
private void bindFromStrings(String interfaceClass, String implClass) {
try {
Class fooClass = Class.forName(interfaceClass);
// I recommend defining a custom exception here with a better message
if (!fooClass.isInterface()) {
throw new Exception("fooClass must be an interface!");
}
Class fooBarClass = Class.forName(implClass);
// I recommend defining a custom exception here with a better message
if (!fooClass.isAssignableFrom(fooBarClass)) {
throw new Exception("classes must be in same inheritance hierarchy");
}
bind(fooClass).to(fooBarClass);
} catch (Exception e) {
// Logger.getLogger().log(blah);
e.printStackTrace();
}
}
}
public static interface Foo {
void doSomething();
}
public static class FooBar implements Foo {
@Override
public void doSomething() {
System.out.println(this.getClass());
}
}
}
class DynamicBinding$FooBar
@Override
protected void configure() {
// for each entry we got in the xml file
for(Entry<String, String> entry : classNames.entrySet()){
try {
// we create the interface-typed class
Class<IInterface> itf = (Class<IInterface>) Class.forName(entry.getKey());
// and the implementation-typed class
Class<IImplementation> concrete = (Class<IImplementation>) Class.forName(entry.getValue());
// to finally bind them together
bind(itf).to(concrete);
} catch (ClassNotFoundException ex) {
Logger.getLogger(GuiceModule.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private void parseXmlBindings(){
try {
File file = new File(getClass().getResource("guiceBindings.xml").toURI());
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(file);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getElementsByTagName("binding");
for(int i = 0; i < nodeList.getLength(); i++){
Node node = nodeList.item(i);
if(node.getNodeType() == Node.ELEMENT_NODE){
Element binding = (Element) node;
NodeList itfList = binding.getElementsByTagName("interface");
Element itfElement = (Element) itfList.item(0);
NodeList itfValue = itfElement.getChildNodes();
NodeList concreteList = binding.getElementsByTagName("implementation");
Element concreteElement = (Element) concreteList.item(0);
NodeList concreteValue = concreteElement.getChildNodes();
classNames.put(itfValue.item(0).getNodeValue().trim(), concreteValue.item(0).getNodeValue().trim());
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}