Spring Boot是Spring社区较新的一个项目。该项目的目的是帮助开发者更容易得创建基于Spring的应用程序和服务,让更多人的人更快的对Spring进行入门体验,让Java开发也能够实现Ruby on Rails那样的生产效率。为Spring生态系统提供了一种固定的、约定优于配置风格的框架。
多年以来,Spring IO平台饱受非议的一点就是大量的XML配置以及复杂的依赖管理。在SpringOne 2GX会议上,Pivotal的CTO Adrian Colyer回应了这些批评,并且特别提到该平台将来的目标之一就是实现免XML配置的开发体验。Boot所实现的功能超出了这个任务的描述,开发人员不仅不再需要编写XML,而且在一些场景中甚至不需要编写繁琐的import语句。
然而,Spring Boot并不是要成为Spring IO平台里面众多“Foundation”层项目的替代者。Spring Boot的目标不在于为已解决的问题提供新的解决方案,而是为平台带来另一种开发体验,从而简化对这些已有技术的使用。对于已经熟悉Spring生态系统的开发人员来说,Boot是一个很理想的选择,不过对于采用Spring技术的新人来说,Boot提供一种更简洁的方式来使用这些技术。
Spring Boot使用“习惯优先配置”(项目中存在大量的配置,此外还内置一个习惯的配置,让你无须手动进行配置)的理念让你的项目快速运行起来。使用Spring Boot可以很容易地创建一个独立运行(运行jar,内嵌Servlet容器)、准生产级别的基于Spring框架的项目,使用Spring Boot你可以不用或者只需很少的Spring配置,它能够改变开发Spring应用程序的方式。它提供了以下几个主要特性:
Spring Boot Starter:它将常用的依赖分组进行了整合,将其合并到一个依赖中,这样就可以一次性添加到项目的Maven中,Spring Boot也提供了一系列的starter pom来简化Maven的依赖加载;
自动配置:Spring Boot的自动配置特性利用了Spring4.0对条件化配置的支持,合理地推测所需的bean并自动化配置它们;
独立运行的项目:Spring Boot可以以jar包的形式独立运行,运行一个Spring Boot项目只需要通过java -jar xx.jar来运行;
内嵌Servlet容器:Spring Boot可以选择内嵌Tomcat、Jetty或者Undertow,这样我们无须以war包形式部署项目;
准生产级别的应用监控:Spring Boot提供基于http、ssh、telnet对运行时的项目进行监控;
Spring Boot的优点总结如下:
快速构建项目;
对主流开发框架的无配置集成;
项目可独立运行,无须外部依赖Servlet容器;
提供运行时的应用监控;
极大地提高了开发、部署效率;
(1)在pom.xml中添加Spring Boot的父级依赖,这样当前项目就是Spring Boot项目了。spring-boot-starter-parent是一个特殊的starter,它用来提供相关的Maven默认依赖,使用它之后,常用的包依赖可以省略version标签。
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.2.RELEASEversion>
parent>
(2)在dependencies标签对中添加Web支持的starter pom这样就添加了Web的依赖。Starter使用了Maven的依赖传递方案,这些依赖本身可能也会有其他的依赖,一个starter可能会传递性地引入几十个依赖。例如,mobile starter引用了Web starter,而后者又引用了Tomcat Starter。大多数的Starter都会引用spring-boot-starter,它实际上是一个基础的starter(当然,它也依赖了logging starter)。依赖是传递性的,将mobile starter添加为依赖之后,就相当于添加了它下面的所有starter。
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
(3)添加Spring Boot的编译插件。
<build>
<finalName>Spring_Boot_TestfinalName>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
完整的pom.xml文件如下:
<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.0modelVersion>
<groupId>com.wiselygroupId>
<artifactId>Spring_Boot_TestartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>warpackaging>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.2.RELEASEversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
<build>
<finalName>Spring_Boot_TestfinalName>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-war-pluginartifactId>
<configuration>
<failOnMissingWebXml>falsefailOnMissingWebXml>
configuration>
plugin>
plugins>
build>
project>
(4)使用上述方法建立Spring Boot项目后,生成的项目在根包目录下会有一个artifactId + Application命名规则的入口类,为了测试方便,不再新建控制器类,而是直接在入口类中编写控制器代码:
package com.wisely.Spring_Boot_Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class Application {
@RequestMapping("/")
String index() {
return "Hello Spring Boot";
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
SpringApplication.run(Application.class, args);
}
}
@SpringBootApplication是Spring Boot项目的核心注解,它是一个组合注解,主要组合了@Configuration、@EnableAutoConfiguration、@ComponentScan,主要目的是开启自动配置。@RestController注解相当于@ResponseBody+@Controller合在一起的作用,返回String或者JSON数据的话就直接用@RestController,如果只是使用@RestController注解了Controller,则Controller中的@RequestMapping注解修饰的方法无法返回jsp或html页面,配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是Return里的内容。如果想要页面跳转的话,返回到指定的jsp或html页面,则需要用@Controller配合视图解析器InternalResourceViewResolver才行,如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。
引申:使用@Responsebody标识的方法表示该方法的返回结果直接写入HTTP response body中,一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@Responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。@ResponseBody注解直接将controller返回的bean对象或map对象等自动进行JSON或XML格式的转换。
(5)启动工程,启动方法有多种。第一种是在命令行使用命令”mvn spring-boot:run”启动该应用;第二种是在Eclipse中(或者IDEA)单击Application.java右键,在右键菜单中选择以Java Application运行项目;第三种先是运行”mvn package”进行打包,该命令会将工程打包成一个可以直接运行的 JAR 文件,然后在命令行使用”java -jar”命令就可以直接运行应用。应用启动后在控制台上打印的日志如下图所示:
(6)访问http://localhost:8080/,结果如图所示:
Spring Boot使用一个全局的配置文件application.properties或application.yml,放置在src/main/resources目录或者类路径的/config下。
Spring Boot不仅支持常规的.properties文件,还支持yaml语言的配置文件。yaml是以数据为中心的语言,在配置数据的时候具有面向对象的特征。Spring Boot的全局配置文件的作用是对一些默认配置的值进行修改。
例如,将Tomcat的默认端口号8080修改为9090,并将默认的访问路径”/”修改为”/helloboot”。可以在application.properties中添加如下语句。
server.port=9090
server.context-path=/helloboot
Spring Boot允许使用properties文件、yaml文件或者命令行参数作为外部配置。注入properties文件里的值的方式,通过@PropertySource指明properties文件的位置,然后通过@Value注入值。在Spring Boot里,只需要在application.properties中定义属性,直接使用@Value注入即可。
在上面的基础上,对application.properties增加属性后如下:
server.port=9090
server.context-path=/helloboot
book.author=fzm
book.name=spring boot
修改入口类:
@RestController
@SpringBootApplication
public class Application {
@Value("${book.author}")
private String bookAuthor;
@Value("${book.name}")
private String bookName;
@RequestMapping("/")
String index() {
return "Hello Spring Boot" +
", and Book Name:" + bookName +
",and Book Author" + bookAuthor;
//return "Hello Spring Boot";
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
SpringApplication.run(Application.class, args);
}
}
运行入口类,访问http://localhost:9090/helloboot/,效果如图所示:
整个工程的目录结构如下:
在剩余的内容里,将使用Spring Boot构建完整且符合现实要求的应用程序,该应用是一个简单的联系人列表,它允许用户输入联系人信息(名字、电话以及Email),并且能够列出用户之前输入的所有联系人信息。
利用Maven来构建应用程序,完整的pom.xml文件内容如下:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.wiselygroupId>
<artifactId>SpringBootContactsartifactId>
<packaging>jarpackaging>
<version>0.0.1-SNAPSHOTversion>
<name>SpringBootContacts Maven Webappname>
<url>http://maven.apache.orgurl>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.2.RELEASEversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleaf-spring4artifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>com.h2databasegroupId>
<artifactId>h2artifactId>
<version>1.4.191version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
dependencies>
<build>
<finalName>SpringBootContactsfinalName>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
因为我们使用Spring MVC来开发应用的Web层,因此需要将Spring MVC作为依赖添加到构建中。Spring Boot的Web Starter能够将Spring MVC需要的所有内容一站式添加到构建中。
控制器相对会非常简单,包含展示联系人表单的HTTP GET请求以及处理表单提交的POST请求。它本身并没有做太多的事情,而是委托给ContactRepository类来持久化联系人信息,控制器程序清单如下:
@Controller
@RequestMapping("/")
public class ContactController {
private ContactRepository contactRepo;
@Autowired //注入ContactReposity
public ContactController(ContactRepository contactRepo){
this.contactRepo = contactRepo;
}
@RequestMapping(method=RequestMethod.GET)
public String home(Map model){
List contacts = contactRepo.findAll();
model.put("contact", contacts);
model.put("contacts", contacts);
return "home";
}
@RequestMapping(method=RequestMethod.POST)
public String submit(Contact contact) {
contactRepo.save(contact);
return "redirect:/";
}
}
ContactController是一个典型的Spring MVC控制器,本例中ContactController遵循了Spring MVC控制器的典型模式,它会展现表单并处理表单的提交。其中home()方法使用注入的ContactRepository来获取所有Contact对象的列表,并将它们放到模型中,然后把请求转交给home视图。这个视图会展示联系人的列表以及添加新Contact的表单。submit()方法将会处理表单提交的POST请求,保存提交的Contact,并重定向到首页。
因为ContactController使用了@Controller注解,所以组件扫描将会找到它,因此,我们不需要在Spring应用上下文中明确将其声明为bean。
Contact模型类是一个简单的POJO,具有一些属性和存取方法,程序如下:
public class Contact {
private Long id;
private String firstName;
private String lastName;
private String phoneNumber;
private String emailAddress;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
}
接下来定义视图。按照传统的方式,Java Web应用会使用JSP作为视图层的技术。但是,Thymeleaf的原生模板比JSP更加便于使用,而且它能够让我们以HTML的形式编写模板。鉴于此,这里使用Thymeleaf来定义Contacts应用的home视图。
首先要将Thymeleaf添加到项目的构建中:
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleaf-spring4artifactId>
dependency>
需要记住的是,只要我们将Tymeleaf添加到项目的类路径下,就启用了Spring Boot的自动配置。当应用运行时,Spring Boot将会探测到类路径中的Thymeleaf,然后会自动配置视图解析器、模板解析器以及模板引擎,这些都是在Spring MVC中使用Thymeleaf所需要的,因此,在应用中,不需要用显式Spring配置的方式来定义Thymeleaf。
将Thymeleaf的依赖添加到构建中以后,需要在application.properties文件里对刚才添加的Thymeleaf依赖进行一些必要的配置。Thymeleaf缓存在开发过程中默认开启,这肯定是不行的,那么就要在开发的时候把缓存关闭,只需要在application.properties进行配置即可:
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.cache=false
定义home视图的Thymeleaf模板home.html如下:
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Boot Contactstitle>
<link rel="stylesheet" th:href="@{/style.css}" />
head>
<body>
<h2>Spring Boot Contactsh2>
<form method="POST">
<label for="firstName">First Name:label>
<input type="text" name="firstName">input><br/>
<label for="lastName">Last Name:label>
<input type="text" name="lastName">input><br/>
<label for="phoneNumber">Phone #:label>
<input type="text" name="phoneNumber">input><br/>
<label for="emailAddress">Email:label>
<input type="text" name="emailAddress">input><br/>
<input type="submit">input>
form>
<ul th:each="contact : ${contacts}">
<li>
<span th:text="${contact.firstName}">Firstspan>
<span th:text="${contact.lastName}">Lastspan> :
<span th:text="${contact.phoneNumber}">phoneNumberspan>,
<span th:text="${contact.emailAddress}">emailAddressspan>
li>
ul>
body>
html>
它实际上是一个非常简单的Thymeleaf模板,分为两部分:一个表单和一个联系人列表。表单将会POST数据到ContactController的submit()方法上,用来创建新的Contact。列表部分将会循环列出模型中的Contact对象。
为了使用这个模板,我们需要对其进行慎重地命名并放在项目的正确目录位置下。因为ContactController中的home()方法所返回的逻辑视图名为”home”,因此模板文件命名为home.html,自动配置的模板解析器会在指定目录下查找Thymeleaf模板,这个目录也就是相对于根类路径下的templates目录,所以在Maven项目中,需要将home.html放置在”src/main/resources/templates”中。
模板中引用了名为style.css的样式表,因此,需要将这个静态文件放到项目中。当采用Spring Boot的Web自动配置来定义Spring MVC bean时,这些bean中会包含一个资源处理器(resource handler),它会将”/**”映射到几个资源路径中。这些资源路径(相对于类路径的根)包括:
/META-INF/resources
/resources
/static
/public
在传统的基于Maven构建的项目中,通常会将静态内容放置在”src/main/webapp”目录下,这样在构建所生成WAR文件里面,这些内容就会位于WAR文件的根目录下,如果使用Spring Boot构建WAR文件的话,这依然是可选的方案。但是,我们也可以将静态内容放置在资源处理器所映射的上述四个路径下。为了满足Thymeleaf模板对”/style.css”文件的引用,我们将style.css文件放置在”/src/main/resources/static”目录下。style.css文件内容如下:
body {
background-color: #eeeeee;
font-family: sans-serif;
}
label {
display: inline-block;
width: 120px;
text-align: right;
}
在Spring应用中,有多种使用数据库的方式。可以使用JPA或Hibernate将对象映射为关系型数据库中的表和列。对于Contacts应用来说,关系型数据库是不错的选择,这里选用H2数据库和JDBC(使用Spring的JdbcTemplate),让这个过程尽可能地简单。H2是一个短小精干的嵌入式内存数据库引擎,主要的特性包括:免费、开源、快速;嵌入式的数据库服务器,支持集群;提供JDBC、ODBC访问接口,提供基于浏览器的控制台管理程序;纯Java编写,不受平台的限制。
选择这种方案就需要在构建中添加一些依赖。JDBC starter依赖会将Spring JdbcTemplate需要的所有内容都引入进来。此外,还需要添加H2依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>com.h2databasegroupId>
<artifactId>h2artifactId>
<version>1.4.191version>
dependency>
将这两项依赖添加到构建之中后,就可以编写ContactRepository类了,如下程序清单中的ContactRepository将会使用注入的JdbcTemplate实现在数据库中读取和写入Contact对象。
@Repository
public class ContactRepository {
private JdbcTemplate jdbc;
//注入JdbcTemplate
@Autowired
public ContactRepository(JdbcTemplate jdbc){
this.jdbc = jdbc;
}
//查询联系人
public List findAll(){
return jdbc.query(
"select id, firstName, lastName, phoneNumber, emailAddress " + "from contacts order by lastName",
new RowMapper() {
public Contact mapRow(ResultSet rs, int rowNum) throws SQLException {
Contact contact = new Contact();
contact.setId(rs.getLong(1));
contact.setFirstName(rs.getString(2));
contact.setLastName(rs.getString(3));
contact.setPhoneNumber(rs.getString(4));
contact.setEmailAddress(rs.getString(5));
return contact;
}
}
);
}
//插入联系人
public void save(Contact contact) {
jdbc.update(
"insert into contacts " +
"(firstName, lastName, phoneNumber, emailAddress) " +
"values (?, ?, ?, ?)",
contact.getFirstName(), contact.getLastName(),
contact.getPhoneNumber(), contact.getEmailAddress());
}
}
@Repository代表仓库. 一般注解在DAO实现类上, 别人看代码时, 就知道这个类是一个跟数据存储有关的类。@Repository、@Service、@Controller,它们分别对应存储层Bean,业务层Bean,和展示层Bean。
与ContactController类似,这个Repository类非常简单。它与传统Spring应用中的Repository类并没有什么差别。从实现中,根本无法看出它要用于Spring Boot的应用程序中。findAll()方法使用JdbcTemplate从数据库中获取Contact对象,save()方法使用JdbcTemplate保存新的Contact对象。因为ContactRepository使用了@Repository注解,因此在组件扫描的时候,它会被发现并创建为Spring应用上下文中的bean。
那么,JdbcTemplate呢?不需要在Spring应用上下文中声明JdbcTemplate bean吗?为了声明它,我们是不是需要声明一个H2 DataSource?
答案是”不需要“,当Spring Boot探测到Spring的JDBC模块和H2在类路径下的时候,自动配置就会发挥作用,它将自动配置JdbcTemplate bean和H2 DataSource bean。Spring Boot再一次为我们处理了所有的Spring配置。
那么数据库模式该怎么处理呢?我们必须自己定义创建contacts表的模式。Spring Boot没有办法猜测contacts表会是什么样子,所以需要定义如下模式:
create table contacts (
id identity,
firstName varchar(30) not null,
lastName varchar(50) not null,
phoneNumber varchar(13),
emailAddress varchar(30)
);
现在,我们只需要有一种方式加载这个”create table”的SQL并将其在H2数据库中的执行就可以了。幸好,Spring Boot也涵盖了这项功能。如果我们将这个文件命名为schema.sql并将其放置在类路径根下(也就是Maven项目的”src/main/resources”目录下),当应用启动的时候,就会找到这个文件并进行数据加载。
整个项目的目录结构如下图所示:
Contacts应用非常简单,但是也算得上现实中的Spring应用。它具有Spring MVC控制器和Thymeleaf模板所定义的Web层,并且具有Repository和Spring JdbcTemplate所定义的持久层。在完成Contacts所需的应用级别代码过程中,没有编写任何形式的配置,没有编写任何Spring配置,也没有在web.xml或Servlet初始化类中配置DispatcherServlet。
通常来讲,Spring Boot的自动配置特性消除了绝大部分或者全部的配置。因此,完全可能编写出没有任何配置的Spring应用程序,当然,自动配置并不能涵盖所有的场景。因此典型的Spring Boot应用程序依然会需要一点配置。具体到Contacts应用,我们不需要任何额外的配置,自动配置功能已经将所有的事情都做好了。
但是,我们需要有个特殊的类来启动Spring Boot应用。Spring本身并不知道自动配置的任何信息。下面程序中的Application类就是Spring Boot启动类的典型例子:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
访问http://localhost:8080/,结果如图所示:
在表单中填写几个联系人信息,多次提交后,结果如图所示:
从最根本上来讲,Spring Boot就是一些库的集合,它能够被任意项目的构建系统所使用。Spring Boot用了两个技巧来消除Spring项目中的样板式配置:Spring Boot Starter和自动配置。自动配置充分利用了Spring4.0的条件化配置特性,能够自动配置特定的Spring bean,用来启用某些特性。例如,Spring Boot能够在应用的类路径中探测到Thymeleaf,然后自动将Thymeleaf模板配置为Spring MVC视图的bean。