SpringBoot封裝咱們本身的Starter

日常咱們使用SpringBoot開發常常用到一些第三方jar包,並且一般只是引入一個xxx-starterjar包就擁有了全部功能,到底其中的原理是怎樣的呢?要想知道其中的原理,咱們不妨先本身手動製做一個Starter,這對咱們深刻使用一些第三框架將會有至關大的幫助。html

1、SpringBoot Starter開發規範

SpringBoot官網文檔提到的規範大體由下面幾個:java

  • 一、命名使用spring-boot-starter-xxx,其中xxx是咱們具體的包名稱,若是集成Spring Cloud則使用spring-cloud-starter-xxx
  • 二、一般須要準備兩個jar文件,其中一個不包含任何代碼,只用於負責引入相關以來的jar文件,另一個則包含核心的代碼

nacos與Spring Cloud集成的starter以下圖:web

更多Starter製做規範,咱們能夠查看官網文檔spring

2、Starter開發開發步驟

首先咱們應該先明白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-autoconfigurespring-boot-dependencies兩個依賴。springboot

  • 三、新建咱們本身的自動配置類

通常來講,咱們可能想在springboot啓動的時候就預先注入本身的一些bean,此時,咱們要新建本身的自動配置類,通常採用xxxxEnableAutoConfigurationbash

下面咱們新建StudyStarterAutoConfiguration.javasession

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才生效怎麼辦(好比mybatisstarter源碼須要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會掃描到這個文件,掃描機制能夠查看小編寫的另一篇博文

3、使用咱們本身的Starter

  • 一、咱們新建另一個springboot工程,引入剛剛的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給其餘人用呢。有疑問,歡迎評論區交流,謝謝閱讀。

相關文章
相關標籤/搜索