手擼一個SpringBoot-Starter


1. 簡介

通過了解SpringBoot的原理后,我們可以手擼一個spring-boot-starter來加深理解。

1.1 什么是starter

spring官網解釋

  • starters是一組方便的依賴描述符(根據功能特點將用到的依賴標記封裝到同一個pom中),可以將其包含在應用程序中。
  • 通過starters可以獲取所需的所有Spring和相關技術的一站式服務,而無需搜索示例代碼或復制粘貼加載的依賴項描述符。

1.2 命名規則

官方首發都遵循類似的命名模式:spring-boot-starter-*,其中*是特定類型的應用程序,例如: spring-boot-starter-web

第三方啟動器不應以spring-boot開頭,因為它是為官方 Spring Boot 工件保留的,相反,第三方啟動器通常以項目名稱開頭,例如:ldx.spring-boot-starter

1.3 代碼結構

如圖,官方的spring-boot-starter Jar中其實沒有包含代碼,starter其實是就是一組依賴描述的集合,而其中主要包含的就是autoconfigure模塊和一些必要的依賴模塊。

spring-boot官方所有的auto-configuration-classes

springboot官方的starter中依賴如下:

當我們進入到官方autoconfiguration中查看redis配置源碼如下,而我們待會兒也會模仿RedisAutoConfiguration寫一個自己的starter

2. 開擼

spring官方學習地址

2.1 項目結構

結構說明:

├── redis-spring-boot-starter  # 自定義的starter模塊
│   ├── pom.xml
├── spring-boot-autoconfigure # 自定義的auto configure模塊
│   ├── pom.xml
│   └── src
│       └── main
│           ├── java
│           │   └── com
│           │       └── ldx
│           │           └── autoconfigure
│           │               └── config
│           │                   ├── RedisAutoConfiguration.java # redis 自動配置類
│           │                   └── RedisProperty.java  # redis property 參數綁定類
│           └── resources
│               └── META-INF
│                   └── spring.factories # spring自動裝配配置文件
└── test # 功能測試模塊
    ├── pom.xml
    ├── src
    │   └── main
    │       ├── java
    │       │   └── com
    │       │       └── ldx
    │       │           └── test
    │       │               └── TestApplication.java # 啟動類
    │       └── resources
    │           └── application.yaml # 資源文件

2.2 spring-boot-autoconfigure

正如簡介中提到的一樣,該模塊用於提供autoconfigure核心功能,通過META-INF/spring.factories實現對RedisAutoConfiguration.class的掃描,然后在RedisAutoConfiguration.class中實現Jedis的條件化注入,從而實現springboot的自動裝配功能。

2.2.1 導入依賴

spring-boot-autoconfigure-processor是一個注釋處理器,依賴用於生成META-INF/spring-autoconfigure-metadata.properties並且被包含在項目 jar 中,其文件記錄了當前classpath下所有的autoconfigure的元信息,在項目啟動時會先掃描此文件(如果存在),此文件有助於縮短啟動時間,但不是程序正常運行所必需的。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.ldx</groupId>
	<artifactId>spring-boot-autoconfigure</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-boot-autoconfigure</name>
	<description>自定義的 spring-boot-autoconfigure</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<!--引入redis客戶端 jedis依賴-->
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<!-- 防止當前依賴被傳遞引用 -->
			<optional>true</optional>
		</dependency>
		<!--自動配置注解注釋處理器,
		用於生成META-INF/spring-autoconfigure-metadata.properties包含在項目中-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-autoconfigure-processor</artifactId>
			<optional>true</optional>
		</dependency>
	</dependencies>
</project>

2.2.2 RedisProperty

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * redis 屬性注入類
 *
 * @author ludangxin
 * @date 2021/8/1
 */
@Data
// 用於讀取配置文件中的鏈接信息
@ConfigurationProperties(prefix = "redis")
public class RedisProperty {
   private String host = "localhost";

   private int port = 6379;
}

2.2.3 RedisAutoConfiguration

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import redis.clients.jedis.Jedis;

/**
 * redis 自動化配置類
 *
 * @author ludangxin
 * @date 2021/8/1
 */
@ConditionalOnClass(Jedis.class)
@EnableConfigurationProperties(RedisProperty.class)
public class RedisAutoConfiguration {

   @Bean
   @ConditionalOnMissingBean(Jedis.class)
   public Jedis jedis(RedisProperty redisProperty) {
      return new Jedis(redisProperty.getHost(), redisProperty.getPort());
   }
}

2.2.4 spring.factories

resources下創建META-INF/spring.factoriesEnableAutoConfiguration指向RedisAutoConfiguration

org.springframework.boot.autoconfigure.EnableAutoConfiguration = \
  com.ldx.autoconfigure.config.RedisAutoConfiguration

2.2.5 安裝依賴

將當前模塊打成Jar安裝到本地倉庫。

2.3 redis-spring-boot-starter

2.3.1 導入依賴

在其pom中添加我們剛才創建的spring-boot-autoconfigure模塊,並且添加jedis模塊(autoconfigure模塊中jedis不允許傳遞依賴因為將來autoconfigure文件中的會有各種各樣的第三方自動化配置,不可能全部傳遞依賴,只能是用到哪個的時候就自行在starter中添加哪個即可)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.ldx</groupId>
   <artifactId>redis-spring-boot-starter</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>redis-spring-boot-starter</name>
   <description>customize starter</description>
   <properties>
      <java.version>1.8</java.version>
   </properties>
   <dependencies>
      <!--引用自己創建的spring-boot-autoconfigure model-->
      <dependency>
         <groupId>com.ldx</groupId>
         <artifactId>spring-boot-autoconfigure</artifactId>
         <version>0.0.1-SNAPSHOT</version>
      </dependency>
      <!-- 引用jedis客戶端 -->
      <dependency>
         <groupId>redis.clients</groupId>
         <artifactId>jedis</artifactId>
         <version>3.6.3</version>
      </dependency>
   </dependencies>
</project>

2.3.2 安裝依賴

將當前模塊打成Jar安裝到本地倉庫。

2.4 test

test模塊為測試模塊,測試starter功能。

2.4.1 導入依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.5.3</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.ldx</groupId>
   <artifactId>test</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>test</name>
   <description>測試springboot-starter</description>
   <properties>
      <java.version>1.8</java.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
      </dependency>
      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <optional>true</optional>
      </dependency>
      <!-- 引用自己創建的redis-starter -->
      <dependency>
         <groupId>com.ldx</groupId>
         <artifactId>redis-spring-boot-starter</artifactId>
         <version>0.0.1-SNAPSHOT</version>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>
</project>

2.4.2 修改啟動類

package com.ldx.test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import redis.clients.jedis.Jedis;

@Slf4j
@SpringBootApplication
public class TestApplication {

	public static void main(String[] args) {
	    ConfigurableApplicationContext applicationContext = SpringApplication.run(TestApplication.class, args);
            // 獲取jedis bean
            Jedis jedis = applicationContext.getBean(Jedis.class);
            // add
	    jedis.set("name", "張三");
	    log.info(jedis.get("name"));
	}

}

2.4.3 啟動測試

啟動項目成功獲取到了設置的數據。

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.3)

2021-08-03 23:08:44.531  INFO 13930 --- [           main] com.ldx.test.TestApplication             : Starting TestApplication using Java 1.8.0_261 on ludangxindeMacBook-Pro.local with PID 13930 (/Users/ludangxin/workspace/idea/redis-starter/test/target/classes started by ludangxin in /Users/ludangxin/workspace/idea/redis-starter)
2021-08-03 23:08:44.532  INFO 13930 --- [           main] com.ldx.test.TestApplication             : No active profile set, falling back to default profiles: default
2021-08-03 23:08:45.062  INFO 13930 --- [           main] com.ldx.test.TestApplication             : Started TestApplication in 0.901 seconds (JVM running for 1.384)
2021-08-03 23:08:45.072  INFO 13930 --- [           main] com.ldx.test.TestApplication             : 張三

這時我們在test模塊的application.yaml文配置redis.port=123測試autoconfigure模塊能不能正常的獲取配置信息。
啟動項目報錯如下:

說明配置類正確的獲取到了錯誤的配置信息,符合預期,打完收工。

這時我們再回頭看下spring-boot-autoconfigure-processor依賴生產的元信息文件如下:

3. 小結

spring-boot-starter的出現,大大的提升了我們項目的搭建速度和質量(我們僅需導入依賴坐標,然后在配置文件中進行簡單的配置即可。再也不用因為依賴找不全,版本對不上,依賴沖突...而煩惱了),並且官方和第三方的starter簡化了我們對中間操作(提供了通用的template,整合了對數據庫比如jpa或者amqp等操作接口),簡直不要太爽。

當我們學習了如何創建自己的starter后,也可以封裝我們自己的starter用於項目的建設和使用。

SpringBoot內置Starter

官方地址介紹地址 github源碼地址

名稱 描述
spring-boot-starter 核心啟動器,包括自動配置支持、日志記錄和 YAML
spring-boot-starter-activemq 使用 Apache ActiveMQ 的 JMS 消息傳遞入門
spring-boot-starter-amqp 使用 Spring AMQP 和 Rabbit MQ 的入門者
spring-boot-starter-aop 使用 Spring AOP 和 AspectJ 進行面向方面編程的入門者
spring-boot-starter-artemis 使用 Apache Artemis 進行 JMS 消息傳遞的入門者
spring-boot-starter-batch 使用 Spring Batch 的啟動器
spring-boot-starter-cache 使用 Spring Framework 的緩存支持的 Starter
spring-boot-starter-data-cassandra Starter 使用 Cassandra 分布式數據庫和 Spring Data Cassandra
spring-boot-starter-data-cassandra-reactive Starter 使用 Cassandra 分布式數據庫和 Spring Data Cassandra Reactive
spring-boot-starter-data-couchbase 使用 Couchbase 面向文檔的數據庫和 Spring Data Couchbase 的入門者
spring-boot-starter-data-couchbase-reactive Starter 使用 Couchbase 面向文檔的數據庫和 Spring Data Couchbase Reactive
spring-boot-starter-data-elasticsearch 使用 Elasticsearch 搜索和分析引擎以及 Spring Data Elasticsearch 的入門者
spring-boot-starter-data-jdbc 使用 Spring Data JDBC 的入門者
spring-boot-starter-data-jpa 將 Spring Data JPA 與 Hibernate 結合使用的入門者
spring-boot-starter-data-ldap 使用 Spring Data LDAP 的入門者
spring-boot-starter-data-mongodb 使用 MongoDB 面向文檔的數據庫和 Spring Data MongoDB 的入門者
spring-boot-starter-data-mongodb-reactive Starter 使用 MongoDB 面向文檔的數據庫和 Spring Data MongoDB Reactive
spring-boot-starter-data-neo4j 使用 Neo4j 圖形數據庫和 Spring Data Neo4j 的入門者
spring-boot-starter-data-r2dbc 使用 Spring Data R2DBC 的啟動器
spring-boot-starter-data-redis 將 Redis 鍵值數據存儲與 Spring Data Redis 和 Lettuce 客戶端一起使用的入門者
spring-boot-starter-data-redis-reactive 將 Redis 鍵值數據存儲與 Spring Data Redis 反應式和 Lettuce 客戶端一起使用的入門者
spring-boot-starter-data-rest 使用 Spring Data REST 在 REST 上公開 Spring Data 存儲庫的啟動器
spring-boot-starter-freemarker 使用 FreeMarker 視圖構建 MVC Web 應用程序的入門者
spring-boot-starter-groovy-templates 使用 Groovy 模板視圖構建 MVC Web 應用程序的入門者
spring-boot-starter-hateoas 使用 Spring MVC 和 Spring HATEOAS 構建基於超媒體的 RESTful Web 應用程序的入門者
spring-boot-starter-integration 使用 Spring Integration 的入門者
spring-boot-starter-jdbc 將 JDBC 與 HikariCP 連接池一起使用的 Starter
spring-boot-starter-jersey 使用 JAX-RS 和 Jersey 構建 RESTful Web 應用程序的初學者。替代方案spring-boot-starter-web
spring-boot-starter-jooq 使用 jOOQ 訪問 SQL 數據庫的入門者。spring-boot-starter-data-jpa或的替代品spring-boot-starter-jdbc
spring-boot-starter-json 讀寫json的Starter
spring-boot-starter-jta-atomikos 使用 Atomikos 的 JTA 事務入門
spring-boot-starter-mail 使用 Java Mail 的 Starter 和 Spring Framework 的電子郵件發送支持
spring-boot-starter-mustache 使用 Mustache 視圖構建 Web 應用程序的入門者
spring-boot-starter-oauth2-client 使用 Spring Security 的 OAuth2/OpenID Connect 客戶端功能的入門者
spring-boot-starter-oauth2-resource-server 使用 Spring Security 的 OAuth2 資源服務器功能的入門者
spring-boot-starter-quartz 使用 Quartz 調度器的啟動器
spring-boot-starter-rsocket 用於構建 RSocket 客戶端和服務器的 Starter
spring-boot-starter-security 使用 Spring Security 的入門者
spring-boot-starter-test Starter 用於使用包括 JUnit Jupiter、Hamcrest 和 Mockito 在內的庫測試 Spring Boot 應用程序
spring-boot-starter-thymeleaf 使用 Thymeleaf 視圖構建 MVC Web 應用程序的初學者
spring-boot-starter-validation 將 Java Bean 驗證與 Hibernate Validator 結合使用的入門工具
spring-boot-starter-web 使用 Spring MVC 構建 Web(包括 RESTful)應用程序的入門者。使用 Tomcat 作為默認的嵌入式容器
spring-boot-starter-web-services 使用 Spring Web 服務的入門者
spring-boot-starter-webflux 使用 Spring Framework 的 Reactive Web 支持構建 WebFlux 應用程序的 Starter
spring-boot-starter-websocket 使用 Spring Framework 的 WebSocket 支持構建 WebSocket 應用程序的 Starter

除了應用程序啟動器之外,以下啟動器還可用於添加生產就緒功能:

名稱 描述
spring-boot-starter-actuator 使用 Spring Boot 的 Actuator 的 Starter,它提供了生產就緒的特性來幫助你監控和管理你的應用程序

最后,Spring Boot 還包括以下啟動器,如果您想排除或交換特定的技術方面,可以使用它們:

名稱 描述
spring-boot-starter-jetty 使用 Jetty 作為嵌入式 servlet 容器的啟動器。替代方案spring-boot-starter-tomcat
spring-boot-starter-log4j2 使用 Log4j2 進行日志記錄的啟動器。替代方案spring-boot-starter-logging
spring-boot-starter-logging 使用 Logback 進行日志記錄的啟動器。默認日志記錄啟動器
spring-boot-starter-reactor-netty 使用 Reactor Netty 作為嵌入式響應式 HTTP 服務器的啟動器。
spring-boot-starter-tomcat 使用 Tomcat 作為嵌入式 servlet 容器的啟動器。使用的默認 servlet 容器啟動器spring-boot-starter-web
spring-boot-starter-undertow 使用 Undertow 作為嵌入式 servlet 容器的啟動器。替代方案spring-boot-starter-tomcat


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM