@Lookup Anotasi di Musim Semi

1. Perkenalan

Dalam tutorial singkat ini, kita akan melihat dukungan injeksi ketergantungan tingkat metode Spring, melalui anotasi @Lookup .

2. Mengapa @Lookup ?

Metode yang dianotasi dengan @Lookup memberi tahu Spring untuk mengembalikan instance dari tipe kembalian metode saat kita memanggilnya.

Pada dasarnya, Spring akan menimpa metode beranotasi kami dan menggunakan jenis dan parameter kembalian metode kami sebagai argumen ke BeanFactory # getBean.

@Lookup berguna untuk:

  • Menyuntikkan kacang bercakupan prototipe ke dalam kacang tunggal (mirip dengan Penyedia )
  • Menyuntikkan dependensi secara prosedural

Perhatikan juga bahwa @Lookup adalah Java yang setara dengan metode pencarian elemen XML .

3. Menggunakan @Lookup

3.1. Memasukkan Bean dengan cakupan prototipe ke dalam Kacang Singleton

Jika kita kebetulan memutuskan untuk memiliki prototipe kacang musim semi, maka kita akan segera dihadapkan pada masalah bagaimana kacang musim semi tunggal kita mengakses prototipe kacang musim semi ini?

Sekarang, Penyedia jelas merupakan salah satu cara, meskipun @Lookup lebih fleksibel dalam beberapa hal.

Pertama, mari buat prototipe kacang yang nantinya akan kita masukkan ke dalam kacang tunggal:

@Component @Scope("prototype") public class SchoolNotification { // ... prototype-scoped state }

Dan jika kita membuat kacang tunggal yang menggunakan @Lookup :

@Component public class StudentServices { // ... member variables, etc. @Lookup public SchoolNotification getNotification() { return null; } // ... getters and setters }

Dengan menggunakan @Lookup , kita bisa mendapatkan instance SchoolNotification melalui kacang tunggal kita:

@Test public void whenLookupMethodCalled_thenNewInstanceReturned() { // ... initialize context StudentServices first = this.context.getBean(StudentServices.class); StudentServices second = this.context.getBean(StudentServices.class); assertEquals(first, second); assertNotEquals(first.getNotification(), second.getNotification()); }

Perhatikan bahwa di StudentServices , kami meninggalkan metode getNotification sebagai stub.

Ini karena Spring mengganti metode dengan panggilan ke beanFactory.getBean (StudentNotification.class) , jadi kita bisa membiarkannya kosong.

3.2. Menyuntikkan Ketergantungan Secara Prosedur

Namun, yang lebih hebat lagi adalah @Lookup memungkinkan kita memasukkan dependensi secara prosedural, sesuatu yang tidak dapat kita lakukan dengan Provider .

Mari tingkatkan StudentNotification dengan beberapa status:

@Component @Scope("prototype") public class SchoolNotification { @Autowired Grader grader; private String name; private Collection marks; public SchoolNotification(String name) { // ... set fields } // ... getters and setters public String addMark(Integer mark) { this.marks.add(mark); return this.grader.grade(this.marks); } }

Sekarang, itu tergantung pada beberapa konteks Spring dan juga konteks tambahan yang akan kami berikan secara prosedural.

Kami kemudian dapat menambahkan metode ke StudentServices yang mengambil data siswa dan menyimpannya:

public abstract class StudentServices { private Map notes = new HashMap(); @Lookup protected abstract SchoolNotification getNotification(String name); public String appendMark(String name, Integer mark) { SchoolNotification notification = notes.computeIfAbsent(name, exists -> getNotification(name))); return notification.addMark(mark); } } 

Saat runtime, Spring akan mengimplementasikan metode dengan cara yang sama, dengan beberapa trik tambahan.

Pertama, perhatikan bahwa ia dapat memanggil konstruktor kompleks serta menyuntikkan kacang Spring lainnya, memungkinkan kita memperlakukan SchoolNotification sedikit lebih seperti metode sadar-Spring.

Ini dilakukan dengan mengimplementasikan getSchoolNotification dengan panggilan ke beanFactory.getBean (SchoolNotification.class, name) .

Kedua, terkadang kita dapat membuat metode beranotasi @ Lookup- abstrak, seperti contoh di atas.

Menggunakan abstrak sedikit lebih bagus daripada sebuah rintisan, tetapi kita hanya dapat menggunakannya ketika kita tidak memindai komponen atau @Bean -mengelola kacang di sekitarnya:

@Test public void whenAbstractGetterMethodInjects_thenNewInstanceReturned() { // ... initialize context StudentServices services = context.getBean(StudentServices.class); assertEquals("PASS", services.appendMark("Alex", 89)); assertEquals("FAIL", services.appendMark("Bethany", 78)); assertEquals("PASS", services.appendMark("Claire", 96)); }

Dengan penyiapan ini, kita dapat menambahkan dependensi Spring serta dependensi metode ke SchoolNotification .

4. Batasan

Terlepas dari keserbagunaan @Lookup , ada beberapa batasan penting:

  • Metode @Lookup -annotated, seperti getNotification, harus konkret ketika kelas di sekitarnya, seperti Student, dipindai komponennya. Ini karena pemindaian komponen melewatkan kacang abstrak.
  • @ Lookup- metode beranotasi tidak akan berfungsi sama sekali saat kelas di sekitarnya adalah @Bean -managed .

Dalam keadaan seperti itu, jika kita perlu memasukkan prototipe bean ke dalam singleton, kita dapat melihat Provider sebagai alternatif.

5. Kesimpulan

Dalam artikel singkat ini, kami mempelajari bagaimana dan kapan menggunakan anotasi @Lookup Spring , termasuk bagaimana menggunakannya untuk memasukkan kacang bercakupan prototipe ke dalam kacang tunggal dan bagaimana menggunakannya untuk menyuntikkan dependensi secara prosedural.

Semua kode yang digunakan untuk tutorial ini dapat ditemukan di Github.