日常咱們使用SpringBoot開發常常用到一些第三方jar包,並且一般只是引入一個xxx-starter
jar包就擁有了全部功能,到底其中的原理是怎樣的呢?要想知道其中的原理,咱們不妨先本身手動製做一個Starter
,這對咱們深刻使用一些第三框架將會有至關大的幫助。html
SpringBoot官網文檔提到的規範大體由下面幾個:java
spring-boot-starter-xxx
,其中xxx
是咱們具體的包名稱,若是集成Spring Cloud
則使用spring-cloud-starter-xxx
jar
文件,其中一個不包含任何代碼,只用於負責引入相關以來的jar文件,另一個則包含核心的代碼如nacos
與Spring Cloud集成的starter以下圖:web
更多Starter
製做規範,咱們能夠查看官網文檔spring
首先咱們應該先明白Springboot加載第三方Starter
的機制,詳情請參考小編的另一篇文章SpringBoot啓動源碼分析及相關技巧學習sql
Maven
工程,咱們起名爲study-spring-boot-starter
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<!-- 咱們是基於Springboot的應用 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
複製代碼
由於咱們須要用到Springboot提供的相關注解,而且使用springboot提供的自動配置功能,咱們不得不引入spring-boot-autoconfigure
和spring-boot-dependencies
兩個依賴。springboot
通常來講,咱們可能想在springboot啓動的時候就預先注入本身的一些bean,此時,咱們要新建本身的自動配置類,通常採用xxxxEnableAutoConfiguration
。bash
下面咱們新建StudyStarterAutoConfiguration.java
session
package com.example.mystarter.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.example.mystarter.other.Student;
/**
* 存放咱們的配置類,用來配置咱們自定義的bean的。既然是一個配置類,那麼咱們就須要有@Configuration進行聲明
*
* @Author jiawei huang
* @Since 2019年8月23日
* @Version 1.0
*/
@Configuration
// 導入咱們自定義的配置類,供當前類使用
@EnableConfigurationProperties(StudentConfigProperties.class)
// 當存在某個類時,此自動配置類纔會生效,這裏可使用外部的String類名
@ConditionalOnClass(Student.class)
// 只有web應用程序時此自動配置類纔會生效
@ConditionalOnWebApplication
public class StudyStarterAutoConfiguration {
/**
* 當存在study.config.enable=true的配置時,這個Student bean才生效
*
* @return
*/
@Bean
@ConditionalOnProperty(prefix = "study.config", name = "enable", havingValue = "true")
public Student defaultStudent(StudentConfigProperties studyConfigProperties) {
Student student = new Student();
student.setAge(studyConfigProperties.getAge());
student.setName(studyConfigProperties.getName());
return student;
}
}
複製代碼
@Configuration
聲明該類爲一個配置類mybatis
@EnableConfigurationProperties
的意思是,將括號內所指定的類注入容器成爲一個bean對象,由於通常來講,像springboot默認的包掃描路徑爲xxxxxxApplication.java
所在包以及其全部子包,可是一些第三方的jar中的bean很明顯不能被掃描到,此時該註解就派上了用場,固然,你可能會說,我使用@ComponentScan
不就好了,這兩個註解的區別是:@ComponentScan
前提是你要的bean已經存在bean容器中了,而@EnableConfigurationProperties
是要讓容器自動去發現你要類並註冊成爲bean。app
springboot提供了不少的@Condition
開頭的註解,用於表示當某某條件成立或者不成立時所作的操做。
@ConditionalOnClass
指的是當存在某個類時,此自動配置類StudyStarterAutoConfiguration
纔會生效,咱們可能會問,咱們有時候想依賴一個第三方的bean存在,StudyStarterAutoConfiguration
才生效怎麼辦(好比mybatis
的starter
源碼須要sqlsessionfactorybean
同樣),不用慌,@ConditionalOnClass
也容許咱們指定字符串全路徑,例如@ConditionalOnClass("com.xxx.xxx")
@ConditionalOnWebApplication
表示噹噹前應用是一個web servlet應用時,配置類才生效。這也能夠解答爲何springboot源碼SpringApplication.java
中有作應用推斷。
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 這裏會去作推斷
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
複製代碼
StudentConfigProperties.java
,聲明該starter的使用者能夠配置哪些配置項。package com.example.mystarter.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 配置項
*
* @Author jiawei huang
* @Since 2019年8月23日
* @Version 1.0
*/
@ConfigurationProperties(prefix = "study.config")
public class StudentConfigProperties {
private int age;
private String name;
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "StudentConfigProperties [age=" + age + ", name=" + name + "]";
}
}
複製代碼
resources
目錄下新建一個META-INF
目錄而且建立一個spring.factories
文件org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.mystarter.config.StudyStarterAutoConfiguration
複製代碼
咱們的自動配置入口類,Springboot會掃描到這個文件,掃描機制能夠查看小編寫的另一篇博文
Starter
starter
<dependency>
<groupId>com.example</groupId>
<artifactId>study</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
複製代碼
咱們新建一個接口,來測試咱們的starter是有有用,代碼以下:
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.mystarter.config.StudentConfigProperties;
import com.example.mystarter.other.Student;
/**
*
* @Author jiawei huang
* @Since 2019年8月19日
* @Version 1.0
*/
@RestController
public class MyController {
@Autowired
private Student student;
@Autowired
private StudentConfigProperties studentConfigProperties;
@RequestMapping("/getStudent")
private String getStudent() {
return "name=[" + student.getName() + "],age=[" + student.getAge() + "],studentConfigProperties=["
+ studentConfigProperties + "]";
}
}
複製代碼
啓動咱們的demo工程,而後訪問咱們的接口,結果以下:
好了,咱們的starter製做到此就結束了,其實很是簡單,我建議在學會製做的基礎上,多看看其餘框架的源碼加以驗證,最好可以也動手實現如下,說不定之後咱們也須要提供一個starer給其餘人用呢。有疑問,歡迎評論區交流,謝謝閱讀。