2012-05-03 3 views
15

Продолжение с Dependency injection, delayed injection praxis. У меня есть Основной класс:Весна динамическая инъекция, заводская модель

package test; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import org.springframework.stereotype.Component; 

import java.util.List; 
import java.util.Scanner; 

@Component 
public class Main { 
    @Autowired 
    private StringValidator stringValidator; 

    @Autowired 
    private StringService stringService; 

    @Autowired 
    private ValidationService validationService; 

    public void main() { 
     scanKeyboardCreateLists(); 

     stringValidator.validate(); 

     final List<String> validatedList = stringValidator.getValidatedList(); 
     for (String currentValid : validatedList) { 
      System.out.println(currentValid); 
     } 
    } 

    private void scanKeyboardCreateLists() { 
     //Let's presume the user interacts with the GUI, dynamically changing the object graph... 
     //Needless to say, this is past container initialization... 
     Scanner scanner = new Scanner(System.in); 
     int choice = scanner.nextInt(); 

     //Delayed creation, dynamic 
     if (choice == 0) { 
      stringService.createList(); 
      validationService.createList(); 
     } else { 
      stringService.createSecondList(); 
      validationService.createSecondList(); 
     } 
    } 

    public static void main(String[] args) { 
     ApplicationContext container = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml"); 
     container.getBean(Main.class).main(); 
    } 
} 

И графический объект динамически создается в зависимости от взаимодействия пользователя. Я решил использовать приложение, позволяющее мне это проверить очень просто. Кроме того, поскольку списки поддерживаются контейнером, динамический характер этого приложения (и любого другого) не имеет значения, поскольку их можно запросить в любое время, когда приложение им понадобится, поддерживая их элементы.

Остальная часть коды находится здесь:

package test; 

import java.util.List; 

public interface Stringable { 
    List<String> getStringList(); 
} 

package test; 

import org.springframework.stereotype.Component; 

import java.util.ArrayList; 

@Component 
public class StringList extends ArrayList<String> { 
} 

package test; 

import org.springframework.stereotype.Component; 

import javax.inject.Inject; 
import java.util.ArrayList; 
import java.util.List; 

@Component 
public class StringService implements Stringable { 

    private List<String> stringList; 

    @Inject 
    public StringService(final ArrayList<String> stringList) { 
     this.stringList = stringList; 
    } 

    //Simplified 
    public void createList() { 
     stringList.add("FILE1.txt"); 
     stringList.add("FILE1.dat"); 
     stringList.add("FILE1.pdf"); 
     stringList.add("FILE1.rdf"); 
    } 

    public void createSecondList() { 
     stringList.add("FILE2.txt"); 
     stringList.add("FILE2.dat"); 
     stringList.add("FILE3.pdf"); 
     stringList.add("FILE3.rdf"); 
    } 

    @Override 
    public List<String> getStringList() { 
     return stringList; 
    } 
} 

package test; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Component; 

import java.util.ArrayList; 
import java.util.List; 

@Component 
public class StringValidator { 
    private List<String> stringList; 
    private List<String> validationList; 

    private final List<String> validatedList = new ArrayList<String>(); 

    @Autowired 
    public StringValidator(final ArrayList<String> stringList, 
          final ArrayList<String> validationList) { 
     this.stringList = stringList; 
     this.validationList = validationList; 
    } 

    public void validate() { 
     for (String currentString : stringList) { 
      for (String currentValidation : validationList) { 
       if (currentString.equalsIgnoreCase(currentValidation)) { 
        validatedList.add(currentString); 
       } 
      } 
     } 
    } 

    public List<String> getValidatedList() { 
     return validatedList; 
    } 
} 

package test; 

import java.util.List; 

public interface Validateable { 
    List<String> getValidationList(); 
} 

package test; 

import org.springframework.stereotype.Component; 

import java.util.ArrayList; 

@Component 
public class ValidationList extends ArrayList<String> { 
} 

package test; 

import org.springframework.stereotype.Component; 

import javax.inject.Inject; 
import java.util.ArrayList; 
import java.util.List; 

@Component 
public class ValidationService implements Validateable { 

    private List<String> validationList; 

    @Inject 
    public ValidationService(final ArrayList<String> validationList) { 
     this.validationList = validationList; 
    } 

    //Simplified... 
    public void createList() { 
     validationList.add("FILE1.txt"); 
     validationList.add("FILE2.txt"); 
     validationList.add("FILE3.txt"); 
     validationList.add("FILE4.txt"); 
    } 

    public void createSecondList() { 
     validationList.add("FILE5.txt"); 
     validationList.add("FILE6.txt"); 
     validationList.add("FILE7.txt"); 
     validationList.add("FILE8.txt"); 
    } 

    @Override 
    public List<String> getValidationList() { 
     return validationList; 
    } 
} 

Кто-нибудь знает, как бы я решить createList метода вызова() или createSecondList() - без использования конструктора, который в значительной степени силы дизайна. Я думал о фабрике, но фабрика для каждого класса в проекте большего масштаба не кажется хорошей идеей.

Что-то вроде:

<bean ... factory-method="..." depends-on="..." lazy-init="..."/> 

И в фабричный метод экземпляра класса и вызвать метод createList(). Или вызовите его так, используя некоторый метод - который снова выглядит плохо, заставляя метод нести ответственность за создание экземпляра графа объекта.

Картина зависимостей времени выполнения, которые я хочу решить в режиме исполнения ниже:

enter image description here

Есть ли какой-то другой способ, которым я мог бы использовать контейнер для того чтобы достигнуть динамического ленивым инициализационного в зависимости от взаимодействия с пользователем ?

спасибо.

+1

Я понятия не имею, что вы просите. Что вы подразумеваете под «_solve_ метод вызова createList() или createSecondList()»? Если я правильно понимаю, что вы пытаетесь сделать (и я сомневаюсь), я бы создал фабричный класс, который имеет (статический?) Заводский метод, который принимает интерактивный аргумент и создает соответствующий список, затем вводит фабричный объект этого класса в ваш Основной объект. –

+0

Я думал, вы поймете из контекста. Не большой писатель. Да, что-то вроде этого. Вопрос выделен жирным шрифтом. Помимо заводского (статического, конечно) и с использованием pull/initialization объектов (с инициализацией в основном классе, «основным» методом), как я могу построить график динамических объектов, поэтому мне не нужно беспокоиться о «коде» архитектуры "в моем заявлении. Зачем вам вводить фабричный объект в свой основной объект? У вас будет много работы, если все ваши классы будут динамическими. Поскольку у вас должен быть завод на каждом динамическом классе. Я все еще верю, что есть более простое решение :) – pfh

ответ

10

Если вы хотите, чтобы какой-либо член вашего класса был динамически инициализирован \ заполнен при каждом вызове соответствующего получателя, вы можете попробовать метод вхождения метода поиска. Прочитано С. 3.3.4.1here.

Таким образом, даже если класс, содержащий динамический элемент, был создан в scope=singletone (по умолчанию для контейнера с пружинным контейнером) каждый раз, когда вы присоединяетесь к полю, которое имеет назначенный метод поиска, вы получите соответствующий объект в соответствии с бизнес-логикой реализованный внутри метода поиска. В вашем случае список - это интерфейс, поэтому вы можете легко выполнить проверку внутри метода поиска и вернуть проверенный список.

Edit:

Я нашел лучше example в Спринг документации - Я думаю, что это очень ясно. Посмотрите на «3.4.6.1 Уточняющих инъекциях метода»

При настройке Main класса назначить метод поиска его List члена - это будет называться всякий раз, когда вам нужен новый экземпляр List компонента.

Удачи вам!

+0

Это хорошая идея, но перемещение фабрики в метод, похоже, не решает код arhictecture. Кроме того, это добавляет сложности. Внезапно метод должен вернуть требуемый тип. И тогда у меня есть N методов, когда мне требуются N типов. Я смотрю на это неправильно? У Spring нет чего-то вроде @AssistedInject (http://code.google.com/p/google-guice/wiki/AssistedInject, https://jira.springsource.org/browse/SPR-5192)? Вы обычно делаете что-то подобное, если у вас есть «динамическое» приложение? Это похоже на область, в которой опытные программисты не часто посещают это ... – pfh

+0

Я думаю, что достаточно одного метода поиска (убедитесь, что вы не пропустили эту точку) :) метод lookup вернет объект, который реализует некоторые общие интерфейс (List?) или даже интерфейс маркера. Решение о том, какой именно тип объекта может получить метод поиска, может основываться на каком-то внешнем источнике (файле конфигурации, пользовательском вводе и т. Д.), Но все возможные типы должны быть заранее известны. – aviad

+0

Я стараюсь не пропустить точку, но похоже, я терпеть неудачу. Не поймите меня неправильно, я благодарен за ответ. Это - http://java.dzone.com/articles/pragmatic-look-method сильно отличается от того, что я хочу достичь. Я пытаюсь посмотреть на это со всех углов, о которых я могу думать ... Как насчет того, чтобы вы на самом деле пытались сделать пример и продемонстрировать это? Да, я могу использовать интерфейс маркера.Но тогда мне «просто» приходится решать зависимость от времени выполнения. И «метод инъекции» на самом деле не решает этого. Как я могу создавать различные объекты в зависимости от времени выполнения? Я обновил свой вопрос, чтобы вы могли посмотреть на другой. – pfh

2

Похоже, пользователь может выбрать 1 ..N графиков объектов, и вы хотите загрузить только тот, который пользователь выбирает во время выполнения. Если графики известны во время разработки, но пользователь просто выбирает тот, который они хотят, то это звучит для меня, как то, что у вас есть, это набор приложений ApplicationContexts, и вы хотите загрузить только один ApplicationContext, который пользователь выбирает во время выполнения. Итак, почему бы просто не определить набор ApplicationContexts, а затем просто создать экземпляр правильного во время выполнения. Поскольку Spring поддерживает Java Config, имеет смысл определить эти конфиги в качестве классов Java, чтобы вы могли получить наследование и не разрезать/вставлять какой-либо код.

+0

Исправить. Но проблема в том, что контейнер «не знает», каковы объекты во время выполнения. Если у вас есть файл и ожидайте, что пользователь его выберет, вы не сможете статически предопределить все возможные комбинации. Идея хорошая, но динамическая часть решается (используя список как «глобальный» компонент). Реальная проблема заключается в том, как создать экземпляр объекта WHEN, когда пользователь действует (например, нажав кнопку), зная, что у вас есть инициализация в вашем методе. Мне нужна какая-то ленивая инициализация, но я не хочу жертвовать чистотой кода с помощью фабрик или методов инициализации в моем основном методе. – pfh

3

Весна предназначена для повторного использования впрыска компонентов, а не для обработки бизнес-данных и впрыска.

Действительно, некоторые данные используются для инъекций зависимостей, но только для настройки поведения компонентов, а не для создания владельца бизнес-данных.

Кстати, следующий вариант может быть использован в вашем случае: спасибо BeanFactory с BeanFactoryAware interface и использование объема = «прототип», вы можете создать компонент, вызывая getBean() как в that example или that other question: creating bean on demand.

Альтернативный вариант, если у вас есть ограниченное количество бобов для подготовки является использование творению Generic Bean the same way lacking beans are mocked

Теперь рассмотрим, что весна никогда не мусор собирает бобы в его контексте. Поэтому рискованно для потребления памяти создавать Spring beans для хранения бизнес-данных.

Если ваша цель отличается (я надеюсь, что так), возможно, вы пытаетесь реализовать свою собственную поддержку нескольких арендаторов. Spring предоставляет аренда в случае, если у вас есть другой бизнес-контекст для реализации с конкретными компонентами или поведением.

+0

Нет, я еще раз попытался объединить данные и архитектуру бизнеса. Проблема в том, что если вы используете архитектуру ООП, вы не можете использовать контейнер для большой инъекции. Если вы начнете использовать службы без гражданства и разделите код на объекты данных и службы, вы можете использовать весну. Но я не для этого. Я думаю, что statefull объекты все еще управляют (это мое мнение). Я понимаю сбор мусора, объект - синглтон, проблем не будет. Небольшое увеличение памяти практически незаметно. Проблема все еще остается - вы не можете «вырезать» код в код видимой архитектуры. – pfh

+0

OK для statefull компонента с встроенными бизнес-данными. Но как обрабатывать параллелизм или многопользовательский доступ, если он просто синглтон. Будете ли вы использовать потоковые локальные переменные внутри одноэлементного? Вы перейдете к заводской схеме? Искренне концепции JavaEE были разработаны вокруг шаблонов, которые могут быть потокобезопасными и масштабируемыми. Spring был разработан, чтобы использовать одни и те же шаблоны более легким способом, но объективный остается: параллелизм для производительности. –

+0

«Заставьте это работать, а затем оптимизируйте». Цель состоит не в том, чтобы разобраться с параллелизмом прямо сейчас, идея заключалась в том, чтобы придумать способ использования контейнера в динамической среде.Работа с statefull классами по-прежнему является проблемой при использовании какого-либо контейнера в приложении. Отложив это, ваши идеи по работе с ним довольно хороши. И цель «параллелизма для производительности» на самом деле не новая вещь. Итак, да, вы могли бы заставить его работать, используя одноэлемент на одного пользователя (вы могли бы утверждать, что это не будет одиночный). Но достичь действительно великолепного контейнера означало бы сделать его динамичным. – pfh

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