Spring: @Component versus @Bean

459

Saya mengerti bahwa @Componentanotasi diperkenalkan pada musim semi 2.5 untuk menghilangkan definisi xml bean dengan menggunakan pemindaian classpath.

@Beandiperkenalkan di musim semi 3.0 dan dapat digunakan dengan @Configurationuntuk sepenuhnya menyingkirkan file xml dan menggunakan konfigurasi java sebagai gantinya.

Apakah mungkin menggunakan kembali @Componentanotasi alih-alih memperkenalkan @Beananotasi? Pemahaman saya adalah bahwa tujuan akhirnya adalah membuat kacang di kedua kasus.

pengguna1396576
sumber
4
Apakah ada tempat di mana @Bean dapat digunakan selain dari kelas Konfigurasi?
Willa
@Illa Ya, ada. Itu namanya Lite mode. Dan itu tidak dianjurkan. Lihat di sini: docs.spring.io/spring/docs/current/spring-framework-reference/…
smwikipedia
9
Saya akan meringkasnya mengatakan metode dengan @beanmengembalikan contoh kacang musim semi yang dapat dikustomisasi, sementara @componentmendefinisikan kelas yang mungkin kemudian dimunculkan oleh mesin pegas IoC bila diperlukan.
Sebas

Jawaban:

433

@Componentdan @Beanmelakukan dua hal yang sangat berbeda, dan tidak boleh bingung.

@Component(dan @Servicedan @Repository) digunakan untuk mendeteksi dan mengkonfigurasi kacang secara otomatis menggunakan pemindaian classpath. Ada pemetaan satu-ke-satu implisit antara kelas beranotasi dan kacang (yaitu satu kacang per kelas). Kontrol kabel sangat terbatas dengan pendekatan ini, karena ini murni deklaratif.

@Beandigunakan untuk secara eksplisit mendeklarasikan kacang tunggal, daripada membiarkan Spring melakukannya secara otomatis seperti di atas. Ini memisahkan deklarasi kacang dari definisi kelas, dan memungkinkan Anda membuat dan mengkonfigurasi kacang persis seperti yang Anda pilih.

Untuk menjawab pertanyaan Anda ...

mungkinkah menggunakan kembali @Componentanotasi alih-alih memperkenalkan @Beananotasi?

Tentu, mungkin; tetapi mereka memilih untuk tidak, karena keduanya sangat berbeda. Mata air sudah cukup membingungkan tanpa membuat air semakin berlumpur.

skaffman
sumber
3
Jadi saya hanya bisa menggunakan @Componentketika autowired diperlukan? Tampaknya @Beantidak dapat mempengaruhi@Autowired
Jaskey
3
gunakan '@component' untuk kelas berbasis layanan, '@Bean' sebagai objek buatan pabrik, misalnya sumber data jdbc
Junchen Liu
2
@Jaskey dapat Anda gunakan @Autowireddengan @Beanjika Anda memiliki anotasi kelas kacang Anda dengan@Configuration
starcorn
6
Maaf tapi saya tidak mengerti sepatah kata pun dari penjelasan Anda. Anda memahami hal ini dengan jelas, jadi tolong tuliskan penjelasan yang jelas atau arahkan ke dokumentasi yang sesuai?
Alex Worden
13
Sekarang saya mengerti konsepnya (dari membaca jawaban orang lain), penjelasan Anda masuk akal. Yang memberi tahu saya lebih banyak bahwa penjelasan Anda tidak baik bagi siapa pun yang belum memahami konsepnya.
Alex Worden
397

@Component Lebih disukai untuk pemindaian komponen dan kabel otomatis.

Kapan sebaiknya Anda menggunakan @Bean ?

Terkadang konfigurasi otomatis bukanlah suatu pilihan. Kapan? Mari kita bayangkan bahwa Anda ingin mengirim komponen dari pustaka pihak ketiga (Anda tidak memiliki kode sumber sehingga Anda tidak dapat membubuhi keterangan kelasnya dengan @Component), jadi konfigurasi otomatis tidak dimungkinkan.

The @Bean penjelasan mengembalikan sebuah objek yang semi harus mendaftar sebagai kacang dalam konteks aplikasi. The tubuh metode beruang logika bertanggung jawab untuk menciptakan instance.

MagGGG
sumber
5
Saya pikir ini yang paling masuk akal. Jika saya mengerti dengan benar @Componentberjalan di kelas sendiri saat @Beanmelanjutkan metode kelas (yang menghasilkan contoh objek kelas).
jocull
182

Mari pertimbangkan saya ingin implementasi spesifik tergantung pada beberapa keadaan dinamis. @Beansangat cocok untuk kasus itu.

@Bean
@Scope("prototype")
public SomeService someService() {
    switch (state) {
    case 1:
        return new Impl1();
    case 2:
        return new Impl2();
    case 3:
        return new Impl3();
    default:
        return new Impl();
    }
}

Namun tidak ada cara untuk melakukannya @Component.

outdev
sumber
3
Bagaimana Anda memanggil kelas contoh itu?
PowerFlower
1
@ PowerFlower Metode ini harus dalam kelas konfigurasi, dijelaskan dengan@Configuration
Juh_
98
  1. @Component auto mendeteksi dan mengkonfigurasi kacang menggunakan pemindaian classpath sedangkan @Bean secara eksplisit mendeklarasikan kacang tunggal, daripada membiarkan Spring melakukannya secara otomatis.
  2. @Component tidak memisahkan deklarasi kacang dari definisi kelas di mana @Bean memisahkan deklarasi kacang dari definisi kelas.
  3. @Component adalah anotasi tingkat kelas sedangkan @Bean adalah anotasi tingkat metode dan nama metode berfungsi sebagai nama bean.
  4. @Component tidak perlu digunakan dengan anotasi @Configuration di mana anotasi @Bean harus digunakan di dalam kelas yang dianotasi dengan @Configuration .
  5. Kita tidak bisa membuat kacang kelas menggunakan @Component, jika kelas berada di luar wadah musim semi sedangkan kita bisa membuat kacang kelas menggunakan @Bean bahkan jika kelas hadir di luar wadah musim semi .
  6. @Component memiliki spesialisasi yang berbeda seperti @Controller, @Repository dan @Service sedangkan @Bean tidak memiliki spesialisasi .
Saurabh Prakash
sumber
3
4. Sebenarnya @Bean dapat dideklarasikan di kelas non-konfigurasi. Ini dikenal sebagai mode lite
voipp
1
Mengenai poin 5. Saya pikir kita meletakkan kacang di dalam wadah pegas. Jadi, setiap kelas berada di luar wadah pegas. Saya kira, poin 5 harus dihargai
eugen
97

Kedua pendekatan bertujuan untuk mendaftarkan tipe target dalam wadah Spring.

Perbedaannya adalah yang @Beanberlaku untuk metode , sedangkan @Componentberlaku untuk tipe .

Oleh karena itu ketika Anda menggunakan @Beananotasi, Anda mengontrol logika pembuatan instance dalam tubuh metode (lihat contoh di atas ). Dengan @Componentanotasi Anda tidak bisa.

Nurlan Akashayev
sumber
Apa itu tipe?
Jac Frall
20

Saya melihat banyak jawaban dan hampir di mana-mana yang disebutkan @Component adalah untuk autowiring di mana komponen dipindai dan @Bean persis menyatakan kacang itu untuk digunakan secara berbeda. Mari saya tunjukkan betapa berbedanya.

  • @Kacang

Pertama, ini merupakan penjelasan tingkat metode. Kedua Anda biasanya menggunakan untuk mengkonfigurasi kacang dalam kode java (jika Anda tidak menggunakan konfigurasi xml) dan kemudian memanggilnya dari kelas menggunakan metode getBean ApplicationContext. Suka

 @Configuration
class MyConfiguration{
    @Bean
    public User getUser(){
        return new User();
    }
}

class User{
}



//Getting Bean 
User user = applicationContext.getBean("getUser");
  • @Komponen

Ini adalah cara umum untuk membuat anotasi kacang dan bukan kacang khusus. Anotasi tingkat kelas dan digunakan untuk menghindari semua hal konfigurasi melalui konfigurasi java atau xml.

Kami mendapatkan sesuatu seperti ini.

@Component
class User {
}

//to get Bean
@Autowired
User user;

Itu dia . Itu baru saja diperkenalkan untuk menghindari semua langkah konfigurasi untuk instantiate dan menggunakan kacang itu.

xpionir
sumber
5
Saya pikir itu tidak perlu untuk mendapatkan objek Pengguna dari ApplicationContext ketika Anda menggunakan @Beanpendekatan. Anda masih bisa menggunakan @Autowireuntuk mendapatkan kacang seperti yang akan Anda lakukan jika @Component. @Beanhanya menambahkan Bean ke Spring Container seperti @Componenthalnya. Perbedaannya adalah sebagai berikut. 1. Menggunakan @Bean, Anda bisa menambahkan Kelas Pihak Ketiga ke Spring Container. 2. Menggunakan @Bean, Anda bisa mendapatkan implementasi antarmuka yang diinginkan saat run-time (Menggunakan pola desain pabrik)
Andy
20

Anda bisa menggunakan @Beanuntuk membuat kelas pihak ketiga yang ada tersedia untuk konteks aplikasi kerangka kerja Spring Anda.

@Bean
public ViewResolver viewResolver() {

    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

    viewResolver.setPrefix("/WEB-INF/view/");
    viewResolver.setSuffix(".jsp");

    return viewResolver;
}

Dengan menggunakan @Beananotasi, Anda bisa membungkus kelas pihak ketiga (mungkin tidak memiliki @Componentdan mungkin tidak menggunakan Spring), sebagai kacang Spring. Dan kemudian setelah dibungkus menggunakan @Bean, itu sebagai objek tunggal dan tersedia dalam konteks aplikasi kerangka kerja Spring Anda. Anda sekarang dapat dengan mudah membagikan / menggunakan kembali kacang ini di aplikasi Anda menggunakan injeksi ketergantungan dan@Autowired .

Jadi pikirkan @Beananotasi itu adalah pembungkus / adaptor untuk kelas pihak ketiga. Anda ingin membuat kelas pihak ketiga tersedia untuk konteks aplikasi kerangka kerja Spring Anda.

Dengan menggunakan @Beankode di atas, saya secara eksplisit mendeklarasikan kacang tunggal karena di dalam metode ini, saya secara eksplisit membuat objek menggunakan newkata kunci. Saya juga secara manual memanggil metode setter dari kelas yang diberikan. Jadi saya bisa mengubah nilai bidang awalan. Jadi pekerjaan manual ini disebut sebagai penciptaan eksplisit. Jika saya menggunakan @Componentuntuk kelas yang sama, kacang yang terdaftar di wadah Spring akan memiliki nilai default untuk bidang awalan.

Di sisi lain, ketika kita membubuhi keterangan kelas dengan @Component, tidak perlu bagi kita untuk menggunakan newkata kunci secara manual . Ini ditangani secara otomatis oleh Spring.

Elvis
sumber
1
Akan lebih baik jika jawaban ini diperbarui dengan contoh bagaimana kacang itu digunakan juga
softarn
Bagaimana Anda membungkus @Bean di atas kelas pihak ketiga jika kode sumber tidak memungkinkan modifikasi?
veritas
16

Ketika Anda menggunakan @Componenttag, itu sama dengan memiliki POJO (Plain Old Java Object) dengan metode deklarasi vanilla bean (dijelaskan dengan @Bean). Misalnya, metode 1 dan 2 berikut ini akan memberikan hasil yang sama.

Metode 1

@Component
public class SomeClass {

    private int number;

    public SomeClass(Integer theNumber){
        this.number = theNumber.intValue();
    }

    public int getNumber(){
        return this.number;
    }
}

dengan kacang untuk 'theNumber':

@Bean
Integer theNumber(){
    return new Integer(3456);
}

Metode 2

//Note: no @Component tag
public class SomeClass {

    private int number;

    public SomeClass(Integer theNumber){
        this.number = theNumber.intValue();
    }

    public int getNumber(){
        return this.number;
    }
}

dengan kacang untuk keduanya:

@Bean
Integer theNumber(){
    return new Integer(3456);
}

@Bean
SomeClass someClass(Integer theNumber){
    return new SomeClass(theNumber);
}

Metode 2 memungkinkan Anda untuk menjaga pernyataan kacang bersama-sama, itu sedikit lebih fleksibel dll. Anda bahkan mungkin ingin menambahkan kacang SomeClass non-vanilla lain seperti berikut:

@Bean
SomeClass strawberryClass(){
    return new SomeClass(new Integer(1));
}
Beberapa pria
sumber
10

Anda memiliki dua cara untuk menghasilkan kacang. Pertama adalah membuat kelas dengan anotasi @Component. Yang lainnya adalah membuat metode dan menjelaskannya dengan @Bean. Untuk kelas yang berisi metode dengan @Beanharus dianotasi dengan @Configuration Setelah Anda menjalankan proyek pegas Anda, kelas dengan @ComponentScananotasi akan memindai setiap kelas dengan @Componentdi atasnya, dan mengembalikan instance dari kelas ini ke Kontainer Ioc. Hal lain yang @ComponentScanakan dilakukan adalah menjalankan metode dengan . Anda dapat menulis logika dan mengembalikan objek yang Anda inginkan. Hal lain yang layak untuk disebutkan adalah nama metode dengan adalah nama default bean.@Bean di atasnya dan mengembalikan objek kembali ke Kontainer Ioc sebagai kacang. Jadi, ketika Anda perlu memutuskan jenis kacang apa yang ingin Anda buat tergantung pada kondisi saat ini, Anda perlu menggunakannya@Bean@Bean

Dai Niu
sumber
6
  • @component dan spesialisasinya (@Controller, @service, @repository) memungkinkan deteksi otomatis menggunakan pemindaian classpath. Jika kita melihat kelas komponen seperti @Controller, @service, @repository akan dipindai secara otomatis oleh kerangka kerja pegas menggunakan pemindaian komponen.
  • @Bean di sisi lain hanya dapat digunakan untuk secara eksplisit mendeklarasikan kacang tunggal dalam kelas konfigurasi.
  • @Bean digunakan untuk secara eksplisit mendeklarasikan kacang tunggal, daripada membiarkan pegas melakukannya secara otomatis. Itu membuat pernyataan septate kacang dari definisi kelas.
  • Singkatnya @Controller, @service, @repository adalah untuk deteksi otomatis dan @Bean untuk membuat seprate bean dari kelas
    - @Controller
    LoginController kelas publik 
    {--code--}

    - @Configuration
    AppConfig kelas publik {
    @Kacang
    publik SessionFactory sessionFactory () 
    {--code--}
alok
sumber
3

@Bean dibuat untuk menghindari penggabungan pegas dan aturan bisnis Anda dalam waktu kompilasi. Ini berarti Anda dapat menggunakan kembali aturan bisnis Anda dalam kerangka kerja lain seperti PlayFramework atau JEE.

Selain itu, Anda memiliki kontrol total tentang cara membuat kacang, di mana itu tidak cukup instan Spring instan.

Saya menulis posting yang membicarakannya.

https://coderstower.com/2019/04/23/factory-methods-decoupling-ioc-container-abstraction/

Daniel Andres Pelaez Lopez
sumber
3

Perbedaan antara Bean dan Komponen:

Perbedaan antara Bean dan Komponen

AzarEJ
sumber
1

1. Tentang @Component
@Component berfungsi seperti halnya pada @Confonation.

Keduanya menunjukkan bahwa kelas yang dianotasi memiliki satu atau lebih kacang yang harus didaftarkan Spring-IOC-Container.

Kelas dijelaskan oleh @Component, kami menyebutnya Component of Spring. Ini adalah konsep yang mengandung beberapa kacang.

Component classharus dipindai secara otomatis oleh Spring untuk mendaftarkan kacang tersebut component class.

2. Tentang @Bean
@Bean digunakan untuk membubuhi keterangan metode component-class(sebagaimana disebutkan di atas). Ini menunjukkan contoh disimpan oleh metode beranotasi perlu didaftarkan Spring-IOC-Container.

3. Kesimpulan
Perbedaan antara keduanya relatif tidak disadari, mereka digunakan dalam different circumstances. Penggunaan umum adalah:

    // @Configuration is implemented by @Component
    @Configuration
    public ComponentClass {

      @Bean
      public FirstBean FirstBeanMethod() {
        return new FirstBean();
      }

      @Bean
      public SecondBean SecondBeanMethod() {
        return new SecondBean();
      }
    }
Martin521Wang
sumber
0

Poin tambahan dari jawaban di atas

Katakanlah kita punya modul yang dibagikan di banyak aplikasi dan berisi beberapa layanan. Tidak semua dibutuhkan untuk setiap aplikasi.

Jika menggunakan @Component pada kelas-kelas layanan dan pemindaian komponen dalam aplikasi,

kita mungkin akhirnya mendeteksi lebih banyak kacang daripada yang diperlukan

Dalam hal ini, Anda harus menyesuaikan pemfilteran pemindaian komponen atau memberikan konfigurasi yang dapat dijalankan oleh kacang yang tidak digunakan. Kalau tidak, konteks aplikasi tidak akan dimulai.

Dalam hal ini, lebih baik bekerja dengan penjelasan @Bean dan hanya instantiate kacang tersebut,

yang diperlukan secara individual di setiap aplikasi

Jadi, pada dasarnya, gunakan @Bean untuk menambahkan kelas pihak ketiga ke konteksnya. Dan @Component jika ada di dalam aplikasi tunggal Anda.

AzarEJ
sumber