2012-05-03 15 views
15

Kontynuacja z Dependency injection, delayed injection praxis. Mam główną klasę:Dynamiczny wtrysk wiosenny, fabrycznie podobny wzór

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(); 
    } 
} 

Wykres obiektu jest dynamicznie tworzony, w zależności od interakcji użytkownika. Rozwiązałem sprzężenie aplikacji, co pozwoliło mi to przetestować bardzo prosto. Ponadto, ponieważ listy są obsługiwane przez kontener, dynamiczny charakter tej aplikacji (i wszystkich innych) jest nieistotny, ponieważ mogą one być wymagane w dowolnym momencie, gdy aplikacja ich potrzebuje, zachowując ich elementy.

Reszta kodu jest tutaj:

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; 
    } 
} 

Czy ktoś wie w jaki sposób mogę rozwiązać ten createList metoda call() lub createSecondList() - bez użycia konstruktora które dość dużo siły projektu. Myślałem o fabryce, ale fabryka dla każdej klasy w projekcie o większej skali nie wydaje się dobrym pomysłem.

Coś jak:

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

A w sposobie fabrycznego instancję klasy i wywołać metodę createList(). Albo tak to nazwij, z jakiejś metody - która znowu wygląda źle, zmuszając metodę do ponoszenia odpowiedzialności za utworzenie wykresu obiektu.

obrazem zależności runtime, że chcę rozwiązać w czasie wykonywania jest poniżej:

enter image description here

Czy istnieje jakiś inny sposób mógłbym wykorzystać pojemnik do achive dynamiczny leniwy initalization zależności od interakcji z użytkownikiem ?

Dziękuję.

+1

Nie mam pojęcia, o co pytasz. Co masz na myśli przez "_solve_ wywołanie metody createList() lub createSecondList()"? Jeśli mam rację w moim przypuszczeniu, co próbujesz zrobić (i wątpię w to), utworzę klasę fabryczną, która ma (statyczną?) Metodę fabryczną, która pobiera argument interaktywny i tworzy odpowiednią listę, a następnie wstrzykuje obiekt fabryczny tej klasy do twojego głównego obiektu. –

+0

Myślałem, że zrozumiesz z kontekstu. Nie jest świetnym pisarzem pytań. Tak, coś takiego. Pytanie jest pogrubione. Poza fabryką (statyczną, oczywiście) i za pomocą ciągnięcia/inicjalizacji obiektów (z inicjalizacją w klasie Main, metodą "główną"), jak mogę skonstruować wykres obiektów dynamicznych, żeby nie musieć się martwić o kod architektury " "w mojej aplikacji. Dlaczego miałbyś wstrzyknąć obiekt fabryczny w swój główny obiekt? Będziesz miał dużo pracy, jeśli wszystkie zajęcia będą dynamiczne. Ponieważ powinieneś mieć fabrykę na każdej dynamicznej klasie. Nadal uważam, że istnieje prostsze rozwiązanie :) – pfh

Odpowiedz

10

Jeśli chcesz, aby jakiś członek twojej klasy był dynamicznie inicjowany \ wypełniany podczas każdego połączenia z odpowiednim programem pobierającym, możesz wypróbować metodę wyszukiwania wtrysku. Przeczytaj pp. 3.3.4.1here.

Tak więc nawet jeśli klasa zawierająca element dynamiczny została utworzona w scope=singletone (domyślna dla kontenera z komponentem sprężynowym) za każdym razem, gdy przejdziesz do pola, które ma przypisaną metodę wyszukiwania, otrzymasz odpowiedni obiekt zgodnie z logiką biznesową zaimplementowane wewnątrz metody wyszukiwania. W twoim przypadku lista jest interfejsem, dzięki czemu możesz łatwo zaimplementować sprawdzanie poprawności w swojej metodzie wyszukiwania i zwrócić zweryfikowaną listę.

Edit:

znalazłem lepsze example w dokumentacji Spring - Myślę, że to jest bardzo jasne. Spójrz na „3.4.6.1 Lookup metodą wtrysku”

Po skonfigurowaniu klasa Main przypisać metodę odnośnika do swojej List członka - będzie się nazywać, gdy trzeba nową instancję List fasoli.

Powodzenia!

+0

To dobry pomysł, ale przeniesienie fabryki do metody nie wydaje się rozwiązać kodu arhictecture. Ponadto zwiększa złożoność. Nagle metoda musi zwrócić wymagany typ. A potem mam N metod, gdy wymagam typów N. Czy patrzę na to źle? Wiosna nie ma czegoś takiego jak @AssistedInject (http://code.google.com/p/google-guice/wiki/AssistedInject, https://jira.springsource.org/browse/SPR-5192)? Zwykle robisz coś takiego, jeśli masz "dynamiczną" aplikację? To wydaje się być obszarem, którego doświadczeni programiści nie odwiedzają tak często ... – pfh

+0

Myślę, że wystarczy jedna metoda wyszukiwania (upewnij się, że nie przegapiłeś tego punktu) :) metoda wyszukiwania zwróci obiekt, który implementuje niektóre wspólne interfejs (lista?), a nawet interfejs znacznika. Decyzja, jaki konkretnie typ obiektu może zostać wywołana przez metodę wyszukiwania, może być oparta na pewnym zewnętrznym źródle (plik konfiguracyjny, dane wejściowe użytkownika itp.), Ale wszystkie możliwe typy muszą być wcześniej znane. – aviad

+0

Staram się nie pomijać punktu, ale wygląda na to, że zawodzę. Nie zrozum mnie źle, jestem wdzięczny za odpowiedź. To - http://java.dzone.com/articles/pragmatic-look-method jest bardzo różne od tego, co chcę osiągnąć. Próbuję spojrzeć na to ze wszystkich stron, o których myślę ... Może spróbujesz zrobić przykład i zademonstrować to? Tak, mogę używać interfejsu znacznika.Ale wtedy "muszę" rozwiązać zależność runtime. A "metoda iniekcji" tak naprawdę nie rozwiązuje tego problemu. Jak mogę utworzyć instancję różnych obiektów w zależności od środowiska wykonawczego? Zaktualizowałem moje pytanie, abyś mógł mieć inne spojrzenie. – pfh

2

Brzmi jak użytkownik może wybrać 1 ..N wykresów obiektów i chcesz tylko załadować ten, który wybierze użytkownik w czasie wykonywania. Jeśli wykresy są znane w czasie projektowania, ale użytkownik wybiera właśnie ten, który chce, to brzmi dla mnie tak, jak to, co masz, to mnóstwo kontekstów aplikacji i chcesz tylko załadować jeden kontekst aplikacji wybrany przez użytkownika w czasie wykonywania. Dlaczego więc nie wystarczy zdefiniować zestaw ApplicationContexts, a następnie po prostu utworzyć odpowiedni w środowisku wykonawczym. Ponieważ Spring obsługuje Java Config, może być sens zdefiniowanie tych konfiguracji jako klas Java, aby można było dziedziczyć i unikać przecinania/wklejania dowolnego kodu.

+0

Prawidłowo. Problem polega jednak na tym, że kontener "nie wie", jakie obiekty znajdują się w czasie wykonywania. Jeśli masz plik i oczekujesz, że użytkownik go wybierze, nie możesz tak naprawdę wstępnie zdefiniować wszystkich możliwych kombinacji. Pomysł jest dobry, ale część dynamiczna jest rozwiązana (używając listy jako "globalnej" fasoli). Prawdziwy problem polega na tym, jak utworzyć instancję obiektu, gdy użytkownik działa (np. Kliknij przycisk), wiedząc, że masz inicjalizację w swojej metodzie. Potrzebuję jakiejś leniwej inicjalizacji, ale nie chcę rezygnować z czystej czystości kodu przy użyciu fabryk lub metod inicjalizacji w mojej głównej metodzie. – pfh

3

Sprężyna przeznaczona jest do wtrysku komponentów wielokrotnego użytku, nie do manipulacji danymi biznesowymi i wtryskiem.

Rzeczywiście niektóre dane są używane w zastrzyku zależności, ale tylko do konfigurowania zachowania składników, a nie do tworzenia firmowego właściciela danych.

Nawiasem mówiąc, poniższa opcja może być użyta w tym przypadku: dziękuję BeanFactory z BeanFactoryAware interface i wykorzystanie zakresu = „prototyp”, można wygenerować fasoli powołując getBean() jak w that example lub that other question: creating bean on demand.

Alternatywnym rozwiązaniem, jeśli masz ograniczoną liczbę ziaren, aby przygotować się do zastosowania ogólnego Creation Bean the same way lacking beans are mocked

Teraz uważają, że wiosna nigdy śmieci zbiera ziarna w jego kontekście. W związku z tym, że zużycie pamięci jest bardzo ryzykowne, tworzenie fasoli Spring umożliwia przechowywanie danych biznesowych.

Jeśli twój cel jest inny (mam taką nadzieję), być może próbujesz wdrożyć własne wsparcie dla wielu dzierżawców. Wiosna zapewnia dzierżawę w przypadku, gdy masz inny kontekst biznesowy do wdrożenia z określonymi komponentami lub zachowaniami.

+0

Nie, ja po raz kolejny próbowałem połączyć dane biznesowe i architekturę. Problem polega na tym, że jeśli korzystasz z architektury OOP, nie możesz tak naprawdę używać kontenera do wielu wstrzyknięć. Jeśli zaczniesz korzystać z usług bezpaństwowych i podzielisz kod na obiekty danych i usługi, możesz użyć wiosny. Ale nie jestem za to. Myślę, że stanowe obiekty wciąż rządzą (to mój pogląd). Rozumiem, że zbieranie śmieci, obiekt jest singleton, nie będzie żadnych problemów. Lekki wzrost pamięci jest praktycznie niewidoczny. Problem nadal pozostaje - nie można "przeciąć" kodu kodu wizualizacyjnego. – pfh

+0

OK dla składnika statefull z osadzonymi danymi biznesowymi. Ale jak obsługiwać współbieżność lub dostęp dla wielu użytkowników, jeśli jest to tylko singleton. Czy użyjesz lokalnych zmiennych wątku wewnątrz singletonu? Czy przejdziesz do wzoru fabrycznego? Szczerze mówiąc, koncepcje JavaEE zostały zaprojektowane wokół wzorców, aby były bezpieczne dla wątków i skalowalne. Wiosna została zaprojektowana, aby używać tych samych wzorów w lżejszy sposób, ale obiektywne pozostaje: współbieżność dla wydajności. –

+0

"Niech to zadziała, a następnie zoptymalizuj". Celem nie jest teraz zajmowanie się współbieżnością, ale pomysł polegał na znalezieniu sposobu na wykorzystanie kontenera w dynamicznym środowisku.Radzenie sobie z klasami statefull nadal stanowi problem przy korzystaniu z pewnego rodzaju kontenera w aplikacji. Odkładając to na bok, twoje pomysły na radzenie sobie z tym są całkiem dobre. A cel "współbieżności dla wydajności" nie jest niczym nowym. Tak, tak, możesz sprawić, żeby działało, używając pojedynczego singleta na użytkownika (można by twierdzić, że nie byłoby to singleton). Jednak osiągnięcie naprawdę doskonałego pojemnika oznaczałoby jego dynamikę. – pfh