Spring-Boot:6分钟掌握SpringBoot开发
构建项目
从技术角度来看,我们要用 Spring MVC 来处理 Web 请求,用 Thymeleaf 来定义 Web 视图,用 Spring Data JPA 来把阅读列表持久化到数据库里,姑且先用嵌入式的 H2 数据库。
1、项目搭建
Spring IO 官网搭建
我们可以进入到 Spring 的官网:http://start.spring.io/
进入官网后,可以快速的构建 Spring boot 的基础项目,这里可以选择 Maven 项目或者 Gradle 项目,然后设置项目相关的配置。
在选择 Generate Project 进行项目下载后,会生成对应的 zip 文件。后续只需要将 Zip 文件解压,添加到 IDE 中即可。
IDEA 快速构建
除了在 SpringIO 官网进行项目初始化外,还可以通过 IDEA 进行项目的搭建。如下图所示,项目的搭建也是引用了 http://start.spring.io/
在后续的页面中,我们可以设置相关的配置信息,一些常用的依赖,也可以进行初始化。
Spring Boot CLI
除了以上常用的项目创建方法以外,我们还可以通过 CLI 进行项目的创建:
1 | spring init -dweb,data-jpa,h2,thymeleaf --build gradle readinglist |
CLI 的 init 命令是不能指定项目根包名和项目名的。包名默认是 demo,项目名默认是 Demo。
2、目录结构
不管我们采用哪种方式进行项目的创建,在将项目导入 IDE 之后,我们可以看到整个项目结构遵循传统 Maven 或 Gradle 项目的布局,即主要应用程序代码位于 src/main/java 目录里,资源都在 src/main/resources 目录里,测试代码则在 src/test/java 目录里。此刻还没有测试资源,但如果有的话,要放在 src/test/resources 里。
文件介绍:
- SpringBootWebApplication: 应用程序的启动引导类 (bootstrap class),也是主要的 Spring 配置类。
- appliction.properties:用于配置应用程序和 Spring boot 的属性
- SpringBootWebApplicationTests:一个基本的集成测试类。
- pom.xml:项目依赖文件
3、文件介绍
SpringBootWebApplication
Application 类在 Spring boot 应用程序中有两个作用:配置和启动引导。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication --开启组件扫描和自动配置
public class SpringBootWebApplication {public static void main(String[] args) {
SpringApplication.run(SpringBootWebApplication.class, args); -- 负责启动引导应用程序
}
}
我们在使用 Spring boot 进行开发时,Application 类是我们启动服务的入口,起到关键作用的是 **@SpringBootApplication** 这一注解,实际上 @SpringBootApplication 包含了三个有用的注解:
- @Configuration:标明该类使用 Spring 基于 Java 的配置。
- @ComponentScan:启用组件扫描,这样你写的 Web 控制器类和其他组件才能被自动发现并注册为 Spring 应用程序上下文中的 Bean。
- @EnableAutoConfiguration:这一个配置开启了 Spring boot 的自动配置。
这里使用到 main 方法是需要提供一个 @EnableAutoConfiguration 注解的引导类,来引导整个应用程序的启动。
SpringBootWebApplicationTests
项目创建时问我们创建了一个带有上下文的测试类。
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest -- 通过 SpringBoot 加载上下文
public class SpringBootWebApplicationTests {@Test
public void contextLoads() {
-- 测试加载的上下文
}}
application.properties
实际上,这个文件是可选的,你可以删掉它而不影响应用程序的运行。
我们可以通过向 application.properties 中添加变量,从而改变程序的默认配置。例如:
server.port=8000
server.contextPath=SpringBootWeb
在上述代码中,我们将程序的默认端口(8080) 修改成为使用 8000 端口,并且将应用程序的项目名修改为 SpringBootWeb。
原访问地址:
http://127.0.0.1:8080/
修改后:
http://127.0.0.1:8000/SpringBootWeb/
除此之外 还可以配置多环境的变量设置等一系列的设置:
spring.profiles.active = dev
pom.xml
在代码清单中,我们引用了 spring-boot-starter-parent 作为上一级,这样一来就能利用到 Maven 的依赖管理功能,集成很多常用库的依赖,并且不需要知道版本。除此之外,也使用到了开篇所提到过的起步依赖,我们只需要引入 spring-boot-starter-web 这一依赖,就可以使用到 Web 中常用的包。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent><dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
...
</dependencies>
如下图所示,我们使用到的 spring-boot-starter-web 依赖中,已经集成了常用的 mvc json 等相关依赖。
org.springframework.boot:spring-boot-starter-web🏺1.5.7.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-tomcat🏺1.5.7.RELEASE:compile
[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-core🏺8.5.20:compile
[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-el🏺8.5.20:compile
[INFO] | | \- org.apache.tomcat.embed:tomcat-embed-websocket🏺8.5.20:compile
[INFO] | +- org.hibernate:hibernate-validator🏺5.3.5.Final:compile
[INFO] | | +- javax.validation:validation-api🏺1.1.0.Final:compile
[INFO] | | \- com.fasterxml:classmate🏺1.3.4:compile
[INFO] | +- com.fasterxml.jackson.core:jackson-databind🏺2.8.10:compile
[INFO] | | +- com.fasterxml.jackson.core:jackson-annotations🏺2.8.0:compile
[INFO] | | \- com.fasterxml.jackson.core:jackson-core🏺2.8.10:compile
[INFO] | +- org.springframework:spring-web🏺4.3.11.RELEASE:compile
[INFO] | \- org.springframework:spring-webmvc🏺4.3.11.RELEASE:compile
[INFO] | \- org.springframework:spring-expression🏺4.3.11.RELEASE:compile
4、开发功能
4.1 定义实体类 Book
如你所见,Book 类就是简单的 Java 对象,其中有些描述书的属性,还有必要的访问方法。
@Entity 注解表明它是一个 JPA 实体,id 属性加了 @Id 和 @GeneratedValue 注解,说明这个字段
是实体的唯一标识,并且这个字段的值是自动生成的。
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;/**
- Created by weijie_huang on 2017/9/20.
*/@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String reader;
private String isbn;
private String title;
private String author;
private String description;
}
4.2 定义仓库接口 ReadRepository
通过扩展 JpaRepository,ReadingListRepository 直接继承了 18 个执行常用持久化操作
的方法。JpaRepository 是个泛型接口,有两个参数:仓库操作的领域对象类型,及其 ID 属性的
类型。此外,我还增加了一个 findByReader() 方法,可以根据读者的用户名来查找阅读列表。
import com.jaycekon.demo.domain.Book; import org.springframework.data.jpa.repository.JpaRepository;import java.util.List;
/**
- Created by weijie_huang on 2017/9/20.
*/
public interface ReadRepository extends JpaRepository<Book,Long> {
List<Book> findByReader(String reader);
}
4.3 定义控制层 ReadController
在定义好了应用程序的实体类,持久化接口后。我们还需要创建一个 MVC 控制器来处理 HTTP 请求。
import com.jaycekon.demo.dao.ReadRepository; import com.jaycekon.demo.domain.Book; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;import java.util.List;
/**
- Created by weijie_huang on 2017/9/20.
*/
@Controller
public class ReadController {
@Autowired
private ReadRepository readRepository;@RequestMapping(value="/{reader}", method= RequestMethod.GET)
public String readersBooks(
@PathVariable("reader") String reader,
Model model) {
List<Book> readingList =
readRepository.findByReader(reader);
if (readingList != null) {
model.addAttribute("books", readingList);
}
return "readingList";
}@RequestMapping(value="/{reader}", method=RequestMethod.POST)
public String addToReadingList(
@PathVariable("reader")String reader, Book book) {
book.setReader(reader);
readRepository.save(book);
return "redirect:/{reader}";
}}
使用了 @Controller 注解,这样组件扫描会自动将其注册为
Spring 应用程序上下文里的一个 Bean。通过 @Autowired 将仓库接口注入到控制类中。
4.4 启动服务
在开发完成后,我们去到 Application 类下,启动 main 方法。即可将应用程序启动,然后进入到下述页面(html 文件不细述,可通过查看源码进行了解)。可以看到,我们的服务已经成功启动。
4.5 流程分析
大家可能会很疑惑,为什么我们没有配置数据库信息,却没有报异常。我们明明创建了 ReadRepository 数据库接口,如果没有 DataSource 的话,应该是会报异常的。但是 Spring boot 却巧妙的避开了这种问题。
首先我们需要来了解一下 Spring-boot-autoconfigure 这个依赖包。这个 Jar 包下包含了很多的配置类。例如 Thymeleaf,JPA 以及 Mvc 的相关配置。
这里主要涉及到了 Condition 接口,该接口的作用是,只有到某个条件达成后,才回对这个 Bean 进行实例化。
注解:
- @ConditionalOnBean 配置了某个特定 Bean
- @ConditionalOnMissingBean 没有配置特定的 Bean
- @ConditionalOnClass Classpath 里有指定的类
- @ConditionalOnMissingClass Classpath 里缺少指定的类
- @ConditionalOnExpression 给定的 Spring Expression Language(SpEL)表达式计算结果为 true
- @ConditionalOnJava Java 的版本匹配特定值或者一个范围值
- @ConditionalOnJndi 参数中给定的 JNDI 位置必须存在一个,如果没有给参数,则要有 JNDI
- @ConditionalOnProperty 指定的配置属性要有一个明确的值
- @ConditionalOnResource Classpath 里有指定的资源
上述程序之所有没有进行数据库操作,主要可以参考 DataSourceAutoConfiguratio 这个类的相应配置。
@Configuration @ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class}) @EnableConfigurationProperties({DataSourceProperties.class}) @Import({Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class}) public class DataSourceAutoConfiguration
可以看到,只有 DataSource 这个类实例化之后,这个 Bean 才会进行实例化。我们再往下观察可以看到 JdbcTemplateConfiguratio 也有想类似的情况。
此处看到的只是 DataSourceAutoConfiguration 的冰山一角,Spring Boot 提供的其他自
动配置类也有很多知识没有提到。但这已经足以说明 SpringBoot 如何利用条件化配置实现自动配置。
自动配置会做出以下配置决策,它们和之前的例子息息相关。
- 因为 Classpath 里有 H2 , 所以会创建一个嵌入式的 H2 数据库 Bean , 它的类型是
javax.sql.DataSource,JPA 实现(Hibernate)需要它来访问数据库。
- 因为 Classpath 里有 Hibernate(Spring Data JPA 传递引入的)的实体管理器,所以自动配置
会配置与 Hibernate 相关的 Bean , 包括 Spring 的 LocalContainerEntityManager-
FactoryBean 和 JpaVendorAdapter。
- 因为 Classpath 里有 Spring Data JPA,所以它会自动配置为根据仓库的接口创建仓库实现。
- 因为 Classpath 里有 Thymeleaf,所以 Thymeleaf 会配置为 Spring MVC 的视图,包括一个
Thymeleaf 的模板解析器、模板引擎及视图解析器。视图解析器会解析相对于 Classpath 根
目录的 /templates 目录里的模板。
- 因为 Classpath 里有 Spring MVC ( 归功于 Web 起步依赖), 所以会配置 Spring 的
DispatcherServlet 并启用 Spring MVC。
- 因为这是一个 Spring MVC Web 应用程序,所以会注册一个资源处理器,把相对于 Classpath
根目录的 /static 目录里的静态内容提供出来。(这个资源处理器还能处理 /public、/resources
和 /META-INF/resources 的静态内容。)
- 因为 Classpath 里有 Tomcat(通过 Web 起步依赖传递引用),所以会启动一个嵌入式的 Tomcat
容器,监听 8080 端口。
总结
通过 Spring Boot 的起步依赖和自动配置,你可以更加快速、便捷地开发 Spring 应用程序。起步依赖帮助你专注于应用程序需要的功能类型,而非提供该功能的具体库和版本。与此同时,自动配置把你从样板式的配置中解放了出来。这些配置在没有 Spring Boot 的 Spring 应用程序里非常常见。
虽然自动配置很方便,但在开发 Spring 应用程序时其中的一些用法也有点武断。要是你在配置 Spring 时希望或者需要有所不同,该怎么办?在第 3 章,我们将会看到如何覆盖 Spring Boot 自动配置,借此达成应用程序的一些目标,还有如何运用类似的技术来配置自己的应用程序组件。
github 地址:https://github.com/jaycekon/SpringBoot