Spring Boot学习

Spring Boot 是为了简化 Spring 应用的创建、运行、调试、部署等而出现的,使用它可以做到专注于 Spring 应用的开发,而无需过多关注 XML 的配置。

简单来说,它提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题 --- 习惯大于约定。

 

Spring Boot 默认使用 tomcat 作为服务器,使用 logback 提供日志记录。

 

无需多言,直接进入节奏:

 

前提

Spring Boot 提供了一系列的依赖包,所以需要构建工具的支持:maven 或 gradle。个人仅熟悉 maven,所以下面的内容都是 maven 相关的。

如果不熟悉 maven,请先了解一下。

使用

① 新建一个 maven 项目。

② pom 中 parent 设为 spring-boot-starter-parent 。建议使用最新的 RELEASE 版本。否则可能需要设置 <repositories/> <pluginRepositories/>

③ 添加应用需要的 starter 模块,作为示例,我们仅添加 web starter 模块。

  这里需要解释下 starter 模块,简单的说,就是一系列的依赖包组合。例如 web starter 模块,就是包含了 Spring Boot 预定义的一些 Web 开发的常用依赖:

○ spring-web, spring-webmvc            Spring WebMvc 框架

○ tomcat-embed-*                              内嵌 Tomcat 容器

○ jackson                                             处理 json 数据

○ spring-*                                            Spring 框架

○ spring-boot-autoconfigure             Spring Boot 提供的自动配置功能

  换句话说,当你添加了相应的 starter 模块,就相当于添加了相应的所有必须的依赖包。

  starter 模块的列表及含义,见 Spring Boot 的启动器 Starter 详解

 

至此,pom 内容如下:

<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>
    <groupId>cn.larry.spring</groupId>
    <artifactId>larry-spring-demo4</artifactId>
    <version>0.0.1-SNAPSHOT</version>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">parent</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework.boot<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-boot-starter-parent<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>1.4.0.RELEASE<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">parent</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependencies</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework.boot<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-boot-starter-web<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependencies</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</project>

保存 pom,刷新 maven,以便刷新依赖导入。
基本上,如果没有特别的需要,现在就可以直接写 Controller 了!!!-- 特别的需要 是指设置容器、访问端口、路径等。后面再解释。

④ 写一个简单的 Controller。-- 直接拿了 Spring Boot——开发新一代 Spring Java 应用 中的示例。

package cn.larry.spring.controller;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@EnableAutoConfiguration
public class SampleController {

@RequestMapping(</span>"/"<span style="color: rgba(0, 0, 0, 1)">)
@ResponseBody
String home() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> "Hello World!"<span style="color: rgba(0, 0, 0, 1)">;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> main(String[] args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Exception {
    SpringApplication.run(SampleController.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
}

}

这里有两个新东西:@EnableAutoConfigurationSpringApplication

@EnableAutoConfiguration 用于自动配置。简单的说,它会根据你的 pom 配置(实际上应该是根据具体的依赖)来判断这是一个什么应用,并创建相应的环境。

在上面这个例子中,@EnableAutoConfiguration 会判断出这是一个 web 应用,所以会创建相应的 web 环境。

 

SpringApplication 则是用于从 main 方法启动 Spring 应用的类。默认,它会执行以下步骤

  1. 创建一个合适的 ApplicationContext 实例 (取决于 classpath)。
  2. 注册一个 CommandLinePropertySource,以便将命令行参数作为 Spring properties。
  3. 刷新 application context,加载所有单例 beans。
  4. 激活所有 CommandLineRunner beans。

默认,直接使用SpringApplication 的静态方法 run() 即可。但也可以创建实例,并自行配置需要的设置。

具体的描述见 javadoc 即可,如下:

Open Declaration org.springframework.boot.SpringApplication

Classes that can be used to bootstrap and launch a Spring application from a Java main method. By default class will perform the following steps to bootstrap your application:

Create an appropriate ApplicationContext instance (depending on your classpath)
Register a CommandLinePropertySource to expose command line arguments as Spring properties
Refresh the application context, loading all singleton beans
Trigger any CommandLineRunner beans
In most circumstances the static run(Object, String []) method can be called directly from your main method to bootstrap your application:
@Configuration
@EnableAutoConfiguration
public class MyApplication {

// ... Bean definitions

public static void main(String[] args) throws Exception {
SpringApplication.run(MyApplication.class, args);
}

For more advanced configuration a SpringApplication instance can be created and customized before being run:

public static void main(String[] args) throws Exception {
SpringApplication app = new SpringApplication(MyApplication.class);
// ... customize app settings here
app.run(args)
}

SpringApplications can read beans from a variety of different sources. It is generally recommended that a single @Configuration class is used to bootstrap your application, however, any of the following sources can also be used:
Class - A Java class to be loaded by AnnotatedBeanDefinitionReader
Resource - An XML resource to be loaded by XmlBeanDefinitionReader, or a groovy script to be loaded by GroovyBeanDefinitionReader
Package - A Java package to be scanned by ClassPathBeanDefinitionScanner
CharSequence - A class name, resource handle or package name to loaded as appropriate. If the CharSequence cannot be resolved to class and does not resolve to a Resource that exists it will be considered a Package.

View Code

 

⑤ 现在,直接右键启动 main 方法即可。启动信息(包括关闭信息)如下:

 1   .   ____          _            __ _ _
 2  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
 3 (()\___ | '_ |'_| | '_ \/ _` | \ \ \ \
 4  \\/  ___)| |_)| | | | | || (_| |) )))
 5   '  |____| .__|_| |_|_| |_\__, | / / / /
 6  =========|_|==============|___/=/_/_/_/
 7  :: Spring Boot ::        (v1.4.0.RELEASE)
 8 
 9 2016-08-15 14:30:16.565  INFO 10652 --- [main] c.l.spring.controller.SampleController   : Starting SampleController on Larry with PID 10652 (D:\Workspace\Workspace_sts\larry-spring-demo4\target\classes started by Administrator in D:\Workspace\Workspace_sts\larry-spring-demo4)
10 2016-08-15 14:30:16.567  INFO 10652 --- [main] c.l.spring.controller.SampleController   : No active profile set, falling back to default profiles: default
11 2016-08-15 14:30:16.596  INFO 10652 --- [main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4a94ee4: startup date [Mon Aug 15 14:30:16 CST 2016]; root of context hierarchy
12 2016-08-15 14:30:17.676  INFO 10652 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
13 2016-08-15 14:30:17.687  INFO 10652 --- [main] o.apache.catalina.core.StandardService   : Starting service Tomcat
14 2016-08-15 14:30:17.688  INFO 10652 --- [main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.4
15 2016-08-15 14:30:17.767  INFO 10652 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
16 2016-08-15 14:30:17.767  INFO 10652 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1173 ms
17 2016-08-15 14:30:17.928  INFO 10652 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
18 2016-08-15 14:30:17.932  INFO 10652 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
19 2016-08-15 14:30:17.933  INFO 10652 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
20 2016-08-15 14:30:17.933  INFO 10652 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
21 2016-08-15 14:30:17.933  INFO 10652 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
22 2016-08-15 14:30:18.177  INFO 10652 --- [main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4a94ee4: startup date [Mon Aug 15 14:30:16 CST 2016]; root of context hierarchy
23 2016-08-15 14:30:18.230  INFO 10652 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto java.lang.String cn.larry.spring.controller.SampleController.home()
24 2016-08-15 14:30:18.234  INFO 10652 --- [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.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
25 2016-08-15 14:30:18.235  INFO 10652 --- [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.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
26 2016-08-15 14:30:18.262  INFO 10652 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
27 2016-08-15 14:30:18.262  INFO 10652 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
28 2016-08-15 14:30:18.295  INFO 10652 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
29 2016-08-15 14:30:18.423  INFO 10652 --- [main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
30 2016-08-15 14:30:18.480  INFO 10652 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
31 2016-08-15 14:30:18.485  INFO 10652 --- [main] c.l.spring.controller.SampleController   : Started SampleController in 2.209 seconds (JVM running for 2.642)
32 2016-08-15 14:30:23.564  INFO 10652 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
33 2016-08-15 14:30:23.564  INFO 10652 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
34 2016-08-15 14:30:23.574  INFO 10652 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 10 ms
35 2016-08-15 14:30:32.002  INFO 10652 --- [2)-192.168.56.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested.
36 2016-08-15 14:30:32.003  INFO 10652 --- [2)-192.168.56.1] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4a94ee4: startup date [Mon Aug 15 14:30:16 CST 2016]; root of context hierarchy
37 2016-08-15 14:30:32.004  INFO 10652 --- [2)-192.168.56.1] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

如果使用 sts (Spring Tools Suite-- 没意外的话,后面的博客我会介绍一下),还可以用 Spring Application 的形式启动,信息不变,但是彩色的,如下:

⑥ 根据这个信息,我们可以看出很多东西,不过现在先访问一下吧。

默认访问地址: http://localhost:8080/

按照之前的 web 项目习惯,你可能会问,怎么没有项目路径?

这就是 Spring Boot 的默认设置了,将项目路径直接设为根路径。

当然,我们也可以设置自己的项目路径 -- 在 classpath 下的 application.properties 或者 application.yaml 文件中设置即可。

内容如下:

# application.yaml
# Server settings (ServerProperties)
server:
  port: 8080
  address: 127.0.0.1
  sessionTimeout: 30
  contextPath: /aaa

Tomcat specifics

tomcat:
accessLogEnabled: false
protocolHeader: x-forwarded-proto
remoteIpHeader: x-forwarded-for
basedir:
backgroundProcessorDelay: 30 # secs

# application.properties
# Server settings (ServerProperties)
server.port=8080
server.address=127.0.0.1
#server.sessionTimeout=30
server.contextPath=/aaa
# Tomcat specifics
#server.tomcat.accessLogEnabled=false
server.tomcat.protocolHeader=x-forwarded-proto
server.tomcat.remoteIpHeader=x-forwarded-for
server.tomcat.basedir=
server.tomcat.backgroundProcessorDelay=30

上面, server.contextPath=/aaa 就是设置了项目路径。所以现在需要访问 http://localhost:8080/aaa/ 才行。

 

分析

OK,当目前为止,已经成功运行并访问了一个 SpringMVC 应用。简单的不能再简单了!

再来看一下启动时的信息:

第 9 行,启动 SampleController。
第 10 行,查找 active profile,无,设为 default。
第 11 行,刷新上下文。
第 12 行,初始化 tomcat,设置端口 8080,设置访问方式为 http。
第 13 行,启动 tomcat 服务。
第 14 行,启动 Servlet 引擎。
第 15 行,Spring 内嵌的 WebApplicationContext 初始化开始。
第 16 行,Spring 内嵌的 WebApplicationContext 初始化完成。
第 17 行,映射 servlet,将 dispatcherServlet 映射到 [/] 。
第 18 行,映射 filter,将 characterEncodingFilter 映射到 [/*] 。
第 19 行,映射 filter,将 hiddenHttpMethodFilter 映射到 [/*] 。
第 20 行,映射 filter,将 httpPutFormContentFilter 映射到 [/*] 。
第 21 行,映射 filter,将 requestContextFilter 映射到 [/*] 。
第 22 行,查找 @ControllerAdvice。
第 23 行,映射路径 "{[/]}" 到 cn.larry.spring.controller.SampleController.home()。
第 24 行,映射路径 "{[/error]}" 到 org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)。
第 25 行,映射路径 "{[/error],produces=[text/html]}" 到 org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)。
第 26 行,略。 第 27 行,略。 第 28 行,略。 第 29 行,略。
第 30 行,tomcat 启动完毕。
第 31 行,SampleController 启动耗费的时间。
第 32 行,初始化 dispatcherServlet 。
第 33 行,dispatcherServlet 的初始化已启动。
第 34 行,dispatcherServlet 的初始化已完成。
第 35 行,收到 shutdown 关闭请求。
第 36 行,关闭 AnnotationConfigEmbeddedWebApplicationContext。
第 37 行,略。

从上面的启动信息中可以明显看到 SpringMVC 的加载过程,特别需要注意的是这种默认方式下加载的几个 filter 。

这里就不再介绍了,具体可以见本文末尾最后三个链接。

 

2018.1.8 补充

使用 IDEA 的 Spring Initializer,也可以新建 Spring Boot 项目,过程类似,不再赘述了。

 

参考:

Spring Boot——开发新一代 Spring Java 应用Spring Boot 的启动器 Starter 详解 深入学习微框架:Spring Boot Spring MVC 过滤器 -RequestContextFilter Spring MVC 过滤器 -HttpPutFormContentFilter Spring MVC 过滤器 -HiddenHttpMethodFilter