Jak prawidłowo wykonać dependency injection (na wiosnę)? [duplikat]

To pytanie ma już odpowiedź tutaj:

  • Setter DI vs. Constructor DI Na Wiosnę? 7 odpowiedzi

Mam wątpliwości co do wstrzykiwania obiektów do klasy za pomocą Springa. Używałem w swoich projektach tego rodzaju kodu:

@Resource // or @Autowired even @Inject
private PersonRepository personRepository;

Następnie używałem go normalnie na metodach jako:

personRepository.save(p);

W przeciwnym razie znalazłem na przykładach Spring, wstrzykując konstruktor:

private final PersonRepository personRepository;

@Autowired
public PersonController(PersonRepository personRepository) {
  this.personRepository = personRepository;
}
Więc oba są poprawne? Lub każdy on ma swoje właściwości i zastosowania?
Author: Oliver Gierke, 2014-06-21

2 answers

Tl; dr-Constructor injection jest najlepszym sposobem na wykonanie DI

Ta ostatnia jest poprawna i dzieje się tak nie tyle ze względu na Spring czy jakikolwiek kontener iniekcji zależności, ale na obiektowe zasady projektowania klas.

Szczegóły

Typ powinien być zaprojektowany tak, aby można było z niego tworzyć tylko instancje, które są w prawidłowym stanie. Aby to osiągnąć, wszystkie obowiązkowe zależności tego typu muszą być argumentami konstruktora. Oznacza to, że zależności te mogą być null - zaznaczone, przypisane do końcowych pól w celu promowania niezmienności. Poza tym, podczas pracy z kodem, dla wywołującego (lub twórcy) danej instancji jest od razu oczywiste, jakie zależności musi dostarczyć (poprzez przeglądanie dokumentów API lub używanie uzupełniania kodu w IDE).

Wszystko to jest niemożliwe z wtryskiem polowym. Nie widzisz zależności z zewnątrz, potrzebujesz czarnej magii, aby wprowadzić zależności i nigdy nie możesz być pewien nie są null, chyba że ślepo ufasz kontenerowi.

[6]}ostatnim, ale nie mniej ważnym aspektem jest to, że przy zastrzykach polowych, mniej bolesne jest dodawanie wielu zależności do klasy, co jest problemem sam w sobie. Z konstruktorami, które stają się znacznie bardziej bolesne, znacznie wcześniej, co jest dobrą rzeczą , ponieważ mówi ci coś o Twoim projekcie klasowym: klasa ma zbyt wiele obowiązków. Nie ma potrzeby, aby obliczyć metryki na nim w pierwszej kolejności, ty poczuj to, gdy próbujesz go rozszerzyć.

Pojemniki

Ludzie często twierdzą, że to tylko akademickie bzdury, ponieważ i tak możesz polegać na kontenerze. Oto moje zdanie na ten temat:

  • Tylko dlatego, że kontener istnieje, nie oznacza to, że musisz wyrzucić wszystkie podstawowe zasady projektowania zorientowanego obiektowo, prawda? Nadal bierzesz prysznic, nawet jeśli antyperspiranty istnieją, prawda?

  • Nawet typy przeznaczone do użytku z pojemnikiem, będzie używany ręcznie: w testach jednostkowych. Jeśli nie piszesz testów jednostkowych ... to już inny temat.

  • Rzekoma słowność dodatkowego konstruktora ("mogę osiągnąć to samo za pomocą pojedynczej linii wtrysku pola!!"- "Nie, Nie możesz. właściwie dostajesz rzeczy z pisania linijki kodu więcej.") mogą być łagodzone przez takie rzeczy jak Lombok . Konstruktor wtryskiwany komponentem ze sprężyną i Lombok wygląda tak:

    @Component
    @RequiredArgsConstructor
    class MyComponent implements MyComponentInterface {
    
      private final @NonNull MyDependency dependency;
    
      …
    }
    

Lombok will zadbaj o wygenerowanie konstruktora pobierającego parametr dla każdego końcowego pola i sprawdź Podany parametr dla null przed przypisaniem go. Dzięki temu uzyskujesz zwięzłość wtrysku pola i zalety konstrukcyjne wtrysku konstruktora.

Epilog

Brałem ostatnio udział w dyskusji z kilkoma osobami spoza Javy, które strasznie mnie zdziwiły, używając terminu "injection" dla konstruktora DI. Skutecznie argumentowali - i jest w tym wiele prawdy - że przechodzenie zależności za pomocą konstruktora nie są w ogóle iniekcjami, ponieważ jest to najbardziej naturalny sposób przekazywania obiektów innym (w przeciwieństwie do iniekcji wszelkiego rodzaju).

Może powinniśmy wymyślić inne określenie dla tego rodzaju stylu? Może karmienie uzależnień?

Zasoby

 71
Author: Oliver Gierke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-01 10:33:20

Z naukowego punktu widzenia zgadzam się, że konstruktory są po prostu lepszym sposobem tworzenia obiektów. Jednak Specyfikacja java beans jest zbudowana na założeniach mutatorów, aby ułatwić refleksję. Zbyt wiele narzędzi i frameworków zostało zbudowanych wokół tego paradygmatu łatwości dostępu. W przypadku usług, DAOs i innych scenariuszy Singletona uważam, że tylko constructor injection powinno być używane, ponieważ mutatory łamią starą zasadę "tylko znajomi mogą zobaczyć Twoje prywatne części".

 2
Author: Ryan McGuinness,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-25 06:50:10