2013-12-04 2 views
0

У нас есть старое приложение, которое использует модули. Главная точка входа (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?

Было бы проще с Весной или Гизом?

ответ

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"; 
    } 
} 
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, но вы также можете использовать конструктор-инъекцию, чтобы вам не пришлось переписывать все ваши классы, если это помогает)

+0

Я не уверен, что это действительно решает сложную часть вопроса OP, который заключается в том, что некоторые из его классов кормятся * частями * дерева синтаксиса основного файла конфигурации во время их создания. Насколько я знаю, вы не можете сделать это весной, так что ему все равно придется переделывать. –

+0

Я не читал это из вопроса. Подход конфигурации «module XML» очень похож на файл конфигурации Spring, который также может импортировать другие файлы конфигурации Spring. Основываясь на описании, я не думаю, что им пришлось бы менять свои классы вообще, просто переписать конфигурации. (По крайней мере, от того, что я могу сказать в вопросе). – clay

+0

@clay: Спасибо за идею, это был настоящий нож для глаз. (Я бы поставил свой ответ, если мог). – user3065913

Смежные вопросы