Spring @Component註解

    1.概述

    在本教程中,我們將全面介紹Spring @Component批註和相關區域。到最後,我們將看到使用它與某些Spring核心功能集成的不同方法,以及如何利用其許多優點。

    2. Spring ApplicationContext

    在我們了解@Component的值之前,我們必須首先了解一些有關Spring ApplicationContext 。在這裡,Spring會保存已確定要自動管理和分發的對象的實例。這些被稱為豆。 Bean管理和依賴注入的機會是Spring的一些主要功能。

    使用“控制反轉”原理, Spring從我們的應用程序中收集bean實例,並在適當的時間使用它們。我們可以顯示對Spring的bean依賴關係,而無需處理那些對象的設置和實例化。

    使用@Autowired註釋將Spring託管的bean注入我們的應用程序的能力是在Spring中創建功能強大且可伸縮的代碼的驅動力。

    那麼,我們如何告訴Spring我們希望它為我們管理的bean?我們應該通過在類上使用構造型註釋來利用Spring的自動bean檢測功能。

    3. @Component

    @Component是一個註釋,它允許Spring自動檢測我們的自定義bean。

    換句話說,無需編寫任何顯式代碼,Spring即可:

    • 掃描我們的應用程序以查找帶有@Component
    • 實例化它們並將任何指定的依賴項注入到它們中
    • 隨時隨地註入

    但是,大多數開發人員更喜歡使用更專業的構造型註釋來實現此功能。

    3.1。Spring 其他註解

    Spring提供了一些專門的@Controller@Service Service和@Repository 。它們都提供與@Component相同的功能。它們都具有相同作用的原因是它們都是由@Component作為每個註釋的元註釋組成的註釋。它們就像@Component別名,具有特殊用途,並且在Spring自動檢測或依賴項注入之外具有含義。

    如果確實需要,從理論上講,我們可以選擇@Component來滿足我們的bean自動檢測需求。另一方面,我們也可以使用@Component自己的專用註釋。但是,Spring的其他領域專門針對Spring的特殊註釋,以提供額外的自動化好處。因此,我們可能大多數時候都應該堅持使用已建立的專業。

    假設我們在Spring Boot項目中有每種情況的示例:

    @Controller
    
     public class ControllerExample {
    
     }
    
    
    
     @Service
    
     public class ServiceExample {
    
     }
    
    
    
     @Repository
    
     public class RepositoryExample {
    
     }
    
    
    
     @Component
    
     public class ComponentExample {
    
     }
    
    
    
     @Target({ElementType.TYPE})
    
     @Retention(RetentionPolicy.RUNTIME)
    
     @Component
    
     public @interface CustomComponent {
    
     }
    
    
    
     @CustomComponent
    
     public class CustomComponentExample {
    
     }

    我們可以編寫一個測試來證明Spring會自動檢測到每個測試並將其添加到ApplicationContext

    @SpringBootTest
    
     @ExtendWith(SpringExtension.class)
    
     public class ComponentUnitTest {
    
    
    
     @Autowired
    
     private ApplicationContext applicationContext;
    
    
    
     @Test
    
     public void givenInScopeComponents_whenSearchingInApplicationContext_thenFindThem() {
    
     assertNotNull(applicationContext.getBean(ControllerExample.class));
    
     assertNotNull(applicationContext.getBean(ServiceExample.class));
    
     assertNotNull(applicationContext.getBean(RepositoryExample.class));
    
     assertNotNull(applicationContext.getBean(ComponentExample.class));
    
     assertNotNull(applicationContext.getBean(CustomComponentExample.class));
    
     }
    
     }

    3.2。 @ComponentScan

    在我們完全依賴@Component之前,我們必須了解一下,它本身只是一個簡單的註釋。註釋用於將bean與其他對象(例如域對象)區分開的目的。但是, Spring使用@ComponentScan批註將它們全部收集到其ApplicationContext

    如果我們正在編寫Spring Boot應用程序,那麼了解@SpringBootApplication是一個包含@ComponentScan的組合批註會很有幫助。只要我們的@SpringBootApplication類位於項目的根目錄下,它將掃描默認情況下定義的@Component

    但是,如果我們的@SpringBootApplication類不能位於項目的根目錄下,或者我們想掃描外部源,則可以@ComponentScan以查找我們指定的任何包,只要它存在於類路徑中即可。

    讓我們定義一個範圍外的@Component bean:

    package com.baeldung.component.scannedscope;
    
    
    
     @Component
    
     public class ScannedScopeExample {
    
     }

    接下來,我們可以通過對@ComponentScan批註的明確說明將其包括在內:

    package com.baeldung.component.inscope;
    
    
    
     @SpringBootApplication
    
     @ComponentScan({"com.baeldung.component.inscope", "com.baeldung.component.scannedscope"})
    
     public class ComponentApplication {
    
     //public static void main(String[] args) {...}
    
     }

    最後,我們可以測試它的存在:

    @Test
    
     public void givenScannedScopeComponent_whenSearchingInApplicationContext_thenFindIt() {
    
     assertNotNull(applicationContext.getBean(ScannedScopeExample.class));
    
     }

    實際上,當我們要掃描項目中包含的外部依賴項時,更可能發生這種情況。

    3.3。 @Component限制

    @Component時,我們希望某個對象成為Spring管理的bean。

    例如,讓我們在項目外部的包中@Component

    package com.baeldung.component.outsidescope;
    
    
    
     @Component
    
     public class OutsideScopeExample {
    
     }

    這是一個證明ApplicationContext不包含外部組件的測試:

    @Test
    
     public void givenOutsideScopeComponent_whenSearchingInApplicationContext_thenFail() {
    
     assertThrows(NoSuchBeanDefinitionException.class, () -> applicationContext.getBean(OutsideScopeExample.class));
    
     }

    另外,我們可能無法訪問源代碼,因為它來自第三方資源,並且我們無法添加@Component批註。或者,也許我們想根據我們所運行的環境有條件地使用一種bean實現,而不是另一種。大多數情況下,自動檢測就足夠了,但是如果不是,我們可以使用@Bean

    4. @Component@Bean

    @Bean也是Spring在運行時用於收集bean的註釋,但在類級別未使用。相反,我們使用@Bean註釋方法,以便Spring可以將方法的結果存儲為Spring Bean。

    要查看其工作方式的示例,首先讓我們創建一個沒有註釋的POJO:

    public class BeanExample {
    
     }

    @Configuration註釋的類中,我們可以創建一個bean生成方法:

    @Bean
    
     public BeanExample beanExample() {
    
     return new BeanExample();
    
     }

    BeanExample可能表示一個本地類,也可能是一個外部類。沒關係,因為我們只需要返回它的一個實例。

    然後,我們可以編寫一個測試來驗證Spring是否確實拾取了bean:

    @Test
    
     public void givenBeanComponent_whenSearchingInApplicationContext_thenFindIt() {
    
     assertNotNull(applicationContext.getBean(BeanExample.class));
    
     }

    @Component@Bean之間的差異,我們應該注意一些重要的含義。

    • @Component是類級別的註釋,但是@Bean是方法級別的,因此@Component僅在類的源代碼可編輯時才是一個選項。 @Bean總是可以使用,但是更冗長。
    • @Component與Spring的自動檢測兼容,但是@Bean需要手動的類實例化。
    • 使用@Bean將Bean的實例與其類定義解耦。這就是為什麼我們可以使用它甚至將3rd Party類製作為Spring Bean的原因。這也意味著我們可以引入邏輯來決定要使用bean的幾個可能的實例選項中的哪一個。

    5.結論

    我們剛剛探討了Spring @Component批註以及其他相關主題。首先,我們討論了各種Spring構造型註解,它們只是@Component專門版本。然後,我們了解到@Component不會執行任何操作,除非@ComponentScan可以找到它。最後,由於無法@Component上使用@Component,因此我們學習瞭如何使用@Bean註解。