在现有项目中使用依赖项注入

时间:2013-12-04 12:59:43

标签: java dependency-injection cdi jboss-weld

我们有一个使用模块的旧应用程序。主入口点(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会更容易吗?

2 个答案:

答案 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

的bean
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";
    }
}