我们有一个使用模块的旧应用程序。主入口点(main()
方法)使用基于XML配置文件的反射来实例化模块(类),如:
<modules>
<module class="com.example.moduleone.ModuleOne" />
<module class="com.example.moduletwo.ModuleTwo" />
<modules>
一些模块在modules.xml
中有其他配置,例如:
<modules>
<module class="com.example.modulethree.ConfigurableModule">
<config>
<keyOne>valueOne</keyOne>
<keyTwo>valueTwo</keyTwo>
</module>
<modules>
这些模块有一个参数化构造函数,它接受org.jdom.Element
实例(从XML文件解析):
public ConfigurableModule(Element moduleConfig) {
...
}
我们想使用CDI / Weld(或其他东西)进行依赖注入。我们如何使用DI框架实例化我们的模块?
使用Spring或Guice会更容易吗?
答案 0 :(得分:1)
是的,使用Spring或Guice会让这更容易。在那里,您可以在配置文件中创建一个对象,并在配置期间将该对象注入另一个对象。
这个概念看起来与你的相似,但更好,因为你不必从头开始重新设计和找到DI的所有细微差别。
来自the Sping docs的示例
<!-- setter injection using the nested <ref/> element -->
<property name="beanOne"><ref bean="anotherExampleBean"/></property>
<!-- setter injection using the neater 'ref' attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
这些类称为bean
,一个实例(“anotherExampleBean”)被注入另一个(“exampleBean”)。 (这个例子使用setter-injection,但你也可以使用构造函数注入,这样你就不必重新编写所有的类,如果有帮助的话)
答案 1 :(得分:0)
我已经找到了粘土开眼界答案的答案。 (谢谢!)
首先,加载modules.xml
:
import static com.google.common.collect.Lists.newArrayList;
import java.util.List;
import javax.annotation.PreDestroy;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Singleton;
@Singleton
public class RequiredModuleConfigurationLoader {
private final List<RequiredModuleConfiguration> configurationList =
newArrayList();
public RequiredModuleConfigurationLoader() {
// read the XML file here
configurationList.add(new RequiredModuleConfiguration(
"cdiproto.ModuleOne", "moduleConfig1"));
configurationList.add(new RequiredModuleConfiguration(
"cdiproto.ModuleTwo", "moduleConfig2"));
}
@Produces
public List<RequiredModuleConfiguration> getRequiredModuleConfigurations() {
return newArrayList(configurationList);
}
@Produces
public ModuleConfiguration getModuleConfiguration(
final InjectionPoint injectionPoint) {
final String injectedClassName = injectionPoint.getMember()
.getDeclaringClass().getName();
for (final RequiredModuleConfiguration requiredModuleConfiguration:
configurationList) {
final String moduleClassName =
requiredModuleConfiguration.getClassName();
if (moduleClassName.equals(injectedClassName)) {
final String option =
requiredModuleConfiguration.getSubConfiguration();
return new ModuleConfiguration(option);
}
}
throw new IllegalStateException("Unknown module: " +
injectedClassName);
}
}
它还根据InjectionPoint
生成每个模块的配置实例。
Application类根据XML配置加载模块如下:
import static com.google.common.collect.Lists.newArrayList;
import java.lang.annotation.Annotation;
import java.util.List;
import javax.annotation.PreDestroy;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.enterprise.util.AnnotationLiteral;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class Application {
private final Annotation qualifiers = new AnnotationLiteral<Any>() { };
@Inject
private List<RequiredModuleConfiguration> requiredModuleConfigurationInstance;
@Inject
private Instance<Module> moduleInstance;
private final List<Module> modules = newArrayList();
public void init() throws Exception {
for (final RequiredModuleConfiguration requiredModuleConfiguration:
requiredModuleConfigurationInstance) {
final String className = requiredModuleConfiguration.getClassName();
final Class<Module> moduleClass =
(Class<Module>) Class.forName(className);
final Instance<Module> currentModuleInstance =
moduleInstance.select(moduleClass, qualifiers);
final Module module = currentModuleInstance.get();
modules.add(module);
}
...
}
...
}
示例模块:
import javax.inject.Inject;
public class ModuleOne implements Module {
@Inject
private ModuleConfiguration moduleConfiguration;
@Inject
ModuleTwo moduleTwo;
public String getName() {
return "moduleOne name";
}
}