<div>
<a class="article-series-header" href="javascript:void(0);">該文章是系列的一部分</a>
<div>
<div>
• Spring Core 註解
<br>
• Spring Web 註解
<br>
• Spring Boot 註解
<br>
• Spring Scheduling 註解
<br>
• Spring Data 註解
<br>
<div>
• Spring Bean 註解 (當前文章)
</div>
</div >
<!-- end of article series inner -->
</div>
<!-- .article-series-links -->
</div >
<!-- end of article series section -->
1. 概述
本教程將討論最常用的 Spring Bean 註解,用於定義不同類型的 Bean。
有幾種方法可以在 Spring 容器中配置 Bean。首先,我們可以使用 XML 配置聲明 Bean。 此外,我們還可以使用 <em @Bean</em> 註解在配置類中聲明 Bean。
最後,我們可以使用 <em org.springframework.stereotype</em> 包中的一個註解標記類,並讓其他部分由組件掃描處理。
2. 組件掃描
Spring 可以在啓用組件掃描的情況下自動掃描一個包以查找 Bean。
@ComponentScan 配置掃描哪些 包以查找具有註解配置的類。我們可以直接使用 basePackages 或 value 參數指定基本包名(value 是 basePackages 的別名):
@Configuration
@ComponentScan(basePackages = "com.baeldung.annotations")
class VehicleFactoryConfig {}此外,我們還可以使用 basePackageClasses 參數來指向基類包中的類:
@Configuration
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
class VehicleFactoryConfig {}兩個參數都是數組,以便我們可以為每個提供多個包。
如果未指定任何參數,掃描將從包含帶有 @ComponentScan 註解的類所在的同一包中進行。
@ComponentScan 利用了 Java 8 的重複註解功能,這意味着我們可以使用它標記一個類多次:
@Configuration
@ComponentScan(basePackages = "com.baeldung.annotations")
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
class VehicleFactoryConfig {}當然,以下是翻譯後的內容:
或者,我們也可以使用 @ComponentScans 來指定多個 @ComponentScan 配置:
@Configuration
@ComponentScans({
@ComponentScan(basePackages = "com.baeldung.annotations"),
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
})
class VehicleFactoryConfig {}當使用XML配置時,配置組件掃描非常簡單:
<context:component-scan base-package="com.baeldung" />3. <em @Component>
@Component 是一個類級別的註解。在組件掃描期間,Spring Framework 會自動檢測帶有@Component註解的類。
@Component
class CarUtility {
// ...
}默認情況下,該類的 Bean 實例名稱與類名相同,且以小寫字母開頭。此外,我們還可以使用註解的value參數指定不同的名稱。
因為@Repository, @Service, @Configuration和@Controller都是@Component的元註解,它們共享相同的 Bean 命名行為。Spring 在組件掃描過程中也會自動拾取它們。
4. <em @Repository>
DAO 或 Repository 類通常代表應用程序中的數據庫訪問層,應使用 <em @Repository> 註解進行標註。
@Repository
class VehicleRepository {
// ...
}使用此註解的主要優勢在於它啓用了自動持久化異常翻譯功能。
當使用持久化框架,例如 Hibernate,在帶有 @Repository 註解的類中拋出的原生異常會自動翻譯成 Spring 的 DataAccessExeption 的子類。
要啓用異常翻譯,我們需要聲明自己的 PersistenceExceptionTranslationPostProcessor Bean:
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}請注意,在大多數情況下,Spring 會自動執行上述步驟。
或者通過 XML 配置:
<bean class=
"org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>5. @Service
應用程序的業務邏輯通常位於服務層,因此我們將使用@Service註解來指示一個類屬於該層:
@Service
public class VehicleService {
// ...
}6. <em @Controller>
@Controller 是一個類級別的註解,告訴 Spring 框架該類作為 Spring MVC 中的 控制器。
@Controller
public class VehicleController {
// ...
}7. <em @Configuration@
類可以包含用 註解標記的 bean 定義方法:
@Configuration
class VehicleFactoryConfig {
@Bean
Engine engine() {
return new Engine();
}
}8. 刻板註解與 AOP
當我們使用 Spring 刻板註解時,很容易創建一個點切,該點切可以針對具有特定刻板印象的所有類。例如,假設我們想測量 DAO 層方法的執行時間。我們將創建一個切面(使用 AspectJ 註解),利用 刻板印象:
@Aspect
@Component
public class PerformanceAspect {
@Pointcut("within(@org.springframework.stereotype.Repository *)")
public void repositoryClassMethods() {};
@Around("repositoryClassMethods()")
public Object measureMethodExecutionTime(ProceedingJoinPoint joinPoint)
throws Throwable {
long start = System.nanoTime();
Object returnValue = joinPoint.proceed();
long end = System.nanoTime();
String methodName = joinPoint.getSignature().getName();
System.out.println(
"Execution of " + methodName + " took " +
TimeUnit.NANOSECONDS.toMillis(end - start) + " ms");
return returnValue;
}
}在本示例中,我們創建了一個切片,它匹配所有標記了 @Repository 註解的類中的方法。然後,我們使用 @Around 建議來針對該切片,並確定攔截的方法調用的執行時間。
此外,使用這種方法,我們可以為每個應用程序層添加日誌記錄、性能管理、審計和其他行為。
9. 結論
在本文中,我們探討了 Spring 樣板註解及其各自代表的語義。
我們還學習瞭如何使用組件掃描來告知容器在哪裏查找帶有註解的類。
最後,我們瞭解到這些註解 導致一個簡潔、分層的設計,以及應用程序關注點的分離。同時,它們也使得配置更加精簡,因為我們不再需要手動定義 Bean。