Spring Boot 概述
Build Anything with Spring Boot:**Spring Boot is the starting point for building all Spring-based applications. Spring Boot is designed to get you up and running as quickly as possible, with minimal upfront configuration of Spring.
上面是引自官網(wǎng)的一段話,大概是說(shuō): Spring Boot 是所有基于 Spring 開(kāi)發(fā)的項(xiàng)目的起點(diǎn)。Spring Boot 的設(shè)計(jì)是為了讓你盡可能快的跑起來(lái) Spring 應(yīng)用程序并且盡可能減少你的配置文件。
什么是 Spring Boot
- 它使用 “習(xí)慣優(yōu)于配置” (項(xiàng)目中存在大量的配置,此外還內(nèi)置一個(gè)習(xí)慣性的配置,讓你無(wú)須手動(dòng)配置)的理念讓你的項(xiàng)目快速運(yùn)行起來(lái)。
- 它并不是什么新的框架,而是默認(rèn)配置了很多框架的使用方式,就像 Maven 整合了所有的 jar 包一樣,Spring Boot 整合了所有框架
使用 Spring Boot 有什么好處
回顧我們之前的 SSM 項(xiàng)目,搭建過(guò)程還是比較繁瑣的,需要:
- 1、配置 web.xml,加載 spring 和 spring mvc
- 2、配置數(shù)據(jù)庫(kù)連接、配置日志文件
- 3、配置家在配置文件的讀取,開(kāi)啟注解
- 4、配置mapper文件
而使用 Spring Boot 來(lái)開(kāi)發(fā)項(xiàng)目則只需要非常少的幾個(gè)配置就可以搭建起來(lái)一個(gè) Web 項(xiàng)目,并且利用 IDEA 可以自動(dòng)生成生成
- 劃重點(diǎn):簡(jiǎn)單、快速、方便地搭建項(xiàng)目;對(duì)主流開(kāi)發(fā)框架的無(wú)配置集成;極大提高了開(kāi)發(fā)、部署效率。
spring boot工程需要導(dǎo)入依賴spring boot相關(guān)的依賴
<?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 http://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.1.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.yibo</groupId>
<artifactId>springboot-source-code</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
編寫主程序
/**
* @SpringBootApplication來(lái)標(biāo)注一個(gè)主程序類,說(shuō)明這是一個(gè)SpringBoot應(yīng)用
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
//Spring應(yīng)用啟動(dòng)
SpringApplication.run(Application.class,args);
}
}
Springboot探究
POM文件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
父項(xiàng)目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.10.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
該父項(xiàng)目是真正管理Spring Boot應(yīng)用里面的所有依賴的版本:Spring Boot的版本仲裁中心,所以以后導(dǎo)入的依賴默認(rèn)是不需要版本號(hào)。如下
<properties>
<activemq.version>5.15.10</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.76</appengine-sdk.version>
<artemis.version>2.6.4</artemis.version>
<aspectj.version>1.9.4</aspectj.version>
<assertj.version>3.11.1</assertj.version>
<atomikos.version>4.0.6</atomikos.version>
<bitronix.version>2.1.4</bitronix.version>
<build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>
<byte-buddy.version>1.9.16</byte-buddy.version>
<caffeine.version>2.6.2</caffeine.version>
<cassandra-driver.version>3.6.0</cassandra-driver.version>
<classmate.version>1.4.0</classmate.version>
<commons-codec.version>1.11</commons-codec.version>
<commons-dbcp2.version>2.5.0</commons-dbcp2.version>
<commons-lang3.version>3.8.1</commons-lang3.version>
<commons-pool.version>1.6</commons-pool.version>
<commons-pool2.version>2.6.2</commons-pool2.version>
<couchbase-cache-client.version>2.1.0</couchbase-cache-client.version>
<couchbase-client.version>2.7.9</couchbase-client.version>
<dependency-management-plugin.version>1.0.8.RELEASE</dependency-management-plugin.version>
......
</properties>
啟動(dòng)器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
spring-boot-starter: spring boot場(chǎng)景啟動(dòng)器;幫助導(dǎo)入web模塊正常運(yùn)行所依賴的組件;
Spring Boot將所有的功能場(chǎng)景抽取出來(lái),做成一個(gè)個(gè)的starter(啟動(dòng)器),只需要在項(xiàng)目中引入這些starter,那么相關(guān)的場(chǎng)景的所有依賴都會(huì)導(dǎo)入進(jìn)項(xiàng)目中。要用什么功能就導(dǎo)入什么場(chǎng)景的啟動(dòng)器。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.10.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.1.10.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.1.10.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.18.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.11.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.11.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
添加spring-boot-starter-web 依賴,會(huì)自動(dòng)添加 Tomcat 和 Spring MVC等依賴,并且spring-boot-starter-web中又引入了spring-boot-starter-tomcat
主程序類(主入口類)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
@SpringBootApplication
Spring Boot應(yīng)用標(biāo)注在某個(gè)類上,說(shuō)明這個(gè)類是SpringBoot的主配置類,SpringBoot就應(yīng)該運(yùn)行這個(gè)類的main方法來(lái)啟動(dòng)SpringBoot應(yīng)用。
注解定義如下:
@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 {}
@SpringBootConfiguration
- Spring Boot的配置類
- 標(biāo)注在某個(gè)類上,表示這是一個(gè)Spring Boot的配置類
注解定義如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
其實(shí)就是一個(gè)Configuration配置類,意思是Application最終會(huì)被注冊(cè)到Spring容器中
@EnableAutoConfiguration
- 開(kāi)啟自動(dòng)配置功能
- 以前使用Spring需要配置的信息,Spring Boot幫助自動(dòng)配置;
- @EnableAutoConfiguration通知SpringBoot開(kāi)啟自動(dòng)配置功能,這樣自動(dòng)配置才能生效。
注解定義如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
@AutoConfigurationPackage
- 自動(dòng)配置包注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
@Import(AutoConfigurationPackages.Registrar.class):默認(rèn)將主配置類(@SpringBootApplication)所在的包及其子包里面的所有組件掃描到Spring容器中。如下
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//默認(rèn)將會(huì)掃描@SpringBootApplication標(biāo)注的主配置類所在的包及其子包下所有組件
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
@Import({AutoConfigurationImportSelector.class})
AutoConfigurationImportSelector: 導(dǎo)入哪些組件的選擇器,將所有需要導(dǎo)入的組件以全類名的方式返回,這些組件就會(huì)被添加到容器中。
AutoConfigurationImportSelector{
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
}
我們主要看List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);attributes);會(huì)給容器中注入眾多的自動(dòng)配置類(xxxAutoConfiguration),就是給容器中導(dǎo)入這個(gè)場(chǎng)景需要的所有組件,并配置好這些組件。我們跟進(jìn)去看看
public class AutoConfigurationImportSelector{
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
}
public final class SpringFactoriesLoader{
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//獲取緩存中的配置
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
//從類路徑的META-INF/spring.factories中加載所有默認(rèn)的自動(dòng)配置類
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
}
SpringBoot啟動(dòng)的時(shí)候通過(guò)SpringFactoriesLoader從類路徑下的 META-INF/spring.factories中獲取EnableAutoConfiguration指定的值,并將這些值作為自動(dòng)配置類導(dǎo)入到容器中,自動(dòng)配置類就會(huì)生效,最后完成自動(dòng)配置工作。EnableAutoConfiguration默認(rèn)在spring-boot-autoconfigure這個(gè)包中,如下圖:

最終有96個(gè)自動(dòng)配置類被加載并注冊(cè)進(jìn)Spring容器中
J2EE的整體整合解決方案和自動(dòng)配置都在spring-boot-autoconfigure-xxx.jar中。在這些自動(dòng)配置類中會(huì)通過(guò)@ConditionalOnClass等條件注解判斷是否導(dǎo)入了某些依賴包,從而通過(guò)@Bean注冊(cè)相應(yīng)的對(duì)象進(jìn)行自動(dòng)配置。