[Spring]springboot

Duancf發表於2024-08-15
  1. 簡單介紹一下 Spring?有啥缺點?
    Spring 是重量級企業開發框架 Enterprise JavaBean(EJB) 的替代品,Spring 為企業級 Java 開發提供了一種相對簡單的方法,透過 依賴注入 和 面向切面程式設計 ,用簡單的 Java 物件(Plain Old Java Object,POJO) 實現了 EJB 的功能
    雖然 Spring 的元件程式碼是輕量級的,但它的配置卻是重量級的(需要大量 XML 配置) 。
    為此,Spring 2.5 引入了基於註解的元件掃描,這消除了大量針對應用程式自身元件的顯式 XML 配置。Spring 3.0 引入了基於 Java 的配置,這是一種型別安全的可重構配置方式,可以代替 XML。
    儘管如此,我們依舊沒能逃脫配置的魔爪。開啟某些 Spring 特性時,比如事務管理和 Spring MVC,還是需要用 XML 或 Java 進行顯式配置。啟用第三方庫時也需要顯式配置,比如基於 Thymeleaf 的 Web 檢視。配置 Servlet 和過濾器(比如 Spring 的DispatcherServlet)同樣需要在 web.xml 或 Servlet 初始化程式碼裡進行顯式配置。元件掃描減少了配置量,Java 配置讓它看上去簡潔不少,但 Spring 還是需要不少配置。
    光配置這些 XML 檔案都夠我們頭疼的了,佔用了我們大部分時間和精力。除此之外,相關庫的依賴非常讓人頭疼,不同庫之間的版本衝突也非常常見。
  2. 為什麼要有 SpringBoot?
    Spring 旨在簡化 J2EE 企業應用程式開發。Spring Boot 旨在簡化 Spring 開發(減少配置檔案,開箱即用!)。

說出使用 Spring Boot 的主要優點

開發基於 Spring 的應用程式很容易。
Spring Boot 專案所需的開發或工程時間明顯減少,通常會提高整體生產力。
Spring Boot 不需要編寫大量樣板程式碼、XML 配置和註釋。
Spring 引導應用程式可以很容易地與 Spring 生態系統整合,如 Spring JDBC、Spring ORM、Spring Data、Spring Security 等。
Spring Boot 遵循“固執己見的預設配置”,以減少開發工作(預設配置可以修改)。
Spring Boot 應用程式提供嵌入式 HTTP 伺服器,如 Tomcat 和 Jetty,可以輕鬆地開發和測試 web 應用程式。(這點很贊!普通執行 Java 程式的方式就能執行基於 Spring Boot web 專案,省事很多)
Spring Boot 提供命令列介面(CLI)工具,用於開發和測試 Spring Boot 應用程式,如 Java 或 Groovy。
Spring Boot 提供了多種外掛,可以使用內建工具(如 Maven 和 Gradle)開發和測試 Spring Boot 應用程式。

什麼是 Spring Boot Starters?

Spring Boot Starters 是一系列依賴關係的集合,因為它的存在,專案的依賴之間的關係對我們來說變的更加簡單了。
舉個例子:在沒有 Spring Boot Starters 之前,我們開發 REST 服務或 Web 應用程式時; 我們需要使用像 Spring MVC,Tomcat 和 Jackson 這樣的庫,這些依賴我們需要手動一個一個新增。但是,有了 Spring Boot Starters 我們只需要一個只需新增一個spring-boot-starter-web一個依賴就可以了,這個依賴包含的子依賴中包含了我們開發 REST 服務需要的所有依賴。

Spring Boot 支援哪些內嵌 Servlet 容器?

Spring Boot 支援以下嵌入式 Servlet 容器:
Name
Servlet Version
Tomcat 9.0
4.0
Jetty 9.4
3.1
Undertow 2.0
4.0
您還可以將 Spring 引導應用程式部署到任何 Servlet 3.1+相容的 Web 容器中。
這就是你為什麼可以透過直接像執行 普通 Java 專案一樣執行 SpringBoot 專案。這樣的確省事了很多,方便了我們進行開發,降低了學習難度。

如何在 Spring Boot 應用程式中使用 Jetty 而不是 Tomcat?

Spring Boot (spring-boot-starter-web)使用 Tomcat 作為預設的嵌入式 servlet 容器, 如果你想使用 Jetty 的話只需要修改pom.xml(Maven)或者build.gradle(Gradle)就可以了。

Maven:

<!--從Web啟動器依賴中排除Tomcat-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<!--新增Jetty依賴-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

Gradle:

compile("org.springframework.boot:spring-boot-starter-web") {
     exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
compile("org.springframework.boot:spring-boot-starter-jetty")

說個題外話,從上面可以看出使用 Gradle 更加簡潔明瞭,但是國內目前還是 Maven 使用的多一點,我個人覺得 Gradle 在很多方面都要好很多。

介紹一下@SpringBootApplication 註解

可以看出大概可以把 @SpringBootApplication看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 註解的集合。根據 SpringBoot 官網,這三個註解的作用分別是:
@EnableAutoConfiguration:啟用 SpringBoot 的自動配置機制
@ComponentScan: 掃描被@Component (@Service,@Controller)註解的 bean,註解預設會掃描該類所在的包下所有的類。
@Configuration:允許在上下文中註冊額外的 bean 或匯入其他配置類

Spring Boot 的自動配置是如何實現的?

這個是因為@SpringBootApplication註解的原因,在上一個問題中已經提到了這個註解。我們知道 @SpringBootApplication看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 註解的集合。

@EnableAutoConfiguration:啟用 SpringBoot 的自動配置機制
@ComponentScan: 掃描被@Component (@Service,@Controller)註解的 bean,註解預設會掃描該類所在的包下所有的類。
@Configuration:允許在上下文中註冊額外的 bean 或匯入其他配置類

@EnableAutoConfiguration是啟動自動配置的關鍵,原始碼如下(建議自己打斷點除錯,走一遍基本的流程):

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

@EnableAutoConfiguration 註解透過 Spring 提供的 @Import 註解匯入了AutoConfigurationImportSelector類(@Import 註解可以匯入配置類或者 Bean 到當前類中)。
AutoConfigurationImportSelector類中getCandidateConfigurations方法會將所有自動配置類的資訊以 List 的形式返回。這些配置資訊會被 Spring 容器作 bean 來管理。

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

自動配置資訊有了,那麼自動配置還差什麼呢?
@Conditional 註解。@ConditionalOnClass(指定的類必須存在於類路徑下),@ConditionalOnBean(容器中是否有指定的 Bean)等等都是對@Conditional註解的擴充套件。
拿 Spring Security 的自動配置舉個例子:SecurityAutoConfiguration中匯入了WebSecurityEnablerConfiguration類,WebSecurityEnablerConfiguration原始碼如下:

@Configuration
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration {

}

WebSecurityEnablerConfiguration類中使用@ConditionalOnBean指定了容器中必須還有WebSecurityConfigurerAdapter 類或其實現類。所以,一般情況下 Spring Security 配置類都會去實現 WebSecurityConfigurerAdapter,這樣自動將配置就完成了。

開發 RESTful Web 服務常用的註解有哪些?

Spring Bean 相關:

@Autowired : 自動匯入物件到類中,被注入進的類同樣要被 Spring 容器管理。
@RestController : @RestController註解是@Controller和@ResponseBody的合集,表示這是個控制器 bean,並且是將函式的返回值直 接填入 HTTP 響應體中,是 REST 風格的控制器。
@Component :通用的註解,可標註任意類為 Spring 元件。如果一個 Bean 不知道屬於哪個層,可以使用@Component 註解標註。
@Repository : 對應持久層即 Dao 層,主要用於資料庫相關操作。
@Service : 對應服務層,主要涉及一些複雜的邏輯,需要用到 Dao 層。
@Controller : 對應 Spring MVC 控制層,主要用於接受使用者請求並呼叫 Service 層返回資料給前端頁面。

處理常見的 HTTP 請求型別:

@GetMapping : GET 請求、
@PostMapping : POST 請求。
@PutMapping : PUT 請求。
@DeleteMapping : DELETE 請求。

前後端傳值:

@RequestParam以及@Pathvariable:@PathVariable用於獲取路徑引數,@RequestParam用於獲取查詢引數。
@RequestBody :用於讀取 Request 請求(可能是 POST,PUT,DELETE,GET 請求)的 body 部分並且 Content-Type 為 application/json 格式的資料,接收到資料之後會自動將資料繫結到 Java 物件上去。系統會使用HttpMessageConverter或者自定義的HttpMessageConverter將請求的 body 中的 json 字串轉換為 Java 物件。
詳細介紹可以檢視這篇文章:《Spring/Spring Boot 常用註解總結》 。

Spirng Boot 常用的兩種配置檔案

我們可以透過 application.properties或者 application.yml 對 Spring Boot 程式進行簡單的配置。如果,你不進行配置的話,就是使用的預設配置。
11. 什麼是 YAML?YAML 配置的優勢在哪裡 ?
YAML 是一種人類可讀的資料序列化語言。它通常用於配置檔案。與屬性檔案相比,如果我們想要在配置檔案中新增複雜的屬性,YAML 檔案就更加結構化,而且更少混淆。可以看出 YAML 具有分層配置資料。
相比於 Properties 配置的方式,YAML 配置的方式更加直觀清晰,簡介明瞭,有層次感。
但是,YAML 配置的方式有一個缺點,那就是不支援 @PropertySource 註解匯入自定義的 YAML 配置。
12. Spring Boot 常用的讀取配置檔案的方法有哪些?
我們要讀取的配置檔案application.yml 內容如下:
YAML
wuhan2020: 2020年初武漢爆發了新型冠狀病毒,疫情嚴重,但是,我相信一切都會過去!武漢加油!中國加油!

my-profile:
name: Guide哥
email: koushuangbwcx@163.com

library:
location: 湖北武漢加油中國加油
books:
- name: 天才基本法
description: 二十二歲的林朝夕在父親確診阿爾茨海默病這天,得知自己暗戀多年的校園男神裴之即將出國深造的訊息——對方考取的學校,恰是父親當年為她放棄的那所。
- name: 時間的秩序
description: 為什麼我們記得過去,而非未來?時間“流逝”意味著什麼?是我們存在於時間之內,還是時間存在於我們之中?卡洛·羅韋利用詩意的文字,邀請我們思考這一亙古難題——時間的本質。
- name: 了不起的我
description: 如何養成一個新習慣?如何讓心智變得更成熟?如何擁有高質量的關係? 如何走出人生的艱難時刻?
12.1. 透過 @value 讀取比較簡單的配置資訊
使用 @Value("${property}") 讀取比較簡單的配置資訊:
需要注意的是 @value這種方式是不被推薦的,Spring 比較建議的是下面幾種讀取配置資訊的方式。
12.2. 透過@ConfigurationProperties讀取並與 bean 繫結
LibraryProperties 類上加了 @Component 註解,我們可以像使用普通 bean 一樣將其注入到類中使用。
這個時候你就可以像使用普通 bean 一樣,將其注入到類中使用:
控制檯輸出:
12.3. 透過@ConfigurationProperties讀取並校驗
我們先將application.yml修改為如下內容,明顯看出這不是一個正確的 email 格式:
ProfileProperties 類沒有加 @Component 註解。我們在我們要使用ProfileProperties 的地方使用@EnableConfigurationProperties註冊我們的配置 bean:
具體使用:
因為我們的郵箱格式不正確,所以程式執行的時候就報錯,根本執行不起來,保證了資料型別的安全性:
我們把郵箱測試改為正確的之後再執行,控制檯就能成功列印出讀取到的資訊:
12.4. @PropertySource讀取指定的 properties 檔案
使用:
13. Spring Boot 載入配置檔案的優先順序瞭解麼?
Spring 讀取配置檔案也是有優先順序的,直接上圖:
更對內容請檢視官方文件:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config
14. 常用的 Bean 對映工具有哪些?
我們經常在程式碼中會對一個資料結構封裝成DO、SDO、DTO、VO等,而這些Bean中的大部分屬性都是一樣的,所以使用屬性複製類工具可以幫助我們節省大量的 set 和 get 操作。
常用的 Bean 對映工具有:Spring BeanUtils、Apache BeanUtils、MapStruct、ModelMapper、Dozer、Orika、JMapper 。
由於 Apache BeanUtils 、Dozer 、ModelMapper 效能太差,所以不建議使用。MapStruct 效能更好而且使用起來比較靈活,是一個比較不錯的選擇。
15. Spring Boot 如何監控系統實際執行狀況?
我們可以使用 Spring Boot Actuator 來對 Spring Boot 專案進行簡單的監控。
整合了這個模組之後,你的 Spring Boot 應用程式就自帶了一些開箱即用的獲取程式執行時的內部狀態資訊的 API。
比如透過 GET 方法訪問 /health 介面,你就可以獲取應用程式的健康指標。
16. Spring Boot 如何做請求引數校驗?
資料的校驗的重要性就不用說了,即使在前端對資料進行校驗的情況下,我們還是要對傳入後端的資料再進行一遍校驗,避免使用者繞過瀏覽器直接透過一些 HTTP 工具直接向後端請求一些違法資料。
Spring Boot 程式做請求引數校驗的話只需要spring-boot-starter-web 依賴就夠了,它的子依賴包含了我們所需要的東西。
16.1. 校驗註解
JSR 提供的校驗註解:
@Null 被註釋的元素必須為 null
@NotNull 被註釋的元素必須不為 null
@AssertTrue 被註釋的元素必須為 true
@AssertFalse 被註釋的元素必須為 false
@Min(value) 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值
@Max(value) 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值
@DecimalMin(value) 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值
@DecimalMax(value) 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值
@Size(max=, min=) 被註釋的元素的大小必須在指定的範圍內
@Digits (integer, fraction) 被註釋的元素必須是一個數字,其值必須在可接受的範圍內
@Past 被註釋的元素必須是一個過去的日期
@Future 被註釋的元素必須是一個將來的日期
@Pattern(regex=,flag=) 被註釋的元素必須符合指定的正規表示式
Hibernate Validator 提供的校驗註解:
@NotBlank(message =) 驗證字串非 null,且長度必須大於 0
@Email 被註釋的元素必須是電子郵箱地址
@Length(min=,max=) 被註釋的字串的大小必須在指定的範圍內
@NotEmpty 被註釋的字串的必須非空
@Range(min=,max=,message=) 被註釋的元素必須在合適的範圍內
使用示例:
16.2. 驗證請求體(RequestBody)
我們在需要驗證的引數上加上了@Valid 註解,如果驗證失敗,它將丟擲MethodArgumentNotValidException。預設情況下,Spring 會將此異常轉換為 HTTP Status 400(錯誤請求)。
16.3. 驗證請求引數(Path Variables 和 Request Parameters)
一定一定不要忘記在類上加上 Validated 註解了,這個引數可以告訴 Spring 去校驗方法引數。
更多內容請參考我的原創: 如何在 Spring/Spring Boot 中做引數校驗?你需要了解的都在這裡!

如何使用 Spring Boot 實現全域性異常處理?

Spring Boot 應用程式可以藉助 @RestControllerAdvice 和 @ExceptionHandler 實現全域性統一異常處理。

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public Result businessExceptionHandler(HttpServletRequest request, BusinessException e){
        ...
        return Result.faild(e.getCode(), e.getMessage());
    }
    ...
}

@RestControllerAdvice 是 Spring 4.3 中引入的,是@ControllerAdvice 和 @ResponseBody 的結合體,你也可以將 @RestControllerAdvice 替換為@ControllerAdvice和 @ResponseBody。這樣的話,如果響應內容不是資料的話,就不需要在方法上新增 @ResponseBody,更加靈活。

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public Result businessExceptionHandler(HttpServletRequest request, BusinessException e){
        ...
        return Result.fail(e.getCode(), e.getMessage());
    }
    ...
}

更多關於 Spring Boot 異常處理的內容,請看我的這兩篇文章:
SpringBoot 處理異常的幾種常見姿勢
使用列舉簡單封裝一個優雅的 Spring Boot 全域性異常處理!

Spring Boot 中如何實現定時任務 ?

我們使用 @Scheduled 註解就能很方便地建立一個定時任務。

@Component
public class ScheduledTasks {
    private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    /**
     * fixedRate:固定速率執行。每5秒執行一次。
     */
    @Scheduled(fixedRate = 5000)
    public void reportCurrentTimeWithFixedRate() {
        log.info("Current Thread : {}", Thread.currentThread().getName());
        log.info("Fixed Rate Task : The time is now {}", dateFormat.format(new Date()));
    }
}

單純依靠 @Scheduled 註解 還不行,我們還需要在 SpringBoot 中我們只需要在啟動類上加上@EnableScheduling 註解,這樣才可以啟動定時任務。@EnableScheduling 註解的作用是發現註解 @Scheduled 的任務並在後臺執行該任務。

為什麼使用springboot

簡化開發:Spring Boot透過提供一系列的開箱即用的元件和自動配置,簡化了專案的配置和開發過程,開發人員可以更專注於業務邏輯的實現,而不需要花費過多時間在繁瑣的配置上。
快速啟動:Spring Boot提供了快速的應用程式啟動方式,可透過內嵌的Tomcat、Jetty或Undertow等容器快速啟動應用程式,無需額外的部署步驟,方便快捷。
自動化配置:Spring Boot透過自動配置功能,根據專案中的依賴關係和約定俗成的規則來配置應用程式,減少了配置的複雜性,使開發者更容易實現應用的最佳實踐。

SpringBoot比Spring好在哪裡

Spring Boot 提供了自動化配置,大大簡化了專案的配置過程。透過約定優於配置的原則,很多常用的配置可以自動完成,開發者可以專注於業務邏輯的實現。
Spring Boot 提供了快速的專案啟動器,透過引入不同的 Starter,可以快速整合常用的框架和庫(如資料庫、訊息佇列、Web 開發等),極大地提高了開發效率。
Spring Boot 預設整合了多種內嵌伺服器(如Tomcat、Jetty、Undertow),無需額外配置,即可將應用打包成可執行的 JAR 檔案,方便部署和執行。

怎麼理解SpringBoot中的約定大於配置

理解 Spring Boot 中的“約定大於配置”原則,可以從以下幾個方面來解釋:

自動化配置:Spring Boot 提供了大量的自動化配置,透過分析專案的依賴和環境,自動配置應用程式的行為。開發者無需顯式地配置每個細節,大部分常用的配置都已經預設好了。例如,Spring Boot 可以根據專案中引入的資料庫依賴自動配置資料來源。
預設配置:Spring Boot 在沒有明確配置的情況下,會使用合理的預設值來初始化應用程式。這種預設行為使得開發者可以專注於核心業務邏輯,而無需關心每個細節的配置。
約定優於配置:Spring Boot 遵循了約定優於配置的設計哲學,即透過約定好的方式來提供預設行為,減少開發者需要做出的決策。例如,約定了專案結構、Bean 命名規範等,使得開發者可以更快地上手並保持團隊間的一致性。
Spring Boot 的“約定大於配置”原則是一種設計理念,透過減少配置和提供合理的預設值,使得開發者可以更快速地構建和部署應用程式,同時降低了入門門檻和維護成本。

Spring Boot透過「自動化配置」和「起步依賴」實現了約定大於配置的特性。

自動化配置:Spring Boot根據專案的依賴和環境自動配置應用程式,無需手動配置大量的XML或Java配置檔案。例如,如果專案引入了Spring Web MVC依賴,Spring Boot會自動配置一個基本的Web應用程式上下文。
起步依賴:Spring Boot提供了一系列起步依賴,這些依賴包含了常用的框架和功能,可以幫助開發者快速搭建專案。透過引入適合專案需求的起步依賴,開發者可以

SpringBoot的專案結構是怎麼樣的?

一個正常的企業專案裡一種通用的專案結構和程式碼層級劃分的指導意見。按這《阿里巴巴Java開發手冊》時本書上說的,一般分為如下幾層:

img

開放介面層:可直接封裝 Service 介面暴露成 RPC 介面;透過 Web 封裝成 http 介面;閘道器控制層等。

終端顯示層:各個端的模板渲染並執行顯示的層。當前主要是 velocity 渲染,JS 渲染,JSP 渲染,移動端展示等。

Web 層:主要是對訪問控制進行轉發,各類基本引數校驗,或者不復用的業務簡單處理等。

Service 層:相對具體的業務邏輯服務層。

Manager 層:通用業務處理層,它有如下特徵

1)對第三方平臺封裝的層,預處理返回結果及轉化異常資訊,適配上層介面。

2)對 Service 層通用能力的下沉,如快取方案、中介軟體通用處理。

3)與 DAO 層互動,對多個 DAO 的組合複用。

DAO 層:資料訪問層,與底層 MySQL、Oracle、Hbase、OceanBase 等進行資料互動。

第三方服務:包括其它部門 RPC 服務介面,基礎平臺,其它公司的 HTTP 介面,如淘寶開放平臺、支付寶付款服務、高德地圖服務等。

外部介面:外部(應用)資料儲存服務提供的介面,多見於資料遷移場景中。

如果從一個使用者訪問一個網站的情況來看,對應著上面的專案程式碼結構來分析,可以貫穿整個程式碼分層:

img

對應程式碼目錄的流轉邏輯就是:

img

所以,以後每當我們拿到一個新的專案到手時,只要按照這個思路去看別人專案的程式碼,應該基本都是能理得順的。

SpringBoot自動裝配原理是什麼?

什麼是自動裝配?

SpringBoot 的自動裝配原理是基於Spring Framework的條件化配置和@EnableAutoConfiguration註解實現的。這種機制允許開發者在專案中引入相關的依賴,SpringBoot 將根據這些依賴自動配置應用程式的上下文和功能。

SpringBoot 定義了一套介面規範,這套規範規定:SpringBoot 在啟動時會掃描外部引用 jar 包中的META-INF/spring.factories檔案,將檔案中配置的型別資訊載入到 Spring 容器(此處涉及到 JVM 類載入機制與 Spring 的容器知識),並執行類中定義的各種操作。對於外部 jar 來說,只需要按照 SpringBoot 定義的標準,就能將自己的功能裝置進 SpringBoot。

通俗來講,自動裝配就是透過註解或一些簡單的配置就可以在SpringBoot的幫助下開啟和配置各種功能,比如資料庫訪問、Web開發。

SpringBoot自動裝配原理

首先點進 @SpringBootApplication 註解的內部

img

接下來將逐個解釋這些註解的作用:

@Target({ElementType.TYPE}): 該註解指定了這個註解可以用來標記在類上。在這個特定的例子中,這表示該註解用於標記配置類。
@Retention(RetentionPolicy.RUNTIME): 這個註解指定了註解的生命週期,即在執行時保留。這是因為 Spring Boot 在執行時掃描類路徑上的註解來實現自動配置,所以這裡使用了 RUNTIME 保留策略。
@Documented: 該註解表示這個註解應該被包含在 Java 文件中。它是用於生成文件的標記,使開發者能夠看到這個註解的相關資訊。
@Inherited: 這個註解指示一個被標註的型別是被繼承的。在這個例子中,它表明這個註解可以被繼承,如果一個類繼承了帶有這個註解的類,它也會繼承這個註解。
@SpringBootConfiguration: 這個註解表明這是一個 Spring Boot 配置類。如果點進這個註解內部會發現與標準的 @Configuration 沒啥區別,只是為了表明這是一個專門用於 SpringBoot 的配置。
@EnableAutoConfiguration: 這個註解是 Spring Boot 自動裝配的核心。它告訴 Spring oot 啟用自動配置機制,根據專案的依賴和配置自動配置應用程式的上下文。透過這個註解,SpringBoot 將嘗試根據類路徑上的依賴自動配置應用程式。
@ComponentScan: 這個註解用於配置元件掃描的規則。在這裡,它告訴 SpringBoot 在指定的包及其子包中查詢元件,這些元件包括被註解的類、@Component 註解的類等。其中的 excludeFilters 引數用於指定排除哪些元件,這裡使用了兩個自定義的過濾器,分別是 TypeExcludeFilter 和 AutoConfigurationExcludeFilter。
@EnableAutoConfiguration 這個註解是實現自動裝配的核心註解

img

@AutoConfigurationPackage,將專案src中main包下的所有元件註冊到容器中,例如標註了Component註解的類等
@Import({AutoConfigurationImportSelector.class}),是自動裝配的核心,接下來分析一下這個註解
AutoConfigurationImportSelector 是 Spring Boot 中一個重要的類,它實現了 ImportSelector 介面,用於實現自動配置的選擇和匯入。具體來說,它透過分析專案的類路徑和條件來決定應該匯入哪些自動配置類。

程式碼太多,選取部分主要功能的程式碼:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

// ... (其他方法和屬性)

// 獲取所有符合條件的類的全限定類名,例如RedisTemplate的全限定類名(org.springframework.data.redis.core.RedisTemplate;),這些類需要被載入到 IoC 容器中。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 掃描類路徑上的 META-INF/spring.factories 檔案,獲取所有實現了 AutoConfiguration 介面的自動配置類
List configurations = getCandidateConfigurations(annotationMetadata, attributes);

	// 過濾掉不滿足條件的自動配置類,比如一些自動裝配類
	configurations = filter(configurations, annotationMetadata, attributes);

	// 排序自動配置類,根據 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 註解指定的順序
	sort(configurations, annotationMetadata, attributes);

	// 將滿足條件的自動配置類的類名陣列返回,這些類將被匯入到應用程式上下文中
	return StringUtils.toStringArray(configurations);
}

// ... (其他方法)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
	// 獲取自動配置類的候選列表,從 META-INF/spring.factories 檔案中讀取
	// 透過類載入器載入所有候選類
	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
			getBeanClassLoader());

	// 過濾出實現了 AutoConfiguration 介面的自動配置類
	configurations = configurations.stream()
			.filter(this::isEnabled)
			.collect(Collectors.toList());

	// 對於 Spring Boot 1.x 版本,還需要新增 spring-boot-autoconfigure 包中的自動配置類
	// configurations.addAll(getAutoConfigEntry(getAutoConfigurationEntry(metadata)));
	return configurations;
}

// ... (其他方法)
protected List<String> filter(List<String> configurations, AnnotationMetadata metadata,
		AnnotationAttributes attributes) {
	// 使用條件判斷機制,過濾掉不滿足條件的自動配置類
	configurations = configurations.stream()
			.filter(configuration -> isConfigurationCandidate(configuration, metadata, attributes))
			.collect(Collectors.toList());
	return configurations;
}

// ... (其他方法)
protected void sort(List<String> configurations, AnnotationMetadata metadata,
		AnnotationAttributes attributes) {
	// 根據 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 註解指定的順序對自動配置類進行排序
	configurations.sort((o1, o2) -> {
		int i1 = getAutoConfigurationOrder(o1, metadata, attributes);
		int i2 = getAutoConfigurationOrder(o2, metadata, attributes);
		return Integer.compare(i1, i2);
	});
}

// ... (其他方法)

}
梳理一下,以下是AutoConfigurationImportSelector的主要工作:

掃描類路徑: 在應用程式啟動時,AutoConfigurationImportSelector 會掃描類路徑上的 META-INF/spring.factories 檔案,這個檔案中包含了各種 Spring 配置和擴充套件的定義。在這裡,它會查詢所有實現了 AutoConfiguration 介面的類,具體的實現為getCandidateConfigurations方法。

條件判斷: 對於每一個發現的自動配置類,AutoConfigurationImportSelector 會使用條件判斷機制(通常是透過 @ConditionalOnXxx註解)來確定是否滿足匯入條件。這些條件可以是配置屬性、類是否存在、Bean是否存在等等。

根據條件匯入自動配置類: 滿足條件的自動配置類將被匯入到應用程式的上下文中。這意味著它們會被例項化並應用於應用程式的配置。

說幾個啟動器(starter)

spring-boot-starter-web:這是最常用的起步依賴之一,它包含了Spring MVC和Tomcat嵌入式伺服器,用於快速構建Web應用程式。
spring-boot-starter-security:提供了Spring Security的基本配置,幫助開發者快速實現應用的安全性,包括認證和授權功能。
mybatis-spring-boot-starter:這個Starter是由MyBatis團隊提供的,用於簡化在Spring Boot應用中整合MyBatis的過程。它自動配置了MyBatis的相關元件,包括SqlSessionFactory、MapperScannerConfigurer等,使得開發者能夠快速地開始使用MyBatis進行資料庫操作。
spring-boot-starter-data-jpa 或 spring-boot-starter-jdbc:如果使用的是Java Persistence API (JPA)進行資料庫操作,那麼應該使用spring-boot-starter-data-jpa。這個Starter包含了Hibernate等JPA實現以及資料庫連線池等必要的庫,可以讓你輕鬆地與MySQL資料庫進行互動。你需要在application.properties或application.yml中配置MySQL的連線資訊。如果傾向於直接使用JDBC而不透過JPA,那麼可以使用spring-boot-starter-jdbc,它提供了基本的JDBC支援。
spring-boot-starter-data-redis:用於整合Redis快取和資料儲存服務。這個Starter包含了與Redis互動所需的客戶端(預設是Jedis客戶端,也可以配置為Lettuce客戶端),以及Spring Data Redis的支援,使得在Spring Boot應用中使用Redis變得非常便捷。同樣地,需要在配置檔案中設定Redis伺服器的連線詳情。
spring-boot-starter-test:包含了單元測試和整合測試所需的庫,如JUnit, Spring Test, AssertJ等,便於進行測試驅動開發(TDD)。

寫過SpringBoot starter嗎?

步驟1: 建立Maven專案

首先,需要建立一個新的Maven專案。在pom.xml中新增Spring Boot的starter parent和一些必要的依賴。例如:

org.springframework.boot spring-boot-starter-parent 2.7.0 org.springframework.boot spring-boot-starter-web 步驟2: 新增自動配置

在src/main/resources/META-INF/spring.factories中新增自動配置的後設資料。例如:

org.springframework.boot.autoconfigure.EnableAutoConfiguration = com.example.starter.MyAutoConfiguration
然後,建立MyAutoConfiguration類,該類需要@Configuration和@EnableConfigurationProperties註解。@EnableConfigurationProperties用於啟用你定義的配置屬性類。

@Configuration
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {

@Autowired
private MyProperties properties;

@Bean
public MyService myService() {
    return new MyServiceImpl(properties);
}

}
步驟3: 建立配置屬性類

建立一個配置屬性類,使用@ConfigurationProperties註解來繫結配置檔案中的屬性。

@ConfigurationProperties(prefix = "my")
public class MyProperties {
private String name;
// getters and setters
}
步驟4: 建立服務和控制器

建立一個服務類和服務實現類,以及一個控制器來展示你的starter的功能。

@Service
public interface MyService {
String getName();
}

@Service
public class MyServiceImpl implements MyService {
private final MyProperties properties;

public MyServiceImpl(MyProperties properties) {
    this.properties = properties;
}

@Override
public String getName() {
    return properties.getName();
}

}

@RestController
public class MyController {
private final MyService myService;

public MyController(MyService myService) {
    this.myService = myService;
}

@GetMapping("/name")
public String getName() {
    return myService.getName();
}

}
步驟5: 釋出Starter

將你的starter釋出到Maven倉庫,無論是私有的還是公共的,如Nexus或Maven Central。

步驟6: 使用Starter

在你的主應用的pom.xml中新增你的starter依賴,然後在application.yml或application.properties中配置你的屬性。

my:
name: Hello World

SpringBoot裡面有哪些重要的註解?還有一個配置相關的註解是哪個?

Spring Boot 中一些常用的註解包括:

@SpringBootApplication:用於標註主應用程式類,標識一個Spring Boot應用程式的入口點,同時啟用自動配置和元件掃描。
@Controller:標識控制器類,處理HTTP請求。
@RestController:結合@Controller和@ResponseBody,返回RESTful風格的資料。
@Service:標識服務類,通常用於標記業務邏輯層。
@Repository:標識資料訪問元件,通常用於標記資料訪問層。
@Component:通用的Spring元件註解,表示一個受Spring管理的元件。
@Autowired:用於自動裝配Spring Bean。
@Value:用於注入配置屬性值。
@RequestMapping:用於對映HTTP請求路徑到Controller的處理方法。
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping**:簡化@RequestMapping的GET、POST、PUT和DELETE請求。
另外,一個與配置相關的重要註解是:

@Configuration:用於指定一個類為配置類,其中定義的bean會被Spring容器管理。通常與@Bean配合使用,@Bean用於宣告一個Bean例項,由Spring容器進行管理。

springboot怎麼開啟事務?

在 Spring Boot 中開啟事務非常簡單,只需在服務層的方法上新增 @Transactional 註解即可。

例如,假設我們有一個 UserService 介面,其中有一個儲存使用者的方法 saveUser():

public interface UserService {
void saveUser(User user);
}
我們希望在這個方法中開啟事務,只需在該方法上新增 @Transactional 註解,如下所示:

public class UserServiceImpl implements UserService {

@Autowired
private UserRepository userRepository;

@Override
@Transactional
public void saveUser(User user) {
    userRepository.save(user);
}

}
這樣,當呼叫 saveUser() 方法時,Spring 就會自動為該方法開啟一個事務。如果方法執行成功,事務會自動提交;如果方法執行失敗,事務會自動回滾。

相關文章