SpringBoot简介
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而不再需要定义样板化的配置。
SpringBoot优点有哪些?
在以往搭建一个Spring Web项目,都需要经过一下流程:
- 配置web.xml,加载Spring、SpringMVC
- 配置数据库、配置Spring事务
- 配置加载配置文件的读取,开启注解
- 配置日志文件
- ...
- 部署Tomcat调试
从上面的步骤可以看出,要搭建一个Spring Web项目步骤非常繁琐,在使用Spring Boot,仅仅需要将需要的依赖放入,以及非常少的配置便可以搭建一个Web项目,也就是说,Spring Boot的优点简单解释如下:
-
快速搭建项目,极大地提高了开发、部署效率。
-
对xml配置没有要求。
-
内嵌servlet容器,无需部署。
-
提供starter简化maven配置。
SpringBoot快速入门
Spring官方推荐使用Spring Initializr来创建Maven项目,通过这种方式创建的Maven项目,已经帮生成了启动类和单元测试模块,并且能很好支持IDE,给开发者带来极大的便利。
1)项目搭建
点击Finish,Idea会自动下载项目所需要的依赖,创建好的项目结构如下所示:
2)项目文件说明
- src
- main
- java(项目Java代码在这里编写)
- resource(静态资源、配置类文件夹)
- static(存放静态资源,例如css、js等)
- templat(存放html模板等)
- application.properties(spring boot核心配置文件)
- test(用于测试)
- pom.xml(Maven构建说明文件)
- main
3)测试
编写一个helloController.java,测试项目能否运行。
HelloController.java
@RestController
public class HelloController {
@GetMapping("helloSpringBoot")
public String helloSpringBoot() {
return "Hello,Spring Boot!";
}
}
运行结果:
SpringBoot项目解析
1)pom.xml解析
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
首先,是
在pom.xml文件中,有两个核心的模块,一个是spring-boot-starter,另一个是spring-boot-starter-test,在这里由于引入了Spring Web,因此spring-boot-starter变成spring-boot-starter-web,点进spring-boot-starter-web,可以看到其实它是依赖于spring-boot-starter的。
除此之外,另一个核心模块spring-boot-starter-test,这个是测试模块,包括了junit、hamcrest、mockito等等。
2)DemoApplication.java解析
DemoApplication.java是Spring Boot项目的启动类:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
该启动类含有一个注解,@SpringBootApplication,该注解是Spring Boot项目的核心注解,打开这个注解,可以看到该注解又包含了三个比较重要的注解:
- SpringBootConfiguration:继承@Configuration,标注当前类为配置类。
- EnableAutoConfiguration:启用Spring自动加载配置。
- ComponentScan:用于类或接口上主要是指定扫描路径。
@EnableAutoConfiguration原理分析
像上面所说,@EnableAutoConfiguration的作用就是启用Spring自动加载配置,Spring Boot一个最大的优点便是节省了开发者的配置时间,那么,@EnableAutoConfiguration又是如何实现自动配置?
面试题:SpringBoot自动配置的原理是什么?
打开@EnableAutoConfiguration,可以看到如下代码:
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
@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 {};
}
从上面的代码中,我们可以看到一个注解@Import,在这个注解中导入了一个类,AutoConfigurationImportSelector,而自动注入配置的功能就是依赖于这个对象。
点进这个类中,可以找到一个getCandidateConfigurations()方法,如下所示:
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;
}
从这里可以看到是使用了Spring中的工具类SpringFactories中的loadFactoryNames()方法来加载配置文件,扫描的路径是 META-INF/spring.factories。
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 {
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 factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
在SpringFactoriesLoader这个类中有一个loadSpringFactories()的方法,该方法返回了一个数据结构是map类型的result,而这个result实际上就是META-INF/spring.factories对应的Map数据结构,这个Map保存了整个Spring中配置类的全类名,获取到对应类的全名的第一步,就是加载一个类,而具体加载方式由SpringBootApplication完成,这里不仔细介绍。
在spring.factories中可以看到如下内容:
随便点开一个配置类看看里面的内容:
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnProperty(
prefix = "spring.aop",
name = {"auto"},
havingValue = "true",
matchIfMissing = true
)
public class AopAutoConfiguration {
其中,@ConditionalOnProperty作用是从spring的配置中加载指定前缀的配置,并自动设置到对应的成员变量上。也正是通过这种方式,真正实现了配置的自动注入。
总结:
@EnableAutoConfiguration的流程大致是:
@EnableAutoConfiguration->AutoConfigurationImportSelector->spring.factories->EnableAutoConfiguration->AopAutoConfiguration(具体的配置类)->@EnableConfigurationProperties->AopProperties(具体的配置类)->@ConditionalOnProperty(prefix = "spring.aop")
3)HelloController.java解析
@RestController
public class HelloController {
@GetMapping("helloSpringBoot")
public String helloSpringBoot() {
return "Hello,Spring Boot!";
}
}
@RestController注解等价于@Controller+@ResponseBody的结合,使用这个注解的类里面的方法都以json格式输出。