1. Gambaran keseluruhan
Bermula dengan Spring 2.5, kerangka ini memperkenalkan Dependency Injection yang didorong oleh anotasi . Anotasi utama ciri ini ialah @Autowired . Ia membolehkan Spring menyelesaikan dan menyuntik kacang bekerjasama ke dalam kacang kami.
Dalam tutorial ini, pertama-tama kita akan melihat bagaimana mengaktifkan pendawaian automatik danpelbagaicara untuk mengaut kacang. Selepas itu, kita akan membincangkan penyelesaian konflik kacang menggunakan anotasi @Qualifier , serta senario pengecualian yang berpotensi.
2. Mengaktifkan Anotasi @Autowired
Kerangka Spring membolehkan suntikan kebergantungan automatik. Dengan kata lain, dengan menyatakan semua pergantungan kacang dalam fail konfigurasi Spring, Spring container dapat melancarkan hubungan antara kacang bekerjasama . Ini dipanggil Autowiring kacang musim bunga .
Untuk menggunakan konfigurasi berasaskan Java dalam aplikasi kami, mari aktifkan suntikan berdasarkan anotasiuntuk memuatkan konfigurasi Spring kami:
@Configuration @ComponentScan("com.baeldung.autowire.sample") public class AppConfig {}
Sebagai alternatif, anotasi digunakan terutamanya untuk mengaktifkan anotasi suntikan kebergantungan dalam fail Spring XML.
Lebih-lebih lagi, Spring Boot memperkenalkan anotasi @SpringBootApplication . Anotasi tunggal ini setara dengan menggunakan @Configuration , @EnableAutoConfiguration , dan @ComponentScan .
Mari gunakan penjelasan ini di kelas utama aplikasi:
@SpringBootApplication class VehicleFactoryApplication { public static void main(String[] args) { SpringApplication.run(VehicleFactoryApplication.class, args); } }
Hasilnya, ketika kita menjalankan aplikasi Spring Boot ini, secara automatik akan mengimbas komponen dalam pakej semasa dan sub-paketnya . Oleh itu, ia akan mendaftarkannya dalam Konteks Aplikasi Spring, dan membolehkan kami menyuntik kacang menggunakan @Autowired .
3. Menggunakan @Autowired
Setelah mengaktifkan suntikan anotasi, kami dapat menggunakan pendawaian automatik pada sifat, setter, dan pembina .
3.1. @Dikehendaki pada Hartanah
Mari lihat bagaimana kita dapat memberi anotasi pada harta tanah menggunakan @Autowired . Ini menghilangkan keperluan untuk mendapatkan dan menetapkan.
Pertama, mari kita tentukan kacang fooFormatter :
@Component("fooFormatter") public class FooFormatter { public String format() { return "foo"; } }
Kemudian, kami akan menyuntik kacang ini ke dalam FooService kacang menggunakan @Autowired kepada definisi bidang:
@Component public class FooService { @Autowired private FooFormatter fooFormatter; }
Hasilnya, Spring menyuntikkan fooFormatter ketika FooService dibuat.
3.2. @Dikehendaki pada Setter
Sekarang mari kita cuba menambahkan anotasi @Autowired pada kaedah setter.
Dalam contoh berikut, kaedah setter dipanggil dengan contoh FooFormatter ketika FooService dibuat:
public class FooService { private FooFormatter fooFormatter; @Autowired public void setFooFormatter(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } }
3.3. @Dikehendaki pada Pembina
Akhirnya, mari gunakan @Autowired pada konstruktor.
Kita akan melihat bahawa contoh FooFormatter disuntik oleh Spring sebagai hujah kepada pembangun FooService :
public class FooService { private FooFormatter fooFormatter; @Autowired public FooService(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } }
4. @ Pergantungan Pilihan dan Pilihan
Semasa kacang sedang dibina, kebergantungan @Autowired harus ada. Jika tidak, jika Spring tidak dapat menyelesaikan biji kabel, ia akan membuat pengecualian .
Akibatnya, ia menghalang kontena Spring berjaya dilancarkan dengan pengecualian dari bentuk:
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)}
Untuk memperbaikinya, kita perlu menyatakan biji jenis yang diperlukan:
public class FooService { @Autowired(required = false) private FooDAO dataAccessor; }
5. Disambiguasi Autowire
Secara lalai, Spring menyelesaikan entri @Autowired mengikut jenis. Sekiranya terdapat lebih daripada satu kacang jenis yang sama di dalam bekas, rangka tersebut akan menyebabkan pengecualian yang membawa maut .
Untuk menyelesaikan konflik ini, kita perlu memberi tahu Spring secara terang-terangan kacang mana yang ingin kita suntik.
5.1. Autowiring oleh @Qualifier
Sebagai contoh, mari kita lihat bagaimana kita dapat menggunakan anotasi @Qualifier untuk menunjukkan kacang yang diperlukan.
Pertama, kita akan menentukan 2 biji jenis 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"; } }
Sekarang mari kita cuba memasukkan kacang Formatter ke kelas FooService :
public class FooService { @Autowired private Formatter formatter; }
In our example, there are two concrete implementations of Formatter available for the Spring container. As a result, Spring will throw a NoUniqueBeanDefinitionException exception when constructing the 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
We can avoid this by narrowing the implementation using a @Qualifier annotation:
public class FooService { @Autowired @Qualifier("fooFormatter") private Formatter formatter; }
When there are multiple beans of the same type, it's a good idea to use @Qualifier to avoid ambiguity.
Please note that the value of the @Qualifier annotation matches with the name declared in the @Component annotation of our FooFormatter implementation.
5.2. Autowiring by Custom Qualifier
Spring also allows us to create our own custom @Qualifier annotation. To do so, we should provide the @Qualifier annotation with the definition:
@Qualifier @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface FormatterType { String value(); }
Then we can use the FormatterType within various implementations to specify a custom value:
@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"; } }
Finally, our custom Qualifier annotation is ready to use for autowiring:
@Component public class FooService { @Autowired @FormatterType("Foo") private Formatter formatter; }
The value specified in the @Target meta-annotation restricts where to apply the qualifier, which in our example is fields, methods, types, and parameters.
5.3. Autowiring by Name
Spring uses the bean's name as a default qualifier value. It will inspect the container and look for a bean with the exact name as the property to autowire it.
Hence, in our example, Spring matches the fooFormatter property name to the FooFormatter implementation. Therefore, it injects that specific implementation when constructing FooService:
public class FooService { @Autowired private Formatter fooFormatter; }
6. Conclusion
In this article, we discussed autowiring and the different ways to use it. We also examined ways to solve two common autowiring exceptions caused by either a missing bean or an ambiguous bean injection.
The source code of this article is available on the GitHub project.