Memanggil metode beranotasi @Bean dalam konfigurasi java Spring

102

Saya ingin tahu tentang bagaimana injeksi pegas menangani metode panggilan dengan @Beananotasi. Jika saya meletakkan @Beananotasi pada sebuah metode, dan mengembalikan sebuah instance, saya mengerti bahwa itu memberitahu spring untuk membuat bean dengan memanggil metode tersebut dan mendapatkan instance yang dikembalikan. Namun, terkadang kacang itu harus digunakan untuk mengirim kacang lain atau membuat kode lain. Cara yang biasa dilakukan adalah dengan memanggil @Beanmetode beranotasi untuk mendapatkan sebuah instance. Pertanyaan saya adalah, mengapa ini tidak menyebabkan ada beberapa contoh kacang yang beredar?

Misalnya lihat kode di bawah ini (diambil dari pertanyaan lain). The entryPoint()Metode dijelaskan dengan @Bean, jadi saya akan membayangkan musim semi akan membuat contoh baru dari BasicAuthenticationEntryPointsebagai kacang. Kemudian, kami memanggil entryPoint()lagi di blok konfigurasi, tetapi sepertinya entryPoint()mengembalikan instance kacang, dan tidak dipanggil beberapa kali (saya mencoba masuk, dan hanya mendapat satu entri log). Secara potensial kita bisa memanggil entryPoint()beberapa kali di bagian lain dari konfigurasi, dan kita akan selalu mendapatkan contoh yang sama. Apakah pemahaman saya tentang ini benar? Apakah musim semi melakukan beberapa metode penulisan ulang ajaib yang dianotasi @Bean?

@Bean
public BasicAuthenticationEntryPoint entryPoint() {
    BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
    basicAuthEntryPoint.setRealmName("My Realm");
    return basicAuthEntryPoint;
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http
        .exceptionHandling()
            .authenticationEntryPoint(entryPoint())
            .and()
        .authorizeUrls()
            .anyRequest().authenticated()
            .and()
        .httpBasic();       
}
markwatson.dll
sumber

Jawaban:

134

Ya, Spring memang ajaib . Periksa Spring Docs :

Di sinilah keajaiban masuk: Semua @Configurationkelas disubkelaskan pada saat startup dengan CGLIB . Di subclass, metode anak memeriksa container terlebih dahulu untuk setiap kacang yang di-cache (terbatas) sebelum memanggil metode induk dan membuat instance baru.

Ini berarti bahwa panggilan ke @Beanmetode diproksikan melalui CGLIB dan oleh karena itu versi kacang yang di-cache dikembalikan (yang baru tidak dibuat).

Cakupan default @Beans adalah SINGLETON, jika Anda menentukan cakupan yang berbeda seperti PROTOTYPEpanggilan akan diteruskan ke metode asli.

Harap dicatat bahwa ini tidak berlaku untuk metode statis . Sesuai dokumen musim semi:

Panggilan ke @Beanmetode statis tidak pernah dicegat oleh container, bahkan di dalam @Configurationkelas (seperti yang dijelaskan sebelumnya di bagian ini), karena keterbatasan teknis: subclass CGLIB hanya dapat mengganti metode non-statis. Akibatnya, panggilan langsung ke @Beanmetode lain memiliki semantik Java standar, yang menghasilkan instance independen yang dikembalikan langsung dari metode pabrik itu sendiri.

wassgren
sumber
Apakah mungkin untuk mengganti kacang yang dibuat dengan cara ini? Sebagai contoh, saya memiliki kelas yang ditentukan Spring yang secara langsung memanggil metode pembuatan kacang. Yang saya inginkan adalah bukan kacang yang dibuat dengan metode itu yang digunakan, tetapi yang saya definisikan sendiri (dengan memberi anotasi @Beandan @Primary).
Fons
4
Tetapi saya juga ingat bahwa proxy (jdk atau CGLIB, mana saja) tidak dapat bekerja dalam pemanggilan mandiri, jadi bagaimana @Configuration mendefinisikan ketergantungan antar-kacang? Ini menggunakan persis doa sendiri
Nowhy
3
@Nowhy CGLib allows us to create proxy classes at runtime by creating sub class of specified class using Byte code generation. CGLib proxies are used in the case where Proxy is to be created for those class which does not have any interfaces or have methods which are not declared in the implementing interface. Dalam kasus ini, CGLIB membuat subclass dari kelas @Configuration dan mengganti metodenya (termasuk metode @Bean). Jadi, ketika kita memanggil metode @Bean dari metode lain, kita sebenarnya memanggil versi yang ditimpa (berkat pengikatan dinamis java).
Flame239
Jadi apakah selfInvocation AOP in @Componentakan berfungsi jika saya menggunakan CHLIB untuk membuat proxy alih-alih java Poxy?
Antoniossss