Пружинный динамический впрыск, заводской рисунок

Продолжение Внедрение зависимостей, практика отложенного внедрения. У меня есть основной класс:

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(). Или назовите это так, из какого-то метода, что снова выглядит плохо, вынуждая метод нести ответственность за создание экземпляра графа объектов.

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

введите здесь описание изображения

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

Спасибо.


person pfh    schedule 03.05.2012    source источник
comment
Я понятия не имею, что вы спрашиваете. Что вы подразумеваете под решить вызов метода createList() или createSecondList()? Если я прав в своем предположении о том, что вы пытаетесь сделать (и я сомневаюсь в этом), я бы создал фабричный класс, который имеет (статический?) фабричный метод, который принимает интерактивный аргумент и создает соответствующий список, а затем вводит фабричный объект этого класса в ваш основной объект.   -  person Old Pro    schedule 07.05.2012
comment
Я думал, ты поймешь из контекста. Не лучший автор вопросов. Да, что-то вроде этого. Вопрос выделен жирным шрифтом. Помимо фабрики (статической, конечно) и использования вытягивания/инициализации объектов (с инициализацией в классе Main, основным методом), как я могу построить динамический граф объектов, чтобы мне не пришлось беспокоиться об архитектурном коде в моем приложении . Зачем вам вводить фабричный объект в ваш основной объект? У вас будет много работы, если все ваши классы будут динамическими. Поскольку у вас должна быть фабрика для каждого динамического класса. Я все еще верю, что есть более простое решение :)   -  person pfh    schedule 07.05.2012


Ответы (3)


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

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

Изменить:

Я нашел лучший пример в документации Spring - я думаю, это очень ясно. Взгляните на «3.4.6.1 Внедрение метода поиска»

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

Удачи!

person aviad    schedule 07.05.2012
comment
Это хорошая идея, но перенос фабрики в метод, похоже, не решает код архитектуры. Кроме того, это добавляет сложности. Внезапно метод должен вернуть требуемый тип. И тогда у меня есть N методов, когда мне требуется N типов. Я смотрю на это неправильно? В Spring нет чего-то вроде @AssistedInject(code.google.com/p/ google-guice/wiki/AssistedInject, jira.springsource.org/browse/SPR- 5192)? Вы обычно делаете что-то подобное, если у вас есть динамическое приложение? Кажется, это область, которую опытные программисты посещают не так часто... - person pfh; 08.05.2012
comment
Я думаю, что достаточно одного метода поиска (убедитесь, что вы не пропустили этот момент) :) метод поиска вернет объект, который реализует какой-то общий интерфейс (список?) или даже интерфейс-маркер. Решение о том, какой именно тип объекта будет создавать метод поиска, может быть основано на некотором внешнем источнике (файл конфигурации, пользовательский ввод и т. д.), но все возможные типы должны быть известны заранее. - person aviad; 08.05.2012
comment
Я пытаюсь не упустить момент, но кажется, что я терплю неудачу. Не поймите меня неправильно, я благодарен за ответ. Это - java.dzone.com/articles/pragmatic-look-method сильно отличается от того, чего я хочу достичь. Я пытаюсь посмотреть на это со всех возможных точек зрения... Как насчет того, чтобы попытаться привести пример и продемонстрировать это? Да, я могу использовать маркерный интерфейс. Но тогда мне просто нужно решить зависимость времени выполнения. И инъекция метода на самом деле не решает этого. Как я могу создавать экземпляры разных объектов в зависимости от времени выполнения? Я обновил свой вопрос, чтобы вы могли взглянуть еще раз. - person pfh; 08.05.2012
comment
Статья, на которую вы ссылаетесь, действительно сильно отличается от того, чего, как я думал, вы хотели достичь. (Вам не нужен АОП, я указал на конкретный абзац в весеннем методе поиска документа). Прежде чем я опубликую пример, мне нужно небольшое пояснение: что вы подразумеваете под ... в зависимости от времени выполнения? - person aviad; 08.05.2012
comment
Я имею в виду в зависимости от параметра времени выполнения, как в примере. Если пользователь введет 0, он получит совершенно другое дерево объектов, чем если бы он ввел что-то еще. Параметр запрашивается после инициализации контейнера, поэтому объекты создаются динамически в зависимости от того, что ввел пользователь. Дело в том, что этот метод должен инициализировать объект, вызывая другой метод для зависимого объекта в зависимости от пользовательского ввода. . Этот зависимый метод на самом деле является методом обработки класса, который изменяет список. - person pfh; 08.05.2012
comment
НО мне не нужен список. Я разобрался со списками. Я создаю их в контейнере. ‹bean id=validationList class=java.util.ArrayList scope=singleton/›. ‹bean id=validationService class=test.ValidationService scope=singleton› ‹constructor-arg name=validationList ref=validationList/› ‹/bean› Я не могу использовать метод поиска для фактической реализации некоторой логики создания. Я не могу ввести оператор if и ожидать, что контейнер подберет его. Я не могу использовать метод поиска в качестве фабрики, я могу использовать его как простой получатель контейнерных компонентов. Правильный? - person pfh; 09.05.2012
comment
Я не могу использовать метод поиска, чтобы на самом деле реализовать некоторую творческую логику. Неправильно, вы можете. Я не могу использовать метод поиска в качестве фабрики. Неправильно, вы можете. Я могу использовать его как простой получатель bean-компонентов из контейнера. Правильно, можно, но какой в ​​этом смысл? - person aviad; 09.05.2012
comment
Действительно? Я могу использовать метод поиска, чтобы реализовать некоторую творческую логику? То, как я это понял, и то, как работает неабстрактный И абстрактный способ, заключается в том, что метод поиска не может реализовать творческую логику. Я знаю, что он может производить бобы (в случае, если они прототипированы) или что он может извлекать бобы (в случае, если они являются синглетами). Мне нужно вызвать код инициализации объекта в методе поиска. Мне нужно создать экземпляр класса и инициализировать его методом. Вот в чем проблема. Это вопрос. Как мне позаботиться о методе инициализации в зависимости от пользовательского ввода? - person pfh; 09.05.2012
comment
Технически вы можете создавать объекты Java, которые вообще не отображаются в конфигурации контекста. Однако тогда контейнер Spring не будет управлять своим жизненным циклом (подумайте о сборке мусора). - person aviad; 13.05.2012

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

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

Кстати, в вашем случае можно использовать следующий вариант: спасибо BeanFactory с интерфейс BeanFactoryAware и использование scope="prototype", вы можете сгенерировать компонент, вызвав getBean(), как в этого примера или из другой вопрос: создание bean-компонентов по требованию.

Альтернативным вариантом, если у вас есть ограниченное количество bean-компонентов для подготовки, является использование общего создания bean-компонентов test/10293543#10293543">так же, как издеваются над отсутствующими бобами

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

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

person Yves Martin    schedule 11.05.2012
comment
Нет, я в очередной раз попытался совместить бизнес-данные и архитектуру. Проблема в том, что если вы используете архитектуру ООП, вы не можете использовать контейнер для большого количества инъекций. Если вы начнете использовать сервисы без сохранения состояния и разделите код на объекты данных и сервисы, вы можете много использовать Spring. Но я не за это. Я думаю, что объекты с полным состоянием все еще правят (это мое мнение). Сборка мусора я понимаю, объект синглтон, проблем не будет. Небольшой прирост памяти практически незаметен. Проблема все еще остается - вы не можете разрезать код на видимый архитектурный код. - person pfh; 14.05.2012
comment
OK для компонента с отслеживанием состояния и встроенными бизнес-данными. Но как справиться с параллелизмом или многопользовательским доступом, если это всего лишь синглтон. Будете ли вы использовать локальные переменные потока внутри синглтона? Вы перейдете на заводской шаблон? Искренне концепции JavaEE были разработаны на основе шаблонов, чтобы быть потокобезопасными и масштабируемыми. Spring был разработан для более легкого использования тех же шаблонов, но цель остается: параллелизм для повышения производительности. - person Yves Martin; 14.05.2012
comment
Заставьте это работать, затем оптимизируйте. Цель состоит не в том, чтобы иметь дело с параллелизмом прямо сейчас, идея заключалась в том, чтобы придумать способ использования контейнера в динамической среде. Работа с классами с полным состоянием по-прежнему является проблемой при использовании в приложении какого-либо контейнера. Отложив это в сторону, ваши идеи, как справиться с этим, довольно хороши. И объективный параллелизм для производительности на самом деле не новинка. Итак, да, вы можете заставить его работать, используя синглтон для каждого пользователя (вы можете возразить, что это не будет синглтоном). Но достичь действительно великого контейнера означало бы сделать его динамичным. - person pfh; 15.05.2012
comment
Заставьте это работать, а затем оптимизация приводит к результату только в том случае, если первоначальные архитектурные концепции достаточно хороши, чтобы можно было оптимизировать без полной перезаписи. Я считаю, что дизайн на основе состояния требует гораздо больше работы для распараллеливания, чтобы избежать сложных для диагностики и еще более сложных для устранения проблем параллелизма. Я почти уверен, что синглтон для каждого пользователя может быть реализован с многопользовательской поддержкой Spring. Попробуйте так. - person Yves Martin; 15.05.2012

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

person dough    schedule 10.05.2012
comment
Правильный. Но проблема в том, что контейнер не знает, что это за объекты во время выполнения. Если у вас есть файл и вы ожидаете, что пользователь выберет его, вы не сможете статически предопределить все возможные комбинации. Идея хороша, но решается динамическая часть (используя список как глобальный компонент). Настоящая проблема заключается в том, как создать экземпляр объекта, КОГДА пользователь действует (например, нажимает кнопку), зная, что у вас есть инициализация в вашем методе. Мне нужна какая-то ленивая инициализация, но я не хочу жертвовать чистотой кода с помощью фабрик или методов инициализации в моем основном методе. - person pfh; 10.05.2012