Panduan untuk Spring @Autowired

1. Ikhtisar

Dimulai dengan Spring 2.5, framework memperkenalkan Injeksi Dependensi yang digerakkan oleh anotasi . Anotasi utama fitur ini adalah @Autowired . Ini memungkinkan Spring untuk menyelesaikan dan menyuntikkan kacang yang berkolaborasi ke dalam kacang kita.

Dalam tutorial ini, pertama kita akan melihat bagaimana mengaktifkan autowiring danberbagaicara untuk melakukan autowire kacang. Setelah itu, kita akan berbicara tentang menyelesaikan konflik kacang menggunakan anotasi @Qualifier , serta skenario pengecualian potensial.

2. Mengaktifkan Anotasi @Autowired

Kerangka Pegas memungkinkan injeksi ketergantungan otomatis. Dengan kata lain, dengan mendeklarasikan semua dependensi kacang dalam file konfigurasi Spring, container Spring dapat melakukan autowire hubungan antara kacang yang berkolaborasi . Ini disebut autowiring kacang musim semi .

Untuk menggunakan konfigurasi berbasis Java dalam aplikasi kita, mari aktifkan injeksi berbasis anotasiuntuk memuat konfigurasi Spring kami:

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

Atau, file anotasi terutama digunakan untuk mengaktifkan anotasi injeksi ketergantungan dalam file XML Spring.

Selain itu, Spring Boot memperkenalkan anotasi @SpringBootApplication . Anotasi tunggal ini setara dengan menggunakan @Configuration , @EnableAutoConfiguration , dan @ComponentScan .

Mari gunakan anotasi 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 otomatis akan memindai komponen-komponen yang ada di paket saat ini dan sub-paketnya . Jadi itu akan mendaftarkan mereka dalam Konteks Aplikasi Spring, dan memungkinkan kita untuk menyuntikkan kacang menggunakan @Autowired .

3. Menggunakan @Autowired

Setelah mengaktifkan injeksi anotasi, kita dapat menggunakan autowiring pada properti, penyetel, dan konstruktor .

3.1. @Autowired pada Properties

Mari kita lihat bagaimana kita dapat membuat anotasi properti menggunakan @Autowired . Ini menghilangkan kebutuhan akan getter dan setter.

Pertama, mari kita definisikan kacang fooFormatter :

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

Kemudian, kami akan menyuntikkan kacang ini ke dalam FooService kacang menggunakan @ Autowired pada definisi bidang:

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

Akibatnya, Spring memasukkan fooFormatter saat FooService dibuat.

3.2. @Autowired pada Setter

Sekarang mari kita coba menambahkan anotasi @Autowired pada metode penyetel.

Dalam contoh berikut, metode penyetel dipanggil dengan instance FooFormatter saat FooService dibuat:

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

3.3. @Autowired pada Konstruktor

Terakhir, mari gunakan @Autowired pada konstruktor.

Kita akan melihat bahwa sebuah instance FooFormatter dimasukkan oleh Spring sebagai argumen ke konstruktor FooService :

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

4. @ Dependensi Kemudahan dan Opsional

Saat kacang sedang dibuat, dependensi @Autowired harus tersedia. Jika tidak, jika Spring tidak dapat menyelesaikan kacang untuk kabel, itu akan menimbulkan pengecualian .

Akibatnya, ini mencegah penampung Spring berhasil diluncurkan dengan pengecualian dalam 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 mendeklarasikan bean dari tipe yang dibutuhkan:

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

5. Disambiguasi Autowire

Secara default, Spring menyelesaikan entri @Autowired menurut jenis. Jika lebih dari satu kacang dengan tipe yang sama tersedia di wadah, kerangka kerja akan mengeluarkan pengecualian yang fatal .

Untuk menyelesaikan konflik ini, kita perlu memberi tahu Spring secara eksplisit kacang mana yang ingin kita masukkan.

5.1. Autowiring oleh @Qualifier

Sebagai contoh, mari kita lihat bagaimana kita dapat menggunakan anotasi @Qualifier untuk menunjukkan kacang yang dibutuhkan.

Pertama, kami akan menentukan 2 biji tipe 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 coba untuk memasukkan kacang Formatter ke dalam 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.