Anotasi Spring @Import

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan belajar bagaimana menggunakan anotasi Spring @Import sambil menjelaskan bagaimana ia berbeza dengan @ ComponentScan .

2. Konfigurasi dan Kacang

Sebelum memahami anotasi @Import , kita perlu mengetahui apa itu Spring Bean dan mempunyai pengetahuan asas mengenai anotasi @ Konfigurasi .

Kedua-dua topik tersebut berada di luar skop tutorial ini. Namun, kita dapat mengetahui tentangnya dalam artikel Spring Bean dan dokumentasi Spring.

Mari kita anggap bahawa kita sudah menyediakan tiga biji - Burung , Kucing , dan Anjing - masing-masing dengan kelas konfigurasi tersendiri.

Kemudian, kami dapat menyediakan konteks kami dengan kelas Config ini :

@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { BirdConfig.class, CatConfig.class, DogConfig.class }) class ConfigUnitTest { @Autowired ApplicationContext context; @Test void givenImportedBeans_whenGettingEach_shallFindIt() { assertThatBeanExists("dog", Dog.class); assertThatBeanExists("cat", Cat.class); assertThatBeanExists("bird", Bird.class); } private void assertThatBeanExists(String beanName, Class beanClass) { Assertions.assertTrue(context.containsBean(beanName)); Assertions.assertNotNull(context.getBean(beanClass)); } }

3. Konfigurasi Pengumpulan dengan @Import

Tidak ada masalah dalam menyatakan semua konfigurasi. Tetapi bayangkan masalah untuk mengendalikan puluhan kelas konfigurasi dalam sumber yang berbeza . Harus ada jalan yang lebih baik.

Anotasi @ Import mempunyai penyelesaian, berdasarkan kemampuannya untuk mengumpulkan kelas Konfigurasi :

@Configuration @Import({ DogConfig.class, CatConfig.class }) class MammalConfiguration { }

Sekarang, kita hanya perlu ingat mamalia :

@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { MammalConfiguration.class }) class ConfigUnitTest { @Autowired ApplicationContext context; @Test void givenImportedBeans_whenGettingEach_shallFindOnlyTheImportedBeans() { assertThatBeanExists("dog", Dog.class); assertThatBeanExists("cat", Cat.class); Assertions.assertFalse(context.containsBean("bird")); } private void assertThatBeanExists(String beanName, Class beanClass) { Assertions.assertTrue(context.containsBean(beanName)); Assertions.assertNotNull(context.getBean(beanClass)); } }

Baiklah, mungkin kita akan melupakan Burung kita tidak lama lagi, jadi mari kita buat satu kumpulan lagi untuk memasukkan semua kelas konfigurasi haiwan :

@Configuration @Import({ MammalConfiguration.class, BirdConfig.class }) class AnimalConfiguration { }

Akhirnya, tidak ada yang tertinggal, dan kita hanya perlu ingat satu kelas:

@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { AnimalConfiguration.class }) class AnimalConfigUnitTest { // same test validating that all beans are available in the context }

4. @Import vs @ComponentScan

Sebelum meneruskan contoh @ Import , mari berhenti sebentar dan bandingkan dengan @ ComponentScan .

4.1. Kesamaan

Kedua-dua anotasi boleh menerima apa-apa @Component atau @Configuration kelas.

Mari tambah @ Komponen baru menggunakan @ Import :

@Configuration @Import(Bug.class) class BugConfig { } @Component(value = "bug") class Bug { }

Sekarang, kacang Bug tersedia sama seperti kacang lain.

4.2. Perbezaan Konseptual

Secara sederhana, kita dapat mencapai hasil yang sama dengan kedua-dua anotasi . Jadi, adakah perbezaan antara mereka?

Untuk menjawab soalan ini, mari kita ingat bahawa Spring umumnya mempromosikan pendekatan konvensyen-over-konfigurasi.

Membuat analogi dengan anotasi kami, @ ComponentScan lebih seperti konvensyen, sementara @ Import kelihatan seperti konfigurasi .

4.3. Apa yang Berlaku dalam Aplikasi Sebenar

Biasanya, kami memulakan aplikasi kami menggunakan @ ComponentScan dalam pakej root sehingga dapat mencari semua komponen untuk kami. Sekiranya kami menggunakan Spring Boot, maka @SpringBootApplication sudah termasuk @ComponentScan , dan kami sudah bersedia . Ini menunjukkan kekuatan konvensyen.

Sekarang, mari kita bayangkan bahawa aplikasi kita berkembang dengan banyak. Sekarang kita perlu berurusan dengan kacang dari semua tempat yang berbeza, seperti komponen, struktur pakej yang berbeza, dan modul yang dibina oleh diri kita sendiri dan pihak ketiga.

Dalam kes ini, menambahkan semua ke dalam konteks berisiko memulakan konflik mengenai kacang mana yang akan digunakan. Selain itu, kita mungkin mendapat waktu permulaan yang perlahan.

Sebaliknya, kami tidak mahu menulis @ Import untuk setiap komponen baru kerana melakukannya adalah tidak produktif.

Ambil contoh haiwan kita. Kami memang boleh menyembunyikan import dari deklarasi konteks, tetapi kami masih perlu mengingati @ Import untuk setiap kelas Config .

4.4. Bekerjasama

Kita boleh mengejar yang terbaik dari kedua-dua dunia. Mari kita gambarkan bahawa kita mempunyai pakej hanya untuk haiwan kita . Ini juga boleh menjadi komponen atau modul dan menyimpan idea yang sama.

Maka kita dapat memiliki satu @ ComponentScan hanya untuk pakej haiwan kita :

package com.baeldung.importannotation.animal; // imports... @Configuration @ComponentScan public class AnimalScanConfiguration { }

Dan @Import untuk terus mengawal apa yang akan kita tambahkan pada konteks:

package com.baeldung.importannotation.zoo; // imports... @Configuration @Import(AnimalScanConfiguration.class) class ZooApplication { }

Akhirnya, sebarang kacang baru yang ditambahkan pada bungkusan haiwan akan dijumpai secara automatik mengikut konteks kami. Dan kami masih mempunyai kawalan eksplisit terhadap konfigurasi yang kami gunakan.

5. Kesimpulan

Dalam tutorial ringkas ini, kami belajar bagaimana menggunakan @Import untuk mengatur konfigurasi kami.

Kami juga mengetahui bahawa @Import sangat mirip dengan @ ComponentScan , kecuali fakta bahawa @ Import mempunyai pendekatan eksplisit sementara @ ComponentScan menggunakan pendekatan tersirat .

Selain itu, kami melihat kemungkinan kesukaran mengendalikan konfigurasi kami dalam aplikasi sebenar dan bagaimana mengatasinya dengan menggabungkan kedua-dua anotasi.

Seperti biasa, kod lengkap boleh didapati di GitHub.