前言
????????最近在學習Spring Boot相關的課程拨齐,過程中以筆記的形式記錄下來,方便以后回憶盛嘿,同時也在這里和大家探討探討洛巢,文章中有漏的或者有補充的、錯誤的都希望大家能夠及時提出來次兆,本人在此先謝謝了稿茉!
開始之前呢,希望大家?guī)е鴰讉€問題去學習:
1芥炭、SpringBoot Starter 是什么漓库?
2、這個功能有什么用园蝠?
3渺蒿、怎么實現(xiàn)的?
4彪薛、這個功能能應用在工作中茂装?
這是對自我的提問怠蹂,我認為帶著問題去學習佩厚,是一種更好的學習方式氢烘,有利于加深理解。好了咱筛,接下來進入主題彼妻。
1嫌佑、起源
????????在 Spring
時代,搭建一個 Web 應用通常需要在 pom 文件中引入多個 Web 模塊相關的 Maven
依賴侨歉,如 SpringMvc
屋摇、Tomcat
等依賴,而 SpringBoot
則只需引入 spring-boot-starter-web
依賴即可幽邓。這就是 SpringBoot
的 Starter 特性炮温,用來簡化項目初始搭建以及開發(fā)過程,它是一個功能模塊的所有 Maven 依賴集合體颊艳。接下來茅特,我們進行詳細討論。
注:本篇文章所用到的 Spring Boot版本是 2.0.3.RELEASE
2棋枕、SpringBoot Starter 原理
????????SpringBoot
提供了非常多的 Starter白修,下面列出常用的幾個:
名稱 | 功能 |
---|---|
spring-boot-starter-web | 支持 Web 開發(fā),包括 Tomcat 和 spring-webmvc |
spring-boot-starter-redis | 支持 Redis 鍵值存儲數(shù)據(jù)庫重斑,包括 spring-redis |
spring-boot-starter-test | 支持常規(guī)的測試依賴兵睛,包括 JUnit、Hamcrest窥浪、Mockito 以及 spring-test 模塊 |
spring-boot-starter-aop | 支持面向切面的編程即 AOP祖很,包括 spring-aop 和 AspectJ |
spring-boot-starter-data-elasticsearch | 支持 ElasticSearch 搜索和分析引擎,包括 spring-data-elasticsearch |
spring-boot-starter-jdbc | 支持JDBC數(shù)據(jù)庫 |
spring-boot-starter-data-jpa | 支持 JPA 漾脂,包括 spring-data-jpa假颇、spring-orm、Hibernate |
可以看到這些 Starter 的名稱都是以 spring-boot-starter 為開頭骨稿,后面跟著具體的模塊名笨鸡,所有官方的 Starter 遵循相似的命名模式。這些 Starter 其實不包含 Java 代碼坦冠,核心是它的 pom 文件形耗。我們以 spring-boot-starter-web
為例,來看看該 Starter 的 pom 文件包含的內容辙浑。
先在項目中引入以下依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
然后找到引入的 spring-boot-starter-web 依賴的文件夾位置:
打開該 pom 文件進行查看:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.3.RELEASE</version>
<name>Spring Boot Web Starter</name>
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.0.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- 對 json 解析的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.0.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- 提供 Tomcat 容器激涤。通過這可以看到 ServletWeb 默認的容器是 Tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.0.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- hibernate 的校驗框架 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.10.Final</version>
<scope>compile</scope>
</dependency>
<!-- 提供了核心 HTTP 集成,用于集成其它 web 框架的基礎結構 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- 提供了對 Spring MVC 的支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.7.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
可以看到判呕,在該 pom 文件中已經(jīng)定義好了 Web 模塊需要的各個組件倦踢。之后送滞,引入的 Starter 依賴可以與 SpringBoot
的自動裝配特性、外部化配置特性進行無縫銜接硼一,來達到快速開發(fā)的目的累澡。關于 SpringBoot
自動裝配和外部化配置大家可以分別參考《SpringBoot 自動裝配(二)》和《SpringBoot 外部化配置(二)》這兩篇文章。接下來般贼,通過實現(xiàn)自定義的 Starter 來理解整體邏輯。
3奥吩、自定義 Starter
????????先創(chuàng)建一個項目哼蛆,在該項目中定義 Starter 的內容,然后通過 Maven 將其打成 jar 包霞赫,之后在另一個項目中使用該 Starter 腮介。
3.1 創(chuàng)建 Starter
1、創(chuàng)建一個 Maven 項目端衰,在其 pom 文件中引入自動裝配的依賴叠洗,并定義好 Starter 的名稱。非官方的 Starter 命名需遵循 xxx-spring-boot-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.loong</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>1.0.0.RELEASE</version>
<name>demo</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
</dependencies>
</project>
2灭抑、新建一個 Properties
配置類,用于保存外部化配置文件中定義的配置數(shù)據(jù)抵代,其中配置文件包括 properties 或 yml 腾节。
// 定義配置文件中的屬性前綴
@ConfigurationProperties(prefix = "demo")
public class DemoProperties {
private String name;
private String date;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
關于外部化配置底層實現(xiàn),大家可以參考《SpringBoot 外部化配置(二)》這篇文章荤牍。
3案腺、新建一個功能類,主要用來返回 DemoProperties
中的 name 和 date 屬性康吵。
public class DemoService {
private DemoProperties demoProperties;
public DemoService(DemoProperties demoProperties) {
this.demoProperties = demoProperties;
}
public String getName() {
return demoProperties.getName();
}
public String getDate() {
return demoProperties.getDate();
}
}
4劈榨、創(chuàng)建自動配置類,在該配置類中完成 Starter 的功能晦嵌。這里同辣,通過構造器注入 DemoProperties
配置類對象,并初始化 DemoService
功能類耍铜。
@Configuration
@EnableConfigurationProperties(value = DemoProperties.class)
public class DemoAutoConfiguration {
private final DemoProperties demoProperties;
public DemoAutoConfiguration(DemoProperties demoProperties) {
this.demoProperties = demoProperties;
}
@Bean
// 當前項目是否包含 DemoService Class
@ConditionalOnMissingBean(DemoService.class)
public DemoService demoService() {
return new DemoService(demoProperties);
}
}
自動配置類是 SpringBoot
自動裝配特性不可或缺的一環(huán)邑闺,關于 SpringBoot
自動裝配底層實現(xiàn),大家可以參考《SpringBoot 自動裝配(二)》這篇文章棕兼。
5陡舅、自定義初始化器和監(jiān)聽器,這是 SpringBoot
提供的擴展點伴挚,主要在 SpringBoot
的不同生命周期執(zhí)行相應操作靶衍。
public class DemoApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
System.out.println(" DemoApplicationContextInitializer 初始化成功 ");
}
}
public class DemoApplicationListener implements ApplicationListener<SpringApplicationEvent> {
@Override
public void onApplicationEvent(SpringApplicationEvent springApplicationEvent) {
if (springApplicationEvent instanceof ApplicationStartingEvent) {
System.out.println(" DemoApplicationListener 監(jiān)聽 ApplicationStartingEvent 事件");
}
}
}
關于初始化器和監(jiān)聽器大家可以參考《Spring Boot SpringApplication啟動類(一)》的 2.2 和 2.3 小節(jié) 灾炭。
6、在 src/main/resources 目錄下創(chuàng)建 META-INF 文件夾颅眶,并在文件夾中創(chuàng)建 spring.factories
文件蜈出,定義如下內容:
# Initializers
org.springframework.context.ApplicationContextInitializer=\
com.loong.demo.context.DemoApplicationContextInitializer
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.loong.demo.configuration.DemoAutoConfiguration
# Application Listeners
org.springframework.context.ApplicationListener=\
com.loong.demo.listener.DemoApplicationListener
這是 SpringBoot
的規(guī)約,當我們自定義的初始化器涛酗、監(jiān)聽器及自動配置類需要被 SpringBoot
讀取時铡原,必須定義成該格式。關于原理商叹,在前幾篇文章說過燕刻,這里不再敘述。
最后剖笙,所有的類已經(jīng)定義完成卵洗,項目結構如下:
打開通過右側的 Maven 工具欄,點擊 install 打包到本地的 Maven 庫弥咪。
之后过蹂,自定義的 Starter 就可以使用,我們來測試一下聚至。
3.2 測試自定義 Starter
1酷勺、在另一個項目中引入該 Starter 的 Maven 依賴:
<dependency>
<groupId>com.loong</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
2、在 properties 文件中定義配置數(shù)據(jù):
demo.name = loong
demo.date = 2020.01.01
3晚岭、在啟動類中鸥印,獲取 DemoService
Bean ,并調用它的 getDate 和 getName 方法獲取配置文件中的數(shù)據(jù):
@SpringBootApplication
public class DiveInSpringBootApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(DiveInSpringBootApplication.class, args);
DemoService bean = run.getBean(DemoService.class);
System.out.println(bean.getDate() + " === " + bean.getName());
}
}
最后坦报,查看控制臺的輸出:
/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA CE.app...
DemoApplicationListener 監(jiān)聽 ApplicationStartingEvent 事件
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.3.RELEASE)
DemoApplicationContextInitializer 初始化成功
2020-01-01 13:14:02.023 INFO 55657 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2020-01-01 13:14:02.189 INFO 55657 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6b19b79: startup date [Wed Jan 01 13:13:59 CST 2020]; root of context hierarchy
2020-01-01 13:14:02.257 INFO 55657 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/hello],methods=[GET]}" onto public java.lang.String com.loong.diveinspringboot.Chapter1.controller.HelloWorldController.helloWorld(java.lang.String)
2020-01-01 13:14:02.260 INFO 55657 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2020-01-01 13:14:02.261 INFO 55657 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2020-01-01 13:14:02.296 INFO 55657 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2020-01-01 13:14:02.296 INFO 55657 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2020-01-01 13:14:02.341 WARN 55657 --- [ main] ion$DefaultTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
2020-01-01 13:14:02.718 INFO 55657 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator'
2020-01-01 13:14:02.726 INFO 55657 --- [ main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/health],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
2020-01-01 13:14:02.727 INFO 55657 --- [ main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/info],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
2020-01-01 13:14:02.728 INFO 55657 --- [ main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto protected java.util.Map<java.lang.String, java.util.Map<java.lang.String, org.springframework.boot.actuate.endpoint.web.Link>> org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.links(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2020-01-01 13:14:02.766 INFO 55657 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2020-01-01 13:14:02.822 INFO 55657 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-01-01 13:14:02.826 INFO 55657 --- [ main] c.l.d.C.DiveInSpringBootApplication : Started DiveInSpringBootApplication in 3.607 seconds (JVM running for 3.984)
2020.01.01 === loong
可以看到库说,結果正確輸出,且初始化器和監(jiān)聽器都已被加載片择。這里只是一個簡單的演示潜的,Starter 較為簡單,大家可以根據(jù)實際情況實現(xiàn)一個更為復雜的字管。
SpringBoot Starter
的內容就介紹到這啰挪,如果文章中有錯誤或者需要補充的請及時提出,本人感激不盡嘲叔。