Menyuntikkan Kacang Musim Semi ke Objek Tak Terkelola

1. Kekuatan Penggerak

Dalam aplikasi Spring, menyuntikkan satu biji ke biji lainnya sangat umum. Namun, terkadang diinginkan untuk menyuntikkan kacang ke dalam benda biasa. Misalnya, kita mungkin ingin mendapatkan referensi ke layanan dari dalam objek entitas.

Untungnya, mencapai itu tidak sesulit kelihatannya. Bagian berikut akan menjelaskan cara melakukannya dengan menggunakan penjelasan @Configurable dan penenun AspectJ.

2. Anotasi @Configurable

Anotasi ini memungkinkan instance dari kelas yang didekorasi untuk menyimpan referensi ke kacang musim semi.

2.1. Mendefinisikan dan Mendaftarkan Spring Bean

Sebelum membahas anotasi @Configurable , mari kita buat definisi Spring bean:

@Service public class IdService { private static int count; int generateId() { return ++count; } }

Kelas ini didekorasi dengan anotasi @Service ; karenanya dapat didaftarkan dengan konteks Spring melalui pemindaian komponen.

Berikut kelas konfigurasi sederhana yang mengaktifkan mekanisme itu:

@ComponentScan public class AspectJConfig { }

2.2. Menggunakan @Configurable

Dalam bentuk yang paling sederhana, kita dapat menggunakan @Configurable tanpa elemen apa pun:

@Configurable public class PersonObject { private int id; private String name; public PersonObject(String name) { this.name = name; } // getters and other code shown in the next subsection }

The @Configurable penjelasan, dalam hal ini, menandai PersonObject kelas sebagai memenuhi syarat untuk konfigurasi Spring-driven.

2.3. Menyuntikkan Spring Bean ke dalam Objek Tidak Terkelola

Kita dapat menyuntikkan IdService ke PersonObject , seperti yang kita lakukan di Spring bean:

@Configurable public class PersonObject { @Autowired private IdService idService; // fields, constructor and getters - shown in the previous subsection void generateId() { this.id = idService.generateId(); } }

Namun, anotasi hanya berguna jika dikenali dan diproses oleh penangan. Di sinilah penenun AspectJ berperan. Secara khusus, para AnnotationBeanConfigurerAspect akan bertindak atas kehadiran @Configurable dan melakukan pengolahan diperlukan.

3. Mengaktifkan Tenun AspectJ

3.1. Deklarasi Plugin

Untuk mengaktifkan tenun AspectJ, kita membutuhkan plugin AspectJ Maven terlebih dahulu:

 org.codehaus.mojo aspectj-maven-plugin 1.11  

Dan itu membutuhkan beberapa konfigurasi tambahan:

 1.8 ignore   org.springframework spring-aspects   

Elemen pertama yang diperlukan adalah complianceLevel . Nilai 1,8 menetapkan versi JDK sumber dan target ke 1,8. Jika tidak ditetapkan secara eksplisit, versi sumbernya adalah 1.3 dan targetnya adalah 1.1. Nilai-nilai ini jelas sudah ketinggalan zaman dan tidak cukup untuk aplikasi Java modern.

Untuk memasukkan kacang ke dalam objek yang tidak dikelola, kita harus bergantung pada kelas AnnotationBeanConfigurerAspect yang disediakan di spring-aspect.jar . Karena ini adalah aspek yang telah dikompilasi sebelumnya, kita perlu menambahkan artefak yang memuatnya ke konfigurasi plugin.

Perhatikan bahwa artefak yang direferensikan harus ada sebagai ketergantungan dalam proyek:

 org.springframework spring-aspects 5.2.7.RELEASE 

Kami dapat menemukan versi terbaru dari aspek pegas di Maven Central.

3.2. Eksekusi Plugin

Untuk menginstruksikan plugin untuk menenun semua kelas yang relevan, kita memerlukan konfigurasi eksekusi ini :

   compile   

Perhatikan bahwa tujuan kompilasi plugin mengikat fase siklus hidup kompilasi secara default.

3.2. Konfigurasi Bean

Langkah terakhir untuk mengaktifkan tenun AspectJ adalah menambahkan @EnableSpringConfigured ke kelas konfigurasi:

@ComponentScan @EnableSpringConfigured public class AspectJConfig { }

Anotasi ekstra mengonfigurasi AnnotationBeanConfigurerAspect , yang kemudian mendaftarkan instance PersonObject dengan container Spring IoC .

4. Pengujian

Sekarang, mari verifikasi bahwa kacang IdService telah berhasil dimasukkan ke dalam PersonObject :

@RunWith(SpringRunner.class) @ContextConfiguration(classes = AspectJConfig.class) public class PersonUnitTest { @Test public void givenUnmanagedObjects_whenInjectingIdService_thenIdValueIsCorrectlySet() { PersonObject personObject = new PersonObject("Baeldung"); personObject.generateId(); assertEquals(1, personObject.getId()); assertEquals("Baeldung", personObject.getName()); } }

5. Memasukkan Bean ke Entitas JPA

Dari sudut pandang wadah Musim Semi, entitas tidak lain adalah objek biasa. Karena itu, tidak ada yang istimewa tentang menyuntikkan kacang Spring ke dalam entitas JPA.

Namun, karena menyuntikkan ke dalam entitas JPA adalah kasus penggunaan yang umum, mari kita bahas lebih detail.

5.1. Kelas Entitas

Mari kita mulai dengan kerangka kelas entitas:

@Entity @Configurable(preConstruction = true) public class PersonEntity { @Id private int id; private String name; public PersonEntity() { } // other code - shown in the next subsection }

Perhatikan elemen preConstruction dalam anotasi @Configurable : ini memungkinkan kita untuk memasukkan dependensi ke dalam objek sebelum dibangun sepenuhnya.

5.2. Injeksi Layanan

Sekarang kita dapat memasukkan IdService ke PersonEntity , mirip dengan yang kita lakukan dengan PersonObject :

// annotations public class PersonEntity { @Autowired @Transient private IdService idService; // fields and no-arg constructor public PersonEntity(String name) { id = idService.generateId(); this.name = name; } // getters }

The @Transient annotation is used to tell JPA that idService is a field not to be persisted.

5.3. Test Method Update

Finally, we can update the test method to indicate that the service can be injected into the entity:

@Test public void givenUnmanagedObjects_whenInjectingIdService_thenIdValueIsCorrectlySet() { // existing statements PersonEntity personEntity = new PersonEntity("Baeldung"); assertEquals(2, personEntity.getId()); assertEquals("Baeldung", personEntity.getName()); }

6. Caveats

Although it's convenient to access Spring components from an unmanaged object, it's often not a good practice to do so.

The problem is that unmanaged objects, including entities, are usually part of the domain model. These objects should carry data only to be reusable across different services.

Injecting beans into such objects could tie components and objects together, making it harder to maintain and enhance the application.

7. Conclusion

Tutorial ini telah menjalani proses menyuntikkan kacang Spring ke dalam objek yang tidak dikelola. Itu juga menyebutkan masalah desain yang terkait dengan injeksi ketergantungan ke objek.

Kode implementasi dapat ditemukan di GitHub.