一、什么是Spring Boot?
Spring Boot是由pivotal團(tuán)隊所提供,目的是為了簡化Spring應(yīng)用的初始化搭建以及開發(fā)過程。
先以最基礎(chǔ)的Spring Mvc項目為例,通過是否使用Spring Boot搭建項目,對比下差異。
二、Spring Boot使用
2.1不使用Spring Boot項目搭建
創(chuàng)建一個Spring Mvc Maven項目需要以下幾步
1:創(chuàng)建一個Maven Web項目
2:pom.xml引入相關(guān)依賴
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
3.在web.xml中配置SpringMvc核心控制器DispatcherServlet
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- SpringMVC的核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置Servlet的初始化參數(shù),讀取springmvc的配置文件,創(chuàng)建spring容器 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMvc.xml</param-value>
</init-param>
<!-- 配置servlet啟動時加載對象 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4.配置SpringMvc相關(guān)配置
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- SpringMVC的核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置Servlet的初始化參數(shù),讀取springmvc的配置文件,創(chuàng)建spring容器 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMvc.xml</param-value>
</init-param>
<!-- 配置servlet啟動時加載對象 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
5.編寫Controller代碼
6.部署啟動tomcat容器
2.1使用Spring Boot項目搭建
創(chuàng)建一個Spring Boot Web Maven項目需要以下幾步
1:創(chuàng)建一個繼承spring-boot-starter-parent的Maven項目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
2:引入spring-boot-starter依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
3:創(chuàng)建啟動類
@SpringBootApplication
public class SpringBootWebApplication {
public static void main(String[] args) throws IOException {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
4:編寫Controller代碼
5:運(yùn)行啟動類
對比一下,spring boot創(chuàng)建項目確實(shí)簡單許多。
三、Spring Boot如何實(shí)現(xiàn)
官方給出Spring Boot的特征 :
- 創(chuàng)建獨(dú)立的Spring applications
- 嵌入tomcat,jetty,Undertow(無需部署WAR文件)
- 提供基礎(chǔ)依賴項,簡化構(gòu)建
- 盡可能自動配置spring和第三方庫
- 提供可用于生產(chǎn)的功能,例如指標(biāo)、運(yùn)行狀況檢查、和外部化配置
- 完全沒有代碼生成、也不需要XML配置
除了第5點(diǎn)(本文不涉及),其它都很清晰。結(jié)合Spring Boot的目的,可以看出Spring Boot是通過提供基礎(chǔ)依賴、自動配置、內(nèi)嵌服務(wù)器三個方面來實(shí)現(xiàn)“簡化Spring應(yīng)用的初始化搭建以及開發(fā)過程”這一目的。
3.1基礎(chǔ)依賴提供###
通過查看Spring Boot項目中引入的spring-boot-starter-web依賴不難發(fā)現(xiàn),Spring Boot利用maven(Gradle相同)依賴具有傳遞性的特點(diǎn),通過引入spring-boot-starter-web依賴,間接引入了spring Mvc相關(guān)依賴。實(shí)際上通過閱讀Spring Boot源碼不難發(fā)現(xiàn)spring-boot-starter-xxx項目下都沒有java代碼,而僅包含pom.xml文件。各pom.xml文件中配置對應(yīng)Spring xxx應(yīng)用所需依賴。
注:由于Spring boot2.3.0之后使用Gradle構(gòu)建,所以本文Spring Boot項目源碼版本為2.2
查看spring-boot-starter-web源碼中pom.xml文件如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
<!--看這里,引入了Spring Mvc的相關(guān)依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.9.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
3.2自動配置
了解Spring Boot自動配置之前,需要先了解Spring Spi機(jī)制(詳情可以百度)。簡單來說就是在項目META-INF/spring.factories文件中配置接口的實(shí)現(xiàn)類名稱,然后在程序中讀取這些配置文件并實(shí)例化。
Spring Boot自動配置的關(guān)鍵是啟動類上注解@SpringBootApplication和SpringApplication.run(SpringBootWebApplication.class, args)
首先查看@SpringBootApplication源碼如下
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication
@SpringBootApplication是一個組合注解,主要關(guān)注
- @ComponentScan注解很熟悉,自動掃描組件。
- @EnableAutoConfiguration注解源碼如下
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration
@EnableAutoConfiguration注解包含 @Import(AutoConfigurationImportSelector.class)。
跟蹤AutoConfigurationImportSelector代碼可以看到getAutoConfigurationEntry方法使用Spring Spi獲取類加載器內(nèi)META-INF/spring.factories配置文件中的EnableAutoConfiguration的配置。
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//此行代碼獲取配置文件中的EnableAutoConfiguration加載類名
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
跟蹤啟動類SpringApplication.run(SpringBootWebApplication.class, args)代碼,run方法中通過refreshContext(context)調(diào)用AutoConfigurationImportSelector.getAutoConfigurationEntry方法加載需要自動配置的類
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//此行代碼調(diào)用AutoConfigurationImportSelector.getAutoConfigurationEntry方法
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
META-INF/spring.factories EnableAutoConfiguration配置中包含Spring Boot整合所有Spring應(yīng)用的自動配置類,Spring Boot如何區(qū)分應(yīng)該加載哪些應(yīng)用自動配置類呢?查看EnableAutoConfiguration中Spring Mvc自動配置類WebMvcAutoConfiguration,源碼如下
@Configuration(proxyBeanMethods = false)
//當(dāng)前是否為servlet web應(yīng)用
@ConditionalOnWebApplication(type = Type.SERVLET)
//當(dāng)前classpath上是否包含Servlet、DispatcherServlet、WebMvcConfigurer三個類
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//上下文中不存在WebMvcConfigurationSupport對象
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration
WebMvcAutoConfiguration 類中包含3個@ConditionalOnxxx。Spring Boot通過@ConditionalOnxxx區(qū)分當(dāng)前配置類是否應(yīng)該被加載,當(dāng)所有@ConditionalOnxxx為真時,配置類才被加載。完整@ConditionalOnxxx請查看
3.3內(nèi)嵌服務(wù)器
三、總結(jié)
Spring Boot極大的簡化了Spring應(yīng)用的開發(fā)。對于Spring Boot基本原理做了基本了解,對于各自動配置內(nèi)容,Spring Boot細(xì)節(jié)還需通過閱讀源碼、文檔深入學(xué)習(xí)。