一、什么是Spring Boot?
Spring Boot是由pivotal团队所提供,目的是为了简化Spring应用的初始化搭建以及开发过程。
先以最基础的Spring Mvc项目为例,通过是否使用Spring Boot搭建项目,对比下差异。
二、Spring Boot使用
2.1不使用Spring Boot项目搭建
创建一个Spring Mvc Maven项目需要以下几步
1:创建一个Maven Web项目
2:pom.xml引入相关依赖
<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的初始化参数,读取springmvc的配置文件,创建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相关配置
<!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的初始化参数,读取springmvc的配置文件,创建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项目搭建
创建一个Spring Boot Web Maven项目需要以下几步
1:创建一个继承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:创建启动类
@SpringBootApplication
public class SpringBootWebApplication {
public static void main(String[] args) throws IOException {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
4:编写Controller代码
5:运行启动类
对比一下,spring boot创建项目确实简单许多。
三、Spring Boot如何实现
官方给出Spring Boot的特征 :
- 创建独立的Spring applications
- 嵌入tomcat,jetty,Undertow(无需部署WAR文件)
- 提供基础依赖项,简化构建
- 尽可能自动配置spring和第三方库
- 提供可用于生产的功能,例如指标、运行状况检查、和外部化配置
- 完全没有代码生成、也不需要XML配置
除了第5点(本文不涉及),其它都很清晰。结合Spring Boot的目的,可以看出Spring Boot是通过提供基础依赖、自动配置、内嵌服务器三个方面来实现“简化Spring应用的初始化搭建以及开发过程”这一目的。
3.1基础依赖提供###
通过查看Spring Boot项目中引入的spring-boot-starter-web依赖不难发现,Spring Boot利用maven(Gradle相同)依赖具有传递性的特点,通过引入spring-boot-starter-web依赖,间接引入了spring Mvc相关依赖。实际上通过阅读Spring Boot源码不难发现spring-boot-starter-xxx项目下都没有java代码,而仅包含pom.xml文件。各pom.xml文件中配置对应Spring xxx应用所需依赖。
注:由于Spring boot2.3.0之后使用Gradle构建,所以本文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的相关依赖-->
<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机制(详情可以百度)。简单来说就是在项目META-INF/spring.factories文件中配置接口的实现类名称,然后在程序中读取这些配置文件并实例化。
Spring Boot自动配置的关键是启动类上注解@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是一个组合注解,主要关注
- @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获取类加载器内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)调用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);
//此行代码调用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应用的自动配置类,Spring Boot如何区分应该加载哪些应用自动配置类呢?查看EnableAutoConfiguration中Spring Mvc自动配置类WebMvcAutoConfiguration,源码如下
@Configuration(proxyBeanMethods = false)
//当前是否为servlet web应用
@ConditionalOnWebApplication(type = Type.SERVLET)
//当前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区分当前配置类是否应该被加载,当所有@ConditionalOnxxx为真时,配置类才被加载。完整@ConditionalOnxxx请查看
3.3内嵌服务器
三、总结
Spring Boot极大的简化了Spring应用的开发。对于Spring Boot基本原理做了基本了解,对于各自动配置内容,Spring Boot细节还需通过阅读源码、文档深入学习。
网友评论