Spring @Autowire on Properties vs Constructor

Więc skoro używam Springa, gdybym miał napisać usługę, która ma zależności, wykonałbym następujące czynności:

@Component
public class SomeService {
     @Autowired private SomeOtherService someOtherService;
}

Natknąłem się teraz na kod, który używa innej konwencji, aby osiągnąć ten sam cel

@Component
public class SomeService {
    private final SomeOtherService someOtherService;

    @Autowired
    public SomeService(SomeOtherService someOtherService){
        this.someOtherService = someOtherService;
    }
}
Rozumiem, że obie te metody zadziałają. Ale czy jest jakaś zaleta korzystania z opcji B? Dla mnie tworzy więcej kodu w klasie i teście jednostkowym. (Konieczność napisania konstruktora i brak możliwości użycia @InjectMocks)

Is there something I ' m zaginęła? Czy jest coś jeszcze, co konstruktor autowired robi poza dodaniem kodu do testów jednostkowych? Czy jest to bardziej preferowany sposób wstrzykiwania zależności?

Author: moffeltje, 2016-11-16

3 answers

Tak, Opcja B (zwana injekcją konstruktora) jest w rzeczywistości zalecana zamiast injekcji w terenie i ma kilka zalet:

  • zależności są wyraźnie określone. Nie ma sposobu, aby o niej zapomnieć podczas testowania lub tworzenia instancji obiektu w innych okolicznościach (jak tworzenie instancji bean jawnie w klasie config)
  • zależności mogą być ostateczne, co pomaga w solidności i bezpieczeństwie nici
  • nie potrzebujesz refleksji, aby ustawić zależności. InjectMocks jest nadal użyteczny, ale nie jest konieczny. Możesz po prostu tworzyć mocki samodzielnie i wstrzykiwać je, po prostu wywołując konstruktor
[[0]}Zobacz ten wpis na bloguaby uzyskać bardziej szczegółowy artykuł, autorstwa jednego z wiosennych współpracowników, Oliviera Gierke.
 69
Author: JB Nizet,
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
2018-02-28 20:44:40

Wyjaśnię Ci prostymi słowami:

W Option (a), pozwalasz każdemu (w innej klasie poza / wewnątrz kontenera Spring) na tworzenie instancji za pomocą domyślnego konstruktora (jak new SomeService()), co nie jest dobre, ponieważ potrzebujesz SomeOtherService obiektu (jako zależności) dla twojego SomeService.

Czy jest coś jeszcze, co konstruktor autowired robi poza dodaniem kodu do testów jednostkowych? Czy jest to bardziej preferowany sposób na uzależnienie zastrzyk?

Opcja (B) jest preferowanym podejściem, ponieważ nie pozwala na tworzenie obiektu SomeService bez faktycznego rozwiązania zależności SomeOtherService.

 13
Author: developer,
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
2018-05-23 16:09:39

Autowired constructors zapewnia hook, aby dodać własny kod przed zarejestrowaniem go w kontenerze spring. Załóżmy, że klasa SomeService rozszerza inną klasę o nazwie SuperSomeService i ma jakiś konstruktor, który przyjmuje nazwę jako swój argument. W tym przypadku konstruktor Autowired działa poprawnie. Ponadto, jeśli masz inne elementy do zainicjowania, możesz to zrobić w konstruktorze przed zwróceniem instancji do kontenera spring.

public class SuperSomeService {
     private String name;
     public SuperSomeService(String name) {
         this.name = name;
     }
}

@Component
public class SomeService extends SuperSomeService {
    private final SomeOtherService someOtherService;
    private Map<String, String> props = null;

    @Autowired
    public SomeService(SomeOtherService someOtherService){
        SuperSomeService("SomeService")
        this.someOtherService = someOtherService;
        props = loadMap();
    }
}
 1
Author: PebblePicker,
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-11-29 09:08:05