Przewodnik po wiośnie @Autowired

1. Przegląd

Począwszy od Spring 2.5, framework wprowadził Dependency Injection oparty na adnotacjach . Główna adnotacja dotycząca tej funkcji to @Autowired . Pozwala Springowi na rozwiązanie i wstrzyknięcie współpracujących ziaren do naszej fasoli.

W tym samouczku najpierw przyjrzymy się, jak włączyć automatyczne okablowanie iróżnysposoby na autowire fasoli. Później porozmawiamy o rozwiązywaniu konfliktów bean za pomocą adnotacji @Qualifier , a także o potencjalnych scenariuszach wyjątków.

2. Włączanie adnotacji @Autowired

Struktura Spring umożliwia automatyczne wstrzykiwanie zależności. Innymi słowy, deklarując wszystkie zależności komponentów bean w pliku konfiguracyjnym Spring, kontener Spring może automatycznie łączyć relacje między współpracującymi komponentami bean . Nazywa się to autoprzewodowaniem fasoli wiosennej .

Aby korzystać z konfiguracji opartej na języku Java w naszej aplikacji, włączmy wstrzykiwanie oparte na adnotacjachaby załadować naszą konfigurację Spring:

@Configuration @ComponentScan("com.baeldung.autowire.sample") public class AppConfig {}

Alternatywnie, plik adnotacja służy głównie do aktywowania adnotacji wstrzykiwania zależności w plikach Spring XML.

Ponadto Spring Boot wprowadza adnotację @SpringBootApplication . Ta pojedyncza adnotacja jest równoważna użyciu @Configuration , @EnableAutoConfiguration i @ComponentScan .

Użyjmy tej adnotacji w głównej klasie aplikacji:

@SpringBootApplication class VehicleFactoryApplication { public static void main(String[] args) { SpringApplication.run(VehicleFactoryApplication.class, args); } }

W rezultacie, gdy uruchamiamy tę aplikację Spring Boot, automatycznie skanuje ona komponenty w bieżącym pakiecie i jego pod-pakietach . W ten sposób zarejestruje je w kontekście aplikacji Springa i pozwoli nam wstrzykiwać ziarna za pomocą @Autowired .

3. Używanie @Autowired

Po włączeniu wstrzykiwania adnotacji możemy użyć autowiring we właściwościach, ustawiaczach i konstruktorach .

3.1. @Autowired we właściwościach

Zobaczmy, jak możemy dodać adnotację do właściwości za pomocą @Autowired . Eliminuje to potrzebę stosowania metod pobierających i ustawiających.

Najpierw zdefiniujmy bean fooFormatter :

@Component("fooFormatter") public class FooFormatter { public String format() { return "foo"; } }

Następnie będziemy wstrzykiwać tej fasoli do FooService fasoli używając @Autowired na definicji pola:

@Component public class FooService { @Autowired private FooFormatter fooFormatter; }

W rezultacie Spring wstrzykuje fooFormatter podczas tworzenia FooService .

3.2. @Autowired na Setters

Teraz spróbujmy dodać adnotację @Autowired do metody ustawiającej.

W poniższym przykładzie metoda ustawiająca jest wywoływana z instancją FooFormatter podczas tworzenia FooService :

public class FooService { private FooFormatter fooFormatter; @Autowired public void setFooFormatter(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } } 

3.3. @Autowired on Constructors

Na koniec użyjmy @Autowired na konstruktorze.

Zobaczymy, że Spring wstrzykuje instancję FooFormatter jako argument do konstruktora FooService :

public class FooService { private FooFormatter fooFormatter; @Autowired public FooService(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } }

4. Zależności @autowired i opcjonalne

Podczas konstruowania fasoli powinny być dostępne zależności @Autowired . W przeciwnym razie, jeśli Spring nie może rozwiązać fasoli dla okablowania, zgłosi wyjątek .

W związku z tym uniemożliwia pomyślne uruchomienie kontenera Spring za wyjątkiem postaci:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.autowire.sample.FooDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Aby to naprawić, musimy zadeklarować ziarno wymaganego typu:

public class FooService { @Autowired(required = false) private FooDAO dataAccessor; }

5. Ujednoznacznienie Autowire

Domyślnie Spring rozwiązuje wpisy @Autowired według typu. Jeśli w kontenerze jest dostępnych więcej niż jeden komponent bean tego samego typu, platforma zgłosi wyjątek krytyczny .

Aby rozwiązać ten konflikt, musimy wyraźnie powiedzieć Springowi, którą fasolę chcemy wstrzyknąć.

5.1. Autowiring przez @Qualifier

Na przykład zobaczmy, jak możemy użyć adnotacji @Qualifier do wskazania wymaganego ziarna.

Najpierw zdefiniujemy 2 ziarna typu Formatter :

@Component("fooFormatter") public class FooFormatter implements Formatter { public String format() { return "foo"; } }
@Component("barFormatter") public class BarFormatter implements Formatter { public String format() { return "bar"; } }

Teraz spróbujmy wstrzyknąć komponent bean Formatter do klasy FooService :

public class FooService { @Autowired private Formatter formatter; }

W naszym przykładzie są dostępne dwie konkretne implementacje programu Formatter dla kontenera Spring. W rezultacie Spring zgłosi wyjątek NoUniqueBeanDefinitionException podczas konstruowania FooService :

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.autowire.sample.Formatter] is defined: expected single matching bean but found 2: barFormatter,fooFormatter 

Możemy tego uniknąć, zawężając implementację za pomocą adnotacji @Qualifier :

public class FooService { @Autowired @Qualifier("fooFormatter") private Formatter formatter; }

Gdy istnieje wiele ziaren tego samego typu, dobrym pomysłem jest użycie @Qualifier, aby uniknąć niejednoznaczności.

Należy pamiętać, że wartość @Qualifier meczów adnotacji o nazwie zadeklarowane w @Component adnotacją naszego FooFormatter realizacji.

5.2. Automatyczne okablowanie przez kwalifikator niestandardowy

Spring pozwala nam również tworzyć własne, niestandardowe adnotacje @Qualifier . Aby to zrobić, powinniśmy podać adnotację @Qualifier z definicją:

@Qualifier @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface FormatterType { String value(); }

Następnie możemy użyć elementu FormatterType w różnych implementacjach, aby określić wartość niestandardową:

@FormatterType("Foo") @Component public class FooFormatter implements Formatter { public String format() { return "foo"; } }
@FormatterType("Bar") @Component public class BarFormatter implements Formatter { public String format() { return "bar"; } }

Wreszcie, nasza niestandardowa adnotacja kwalifikatora jest gotowa do użycia do automatycznego okablowania:

@Component public class FooService { @Autowired @FormatterType("Foo") private Formatter formatter; } 

Wartość określona w meta-adnotacji @Target ogranicza miejsce zastosowania kwalifikatora, którym w naszym przykładzie są pola, metody, typy i parametry.

5.3. Automatyczne okablowanie według nazwy

Spring używa nazwy fasoli jako domyślnej wartości kwalifikatora. Sprawdza pojemnik i szuka ziarna o dokładnej nazwie jako właściwości do automatycznego połączenia.

Dlatego w naszym przykładzie Spring dopasowuje nazwę właściwości fooFormatter do implementacji FooFormatter . Dlatego podczas konstruowania FooService wprowadza tę konkretną implementację :

public class FooService { @Autowired private Formatter fooFormatter; }

6. Wniosek

W tym artykule omówiliśmy autoprzewodowanie i różne sposoby jego wykorzystania. Przeanalizowaliśmy również sposoby rozwiązania dwóch typowych wyjątków automatycznego okablowania spowodowanych brakiem fasoli lub niejednoznacznym wstrzyknięciem ziarna.

Kod źródłowy tego artykułu jest dostępny w projekcie GitHub.