天天看點

面試必問|Spring @bean 和 @component 注解有什麼差別?

本文打算介紹幾個不太容易說出其差別,或者用途的 Spring 注解,比如 @Component 與 @Bean 的比較,@ControllerAdvice 是如何處理自定義異常的等等。

Spring 中的一些注解

1. @Component 和 @Bean 的差別是什麼?

作用對象不同:@Component 注解作用于類,而 @Bean 注解作用于方法、

@Component 通常是通過路徑掃描來自動偵測以及自動裝配到 Spring 容器中(我們可以使用 @ComponentScan 注解定義要掃描的路徑從中找出辨別了需要裝配的類自動裝配到 Spring 的 bean 容器中)。@Bean 注解通常是我們在标有該注解的方法中定義産生這個 bean,@Bean 告訴了 Spring 這是某個類的執行個體,當我們需要用它的時候還給我。

@Bean 注解比 @Component 注解的自定義性更強,而且很多地方我們隻能通過 @Bean 注解來注冊 bean。比如當我們引用第三方庫中的類需要裝配到 Spring 容器時,隻能通過 @Bean 來實作。

@Bean 注解使用示例:

@Configuration
public class AppConfig {
    @Bean
public TransferService transferService() {
return new TransferServiceImpl();
    }
}      

@Component 注解使用示例:

@Component
public class ServiceImpl implements AService {
    ....
    )      

下面這個例子是通過 @Component 無法實作的:

@Bean
public OneService getService(status) {
case (status)  {
when 1:
return new serviceImpl1();
when 2:
return new serviceImpl2();
when 3:
return new serviceImpl3();
    }
}      

2. Autowire 和 @Resource 的差別

@Autowire 和 @Resource都可以用來裝配bean,都可以用于字段或setter方法。

@Autowire 預設按類型裝配,預設情況下必須要求依賴對象必須存在,如果要允許 null 值,可以設定它的 required 屬性為 false。

@Resource 預設按名稱裝配,當找不到與名稱比對的 bean 時才按照類型進行裝配。名稱可以通過 name 屬性指定,如果沒有指定 name 屬性,當注解寫在字段上時,預設取字段名,當注解寫在 setter 方法上時,預設取屬性名進行裝配。

注意:如果 name 屬性一旦指定,就隻會按照名稱進行裝配。

@Autowire和@Qualifier配合使用效果和@Resource一樣:

@Autowired(required = false) @Qualifier("example")
private Example example;

@Resource(name = "example")
private Example example;      

@Resource 裝配順序

如果同時指定 name 和 type,則從容器中查找唯一比對的 bean 裝配,找不到則抛出異常;

如果指定 name 屬性,則從容器中查找名稱比對的 bean 裝配,找不到則抛出異常;

如果指定 type 屬性,則從容器中查找類型唯一比對的 bean 裝配,找不到或者找到多個抛出異常;

如果不指定,則自動按照 byName 方式裝配,如果沒有比對,則回退一個原始類型進行比對,如果比對則自動裝配。

3. 将一個類聲明為 Spring 的 bean 的注解有哪些?

@Component :通用的注解,可标注任意類為 Spring 的元件。如果一個 Bean 不知道屬于哪個層,可以使用 @Component 注解标注。

@Repository :對應持久層即 Dao 層,主要用于資料庫相關操作。

@Service :對應服務層,主要設計一些複雜的邏輯,需要用到 Dao 層。

@Controller :對應 Spring MVC 控制層,主要用來接受使用者請求并調用 Service 層傳回資料給前端頁面。

@Configuration :聲明該類為一個配置類,可以在此類中聲明一個或多個 @Bean 方法。

4. @Configuration :配置類注解

@Configuration 表明在一個類裡可以聲明一個或多個 @Bean 方法,并且可以由 Spring 容器處理,以便在運作時為這些 bean 生成 bean 定義和服務請求,例如:

@Configuration
public class AppConfig {

    @Bean
public MyBean myBean() {
// instantiate, configure and return bean ...
    }
}      

我們可以通過 AnnotationConfigApplicationContext 來注冊 

@Configuration

 類:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
MyBean myBean = ctx.getBean(MyBean.class);
// use myBean ...      

另外也可以通過元件掃描(component scanning)來加載,@Configuration 使用 @Component 進行原注解,是以 @Configuration 類也可以被元件掃描到(特别是使用 XML 的 元素)。@Configuration 類不僅可以使用元件掃描進行引導,還可以使用 @ComponentScan 注解自行配置元件掃描:

@Configuration
@ComponentScan("com.acme.app.services")
public class AppConfig {
// various @Bean definitions ...
}      

使用 @Configuration 的限制:

配置類必須以類的方式提供(比如不能是由工廠方法傳回的執行個體)。

配置類必須是非 final 的。

配置類必須是非本地的(即可能不在方法中聲明),native 标注的方法。

任何嵌套的配置類必須聲明為 static。

@Bean 方法可能不會反過來建立更多的配置類。

除了單獨使用 @Configuration 注解,我們還可以結合一些外部的 bean 或者注解共同使用,比如 Environment API,@PropertySource,@Value,@Profile 等等許多,這裡就不做詳細介紹了,更多的用法可以參看 Spring @Configuration 的相關文檔 。

5. @ControllerAdvice :處理全局異常利器

在 Spring 3.2 中,新增了 @ControllerAdvice、@RestControllerAdvice、@RestController 注解,可以用于定義 @ExceptionHandler、@InitBinder、@ModelAttribute,并應用到所有 @RequestMapping 、@PostMapping、@GetMapping等這些 Controller 層的注解中。

推薦一個 Spring Boot 基礎教程及實戰示例:

https://github.com/javastacks/spring-boot-best-practice

預設情況下,@ControllerAdvice 中的方法應用于全局所有的 Controller。而使用選擇器 annotations(),basePackageClasses() 和 basePackages() (或其别名value())來定義更小範圍的目标 Controller 子集。如果聲明了多個選擇器,則應用 OR 邏輯,這意味着所選的控制器應比對至少一個選擇器。請注意,選擇器檢查是在運作時執行的,是以添加許多選擇器可能會對性能産生負面影響并增加複雜性。

@ControllerAdvice 我們最常使用的是結合 @ExceptionHand

@ControllerAdvice("com.developlee.errorhandle")
public class MyExceptionHandler {
    /**
     * 捕獲CustomException
     * @param e
     * @return json格式類型
     */
    @ResponseBody
    @ExceptionHandler({CustomException.class}) //指定攔截異常的類型
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //自定義浏覽器傳回狀态碼
    public Map>String, Object< customExceptionHandler(CustomException e) {
        Map&lt;String, Object&gt; map = new HashMap&lt;&gt;();
map.put("code", e.getCode());
map.put("msg", e.getMsg());
return map;
    }
}      

更多資訊可以參看 Spring @ControllerAdvice 的官方文檔。

6. @Component, @Repository, @Service 的差別
面試必問|Spring @bean 和 @component 注解有什麼差別?

@Component是一個通用的Spring容器管理的單例bean元件。而@Repository, @Service, @Controller就是針對不同的使用場景所采取的特定功能化的注解元件。

是以,當你的一個類被@Component所注解,那麼就意味着同樣可以用@Repository, @Service, @Controller 來替代它,同時這些注解會具備有更多的功能,而且功能各異。

最後,如果你不知道要在項目的業務層采用@Service還是@Component注解。那麼,@Service是一個更好的選擇。

總結

以上簡單介紹了幾種 Spring 中的幾個注解及代碼示例,就我個人而言,均是平時用到且不容易了解的幾個,或者容易忽略的幾個。當然,這篇文章并沒有完全介紹完,在今後還會繼續補充完善。