一文帶你瞭解 Spring 的@Enablexxx 註解

you發表於2022-11-27
layout: post
categories: Java
title: 一文帶你瞭解 Spring 的@Enablexxx 註解
tagline: by 子悠
tags: 
  - 子悠

前面的文章給大家介紹 Spring 的重試機制的時候有提到過 Spring 有很多 @Enable 開頭的註解,平時在使用的時候也沒有注意過為什麼會有這些註解,今天就給大家介紹一下。

@Enable 註解

首先我們先看一下有哪些常用的 @Enable 開頭的註解,以及都是幹什麼用的。

  • @EnableRetry:開啟 Spring 的重試功能;
  • @EnableScheduling:開啟 Spring 的定時功能;
  • @EnableAsync:開啟 Spring 的非同步功能;
  • @EnableAutoConfiguration:開啟 Spring 的自動裝配功能;

上面這幾個是我們經常會用到和看到的,都知道在使用相應的功能的時候,如果沒有配置上面的註解功能都是不生效的。以我們前面的文章的 Spring 重試為例,我們需要在啟動類上面配置 @EnableRetry ,否則自動重試註解 @Retryable 是不會生效的,如下所示,沒看過的可以去看下,https://mp.weixin.qq.com/s/U_nm92ujCGArkii5ze7uaA。

@Import 註解

那有的小夥伴就要問了,這個 @EnableRetry 註解到底有什麼作用呢?不用這個註解就沒辦法了嗎?

要知道這個註解有什麼功效,我們可以點開看看原始碼,程式碼如下

package org.springframework.retry.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@Import(RetryConfiguration.class)
@Documented
public @interface EnableRetry {

	boolean proxyTargetClass() default false;
}

可以看到原始碼很簡單,其中最有用的就一行 @Import(RetryConfiguration.class) ,我們可以嘗試把這一行程式碼放到啟動類上面看看效果,如下所示,可以看到專案可以正常啟動,並且也還是有效果的,說明跟我們的 @EnableRetry 註解是一樣的。

從上面的實驗效果我們可以看到 @EnableRetry 註解其實就是對 @Import(RetryConfiguration.class) 的一個封裝,同樣的透過原始碼我們還可以看到 @EnableScheduling 註解就是對 @Import({SchedulingConfiguration.class}) 的一個封裝。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({SchedulingConfiguration.class})
@Documented
public @interface EnableScheduling {
}

那如果在沒有 @Enablexxx 註解的時候,我們直接透過 @Import 註解是可以這樣寫的,在一個 @Import 註解裡面包含多個配置類,不過這種在配置類較多的場景下還是相對不夠簡潔的,因而才有了各自功能對應的 @Enable 註解。

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.retry.annotation.RetryConfiguration;
import org.springframework.scheduling.annotation.SchedulingConfiguration;

@SpringBootApplication
@ComponentScan(value = "com.example.demo.*")
@Import({RetryConfiguration.class, SchedulingConfiguration.class})
public class DemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

}

為什麼要使用 @Import 註解呢

那麼很多的小夥伴又要問了,為啥要透過使用 @Import 註解將配置類載入進來呢?在專案中的 Spring 上下文中不是能直接獲取到嗎?為此我們來實驗一下,透過下面的程式碼我們看下是否能在 Spring 的容器中獲取到 RetryConfiguration Bean

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.retry.annotation.RetryConfiguration;
import org.springframework.scheduling.annotation.SchedulingConfiguration;

@SpringBootApplication
@ComponentScan(value = "com.example.demo.*")
//@Import({RetryConfiguration.class, SchedulingConfiguration.class})
public class DemoApplication {

  public static void main(String[] args) {

    ConfigurableApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
    Object bean = applicationContext.getBean("org.springframework.retry.annotation.RetryConfiguration");
    System.out.println(bean.toString());
  }
}

啟動過後我們可以看到結果如下,提示我們在容器中找不到這個 bean,有點小夥伴會說是不是 bean 的名字寫錯了,其實並不是,緊接著我們再把註釋的那一行放開再執行一下。

可以看到,這次我們成功的獲取到了這個 Bean,這個實驗就是告訴我們,其實在預設情況下,Spring 的容器中是找不到RetryConfiguration 這個 Bean 的,因此我們需要透過使用 @Import 註解,將該類載入到容器中。

那麼為什麼在容器中找不到這個 Bean 呢?

其實很簡單,因為這個 Bean 跟我們當前環境的類是不是同一個包裡面的,在專案啟動的過程中並不會掃描到 RetryConfiguration 類所在的包,因此找不到是很正常的。

總結

上面透過 @EnableRetry 這個註解帶大家瞭解了一下 Spring@Enable 開頭的註解的使用原理,相信大家對這些註解有了更深入的瞭解。簡單來說就是因為我們要使用的很多類並不在我們專案所在的包下面,我們不能將所有的依賴包都進行掃描,也不不方便將所有的配置類都透過 @Import 的方式進行匯入,而是讓每個功能的專案包都提供一個 @Enable 開頭的註解,我們直接啟用註解就可以達到效果。

這種方式我們在平時的開發中也可以自己實現,實現一個自己的 @Enable 開頭的註解來實現特定的功能,下一篇文章我們來帶大家實現一下。好了,今天的文章就到這裡,如果覺得有幫助還請大家幫我們的文章點贊,評論,轉發,一鍵三連走起。


更多優質內容歡迎關注公眾號【Java 極客技術】,我準備了一份面試資料,回覆【bbbb07】免費領取。希望能在這寒冷的日子裡,幫助到大家。

相關文章