javascript
你还不会手写SpringBoot启动器吗
Starter是什么 ?
Spring Boot 對比 Spring MVC 最大的優點就是使用簡單,約定大于配置。不用 Spring MVC 的時候,時不時被 xml 配置文件搞的暈頭轉向,冷不防還因為 xml 配置上的一點疏忽,導致整個項目莫名其妙的不可用,頓感生無可戀。這要歸功于Spring Boot 的各種各樣的 starters,有官方提供以及第三方開源出來的。這些依賴模塊都遵循著約定成俗的默認配置,并允許我們根據自身情況調整這些配置。基本上你打算用的功能都可以找到,如果沒有找到,那就請再找一找。SpringBoot 會自動掃描需要加載的信息并啟動相應的默認配置。
Starter 提供了以下功能:
- 整合了模塊需要的所有依賴,統一集合到 Starter 中。
- 提供了默認配置,并允許我們調整這些默認配置。
- 提供了自動配置類對模塊內的 Bean 進行自動裝配,注入 Spring 容器中。
Starter 命名規則
Spring 官方定義的 Starter 通常命名遵循的格式為 spring-boot-starter-{name},例如 spring-boot-starter-data-mongodb。Spring 官方建議,非官方 Starter 命名應遵循 {name}-spring-boot-starter 的格式,例如,myjson-spring-boot-starter。
Starter可以用來解決什么問題?
日常開發中有一些獨立于業務系統之外的配置模塊,它是可以在不同項目中進行復用的。如果在每個項目中都編寫重復的模塊代碼,除了浪費時間和人力耦合性還高。將這些可獨立于業務代碼之外的功能配置模塊封裝成一個 Starter,在需要用到此功能模塊的項目中,只需要在其 pom.xml 文件中引用依賴即可。
手寫SpringBoot啟動器的主要步驟
pom文件依賴
| <?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.4.4</version> ??????? <relativePath/> <!-- lookup parent from repository --> ??? </parent> ??? <groupId>com.example</groupId> ??? <artifactId>my-starter</artifactId> ??? <version>0.0.1-SNAPSHOT</version> ??? <name>my-starter</name> ??? <description>Demo project for Spring Boot</description> ??? <properties> ??????? <java.version>1.8</java.version> ??? </properties> ? ??<dependencies> ??????? <dependency> ??????????? <groupId>com.example</groupId> ??????????? <artifactId>myjson-spring-boot-starter-autoconfigurer</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> |
?
| <?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.4.4</version> ? ??????<relativePath/> <!-- lookup parent from repository --> ??? </parent> ??? <groupId>com.example</groupId> ??? <artifactId>myjson-spring-boot-starter-autoconfigurer</artifactId> ??? <version>0.0.1-SNAPSHOT</version> ??? <name>myjson-spring-boot-starter-autoconfigurer</name> ??? <description>Demo project for Spring Boot</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.springframework.boot</groupId> ??????????? <artifactId>spring-boot-configuration-processor</artifactId> ??????????? <version>2.3.8.RELEASE</version> ??????????? <optional>true</optional> ??????? </dependency> ????? ??<dependency> ??????????? <groupId>com.alibaba</groupId> ??????????? <artifactId>fastjson</artifactId> ??????????? <version>1.2.73</version> ??????? </dependency> ??????? <dependency> ??????????? <groupId>org.springframework.boot</groupId> ??????????? <artifactId>spring-boot-autoconfigure</artifactId> ??????????? <version>2.3.8.RELEASE</version> ??????? </dependency> ??????? <dependency> ??????????? <groupId>org.springframework.boot</groupId> ??????????? <artifactId>spring-boot-starter-test</artifactId> ??????????? <scope>test</scope> ??????? </dependency> ??? </dependencies> ? ??? <build> ??????? <plugins> ??????????? <plugin> ??????????????? <groupId>org.springframework.boot</groupId> ??????????????? <artifactId>spring-boot-maven-plugin</artifactId> ??????????????? <configuration> ??????????????????? <mainClass>com.example.myjson.MyjsonApplication</mainClass> ????????????????? ??<skip>true</skip> ??????????????? </configuration> ??????????? </plugin> ??????? </plugins> ??? </build> ? </project> |
加紅色的三個依賴,fastjson是我們需要的第三方依賴,其他的spring-boot-configuration-processor 依賴是可選的,加入此依賴主要是打包時,自動生成配置元信息文件 META-INF/spring-configuration-metadata.json,并放入到 jar 中。綠色的artifact是我們自定義starter的名稱,藍色的插件依賴是我們
| public class MyJsonService { ??? private String prefixName; ??? private String suffixName; ? ??? public String getPrefixName() { ??????? return prefixName; ??? } ? ??? public void setPrefixName(String prefixName) { ??????? this.prefixName = prefixName; ??? } ? ??? public String getSuffixName() { ??????? return suffixName; ??? } ? ??? public void setSuffixName(String suffixName) { ??????? this.suffixName = suffixName; ??? } ? ??? public String objectToMyJson(Object obj) { ??????? return prefixName + JSON.toJSONString(obj) + suffixName; ??? } } |
?
| public class Person { ??? private String name; ??? private int age; ??? private String address; ??? public Person(String name, int age, String address) { ??????? super(); ??????? this.name = name; ??????? this.age = age; ??????? this.address = address; ??? } ? ??? public String getName() { ??????? return name; ??? } ? ??? public void setName(String name) { ??????? this.name = name; ??? } ? ??? public int getAge() { ??????? return age; ??? } ? ??? public void setAge(int age) { ??????? this.age = age; ??? } ? ??? public String getAddress() { ??????? return address; ??? } ? ??? public void setAddress(String address) { ??????? this.address = address; ??? } } |
?
| /** ?* @author:cp ?* @time:2021-4-12 ?* @Description: 配置類(類名一般為模塊名+Properties) cp.json為Starter使用者通過yml配置文件動態修改屬性值的變量名前綴 ?*/ @ConfigurationProperties(prefix = "cp.json") public class MyJsonProperties { ??? // Starter使用者沒在配置文件中配置prefixName屬性的值時的默認值 ??? public static final String DEFAULT_PREFIX_NAME = "@"; ? ??? // Starter使用者沒在配置文件中配置suffixName屬性的值時的默認值 ??? public static final String DEFAULT_SUFFIX_NAME = "#"; ??? private String prefixName = DEFAULT_PREFIX_NAME; ??? private String suffixName = DEFAULT_SUFFIX_NAME; ? ??? public String getPrefixName() { ??????? return prefixName; ??? } ? ??? public void setPrefixName(String prefixName) { ??????? this.prefixName = prefixName; ??? } ? ??? public String getSuffixName() { ??????? return suffixName; ??? } ? ??? public void setSuffixName(String suffixName) { ??????? this.suffixName = suffixName; ??? } } |
?
| package com.example.myjson.config; ? import com.example.myjson.service.MyJsonService; 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 org.springframework.context.annotation.Configuration; ? /** ?* @author:cp ?* @time:2021-4-12 ?* @Description: 自動裝配類 ?*/ @Configuration @ConditionalOnClass(MyJsonService.class) // 表示只有指定的class在classpath上時才能被注冊 @EnableConfigurationProperties(MyJsonProperties.class) // 激活被@ConfigurationProperties注解修飾的類 public class MyJsonConfiguration { ??? private MyJsonProperties myJsonProperties; ? ??? // 自動注入配置類 ??? public MyJsonConfiguration(MyJsonProperties myJsonProperties) { ??????? this.myJsonProperties = myJsonProperties; ??? } ? ??? // 創建MyJsonService對象,注入到Spring容器中 ??? @Bean ??? @ConditionalOnMissingBean(MyJsonService.class)? // 當容器沒有此bean時,才注冊 ??? public MyJsonService myJsonService() { ??????? MyJsonService myJsonService = new MyJsonService(); ??????? myJsonService.setPrefixName(myJsonProperties.getPrefixName()); ??????? myJsonService.setSuffixName(myJsonProperties.getSuffixName()); ??????? return myJsonService; ??? } } |
?
| org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.myjson.config.MyJsonConfiguration |
?
| <?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.4.4</version> ??????? <relativePath/> <!-- lookup parent from repository --> ??? </parent> ??? <groupId>com.example</groupId> ??? <artifactId>kk</artifactId> ??? <version>0.0.1-SNAPSHOT</version> ??? <name>kk</name> ??? <description>Demo project for Spring Boot</description> ??? <properties> ??????? <java.version>1.8</java.version> ??? </properties> ??? <dependencies> ??????? <dependency> ??????????? <groupId>org.springframework.boot</groupId> ??????????? <artifactId>spring-boot-starter-web</artifactId> ??????? </dependency> ?????? ?<dependency> ??????????? <groupId>com.example</groupId> ??????????? <artifactId>myjson-spring-boot-starter-autoconfigurer</artifactId> ??????????? <version>0.0.1-SNAPSHOT</version> ??????? </dependency> ??????? <dependency> ??????????? <groupId>org.springframework.boot</groupId> ??????????? <artifactId>spring-boot-starter-test</artifactId> ??????????? <scope>test</scope> ??????? </dependency> ??? </dependencies> ? ??? <build> ??????? <plugins> ??????????? <plugin> ??????????????? <groupId>org.springframework.boot</groupId> ??????????????? <artifactId>spring-boot-maven-plugin</artifactId> ??????????? </plugin> ??????? </plugins> ??? </build> ? </project> |
?
| cp: ? json: ??? prefix-name: hello ??? suffix-name: world |
?
| @RestController @RequestMapping("demo") public class DemoController { ??? @Autowired ??? private MyJsonService myJsonService; ? ??? @GetMapping() ??? public String test() { ? ??????Person p = new Person(“千與千尋” , 18, "拉斯維加斯"); ??????? // 調用服務方法 ??????? return myJsonService.objectToMyJson(p); ??? } } |
引入我們自定義啟動器中的業務service類,啟動springboot工程,訪問http://localhost:8080/demo,驗證我們的service類即可。
中間問題點:在打包自定義啟動器類jar包本地倉庫時,沒有添加構建插件,導致生成包多了一個BOOT-INF的文件,無法被其他工程引用導入自定義service類:添加如下構建插件后問題解決:
| <build> ??????? <plugins> ??????????? <plugin> ??????????????? <groupId>org.springframework.boot</groupId> ??????????????? <artifactId>spring-boot-maven-plugin</artifactId> ??????????????? <configuration> ??????????????????? <mainClass>com.example.myjson.MyjsonApplication</mainClass> ??????????????????? <skip>true</skip> ??? ????????????</configuration> ??????????? </plugin> ??????? </plugins> ??? </build> |
?
?
總結
以上是生活随笔為你收集整理的你还不会手写SpringBoot启动器吗的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TreeMap的讲解
- 下一篇: file相对路径java_浅谈java