介绍
前置知识点
- Spring
- Maven
代码获取
wget https://labfile.oss.aliyuncs.com/courses/1152/springbootmavenshiyan2.zip
采用 Spring Initializr 搭建
Spring Initializr 是官方提供的一种快捷搭建 Spring Boot 应用的方式,网址为: https://start.spring.io/
我们可以在该网页选择构建工具、语言、Spring Boot 版本、group、artiface、依赖等信息。这里我们选择使用使用 Maven
构建,语言 java
,group 为 com.shiyanlou
,artifact 为 springboot
,依赖我们选择 web
,同时选择合适的 打包方式
及 java版本
,这里实验我们使用的 Spring Boot 版本为 2.0.4
,同学们可以根据需要自行选择其他版本。
点击 Generate,我们会得到一个 springboot.zip
的压缩包。同学们也可以在这里直接获取该压缩包,将其下载解压。
wget https://labfile.oss.aliyuncs.com/courses/1152/springboot.zip
unzip springboot.zip
接着切换工作空间到 springboot
目录,然后在 src/main/java
目录下新建包路径 com.shiyanlou.springboot.controller
。
在包中建立新类 ShiyanlouController.java
,代码如下:
package com.shiyanlou.springboot.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
// RestController 相当于同时使用 @Controller 和 @ResponseBody 注解
public class ShiyanlouController{
@RequestMapping("shiyanlou")
public String shiyanlou(){
return "Hello Shiyanlou";
}
}
项目文件结构如下:
然后打开 terminal,运行 mvn spring-boot:run
,这里使用 Spirng Boot 的 maven 插件启动。点击工具中的 Web 服务,接着修改地址栏为 https://**************.simplelab.cn/shiyanlou
如:
结果:
如果同学们不清楚代码中的相关注解如 @RequestMapping
等,可以先学习 Spring MVC 教程,因为 Spring Boot 是在 Spring 的基础上建立的。
目录结构详解
打开项目之后可以看到 Spring Boot 项目的目录结构如下:
如上图所示,Spring Boot 的目录结构主要由以下部分组成:
lou-springboot
├── src/main/java
├── src/main/resources
├── src/test/java
└── pom.xml
其中 src/main/java 表示 Java 程序开发目录,这个目录大家应该都比较熟悉,唯一的区别是 Spring Boot 项目中还有一个主程序类。
src/main/resources 表示配置文件目录,与普通的 Spring 项目相比有些区别,如上图所示该目录下有 static 和 templates 两个目录,是 Spring Boot 项目默认的静态资源文件目录和模板文件目录,在 Spring Boot 项目中是没有 webapp 目录的,默认是使用 static 和 templates 两个文件夹。
src/test/java 表示测试类文件夹,与普通的 Spring 项目差别不大。
pom.xml 用于配置项目依赖。
以上即为 Spring Boot 项目的目录结构,与普通的 Spring 项目存在一些差异,不过在平常开发过程中,这个差异的影响并不大,说到差别较大的地方可能是部署和启动方式的差异,接下来详细介绍 Spring Boot 项目的启动方式。
使用IDEA安装SpringBoot框架
点击 File->New->Project 创建新项目:
选择spring Initializr:
点击next 进行下一步:
点击完成之后打开项目:
点击右侧的maven图标,点击同步按钮,下载需要的依赖:
如果下载慢,可以切换maven镜像进行下载
编写Index控制器
package com.example.helloworld;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/index")
public String index(){
return "helloworld";
}
}
默认情况下主应用程序类(Main application class)只会扫描同一包下的Class。
如果我非要在不同的包下访问呢?很任性!!
那我们可以在application类上加上@ComponentScan的注解也是可以的。
它会在你启动Application时扫描括号内的包下面的类。
通过右上角的启动命令,一键编译+启动:
访问 http://localhost:8080/index (默认端口)
启动成功
如果我们没有在配置文件(application.properties)中配置端口号,Spring Boot项目则会采用默认的8080端口号,我们通过在配置文件中添加server.port=8004
将端口号改为不为8080的端口;
如下图:
手动构建 Spring Boot 项目
首先我们需要创建一个普通的 maven 项目 springboot
:
mvn archetype:generate \
-DgroupId=com.shiyanlou \
-DartifactId=springboot \
-DarchetypeArtifactId=maven-archetype-quickstart
参数说明:
- Group Id:项目的组织机构,也是包的目录结构,比如
com.example
。 - Artifact Id:项目名称。
- archetype Artifact Id:使用的 maven 骨架名称。
- interactive Mode: 当为 false 时关闭交互模式。
接着新建目录 src/main/resources
,在该目录下新建配置文件 application.properties
。这里不需要单元测试,所以将 src/test
目录删除。
创建过程中会提示输入版本号等,直接使用默认即可。接着输入 Y
确定创建。
接着建立目录 src/main/resources
,这里不要单元测试,所以将 src/test
目录删除,建立包路径 com.shiyanlou.springboot
和 com.shiyanlou.springboot.controller
。
最终的目录结构如下:
添加 maven 依赖,修改 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.shiyanlou</groupId>
<artifactId>springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot</name>
<description>Demo project for Spring Boot</description>
<!--设置父模块 这样就可以继承父模块中的配置信息-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--添加web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!--spirng Boot maven插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
项目依赖主要有四个部分:
- 项目元数据:创建项目时配置的元数据部分,也就是 Maven 项目的基本元素,包括:groupId、artifactId、version、name、description 等。
- parent:继承
spring-boot-dependencies
的依赖管理,控制版本与打包等内容。 - dependencies:项目具体依赖,这里包含了
spring-boot-starter-web
用于实现 HTTP 接口(该依赖中包含了 Spring MVC),更多功能模块的使用将在后面的教程中逐步学习。 - build:构建配置部分。默认使用了
spring-boot-maven-plugin
,配合spring-boot-starter-parent
就可以把 Spring Boot 应用打包成 JAR 包来直接运行。
在包 com.shiyanlou.springboot
中建立 SpringbootApplication.java
,代码如下:
package com.shiyanlou.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// @SpringBootApplication 注解相当于同时使用 @EnableAutoConfiguration、@ComponentScan、@Configurations 三个注解
// @EnableAutoConfiguration 用于打开 Spring Boot 自动配置,而其余注解为 Spring 注解,这里不再赘述
@SpringBootApplication
public class SpringbootApplication{
public static void main(String[] args){
SpringApplication.run(SpringbootApplication.class, args);
}
}
在包 com.shiyanlou.springboot.controller
下建立 ShiyanlouController.java
,代码如下:
package com.shiyanlou.springboot.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ShiyanlouController{
@RequestMapping("shiyanlou")
public String shiyanlou(){
return "Hello Shiyanlou";
}
}
以上代码中相关注解的作用解析:
@SpringBootApplication
:Spring Boot 应用的标识。表示这是一个 Spring Boot 配置类,并且该类还触发了自动配置和组件扫描功能,等于同时配置了@Configuration
注解、@EnableAutoConfiguration
注解和@ComponentScan
注解。@RestController
:之前在 Spring 中学习过,集合了@Controller
注解和@RequestBody
注解。该注解标识的类为一个控制器,且该类的所有方法的返回值都转换为 JSON 格式,同时将返回值写入到 Response 对象的 body 中。@GetMapping("/hello")
:HTTP GET 方式的/hello
请求都将映射到该方法进行处理。@RequestParam
:将方法参数绑定到请求参数。
该应用程序通过浏览器发送 GET 请求 /hello
路径,服务器接受请求并处理,最终响应“Hello World!”字符串。其中 main() 作为程序的入口,SpringApplication 用来启动应用,并且把 App 类作为 参数传递给 run() 方法。具体的 run() 方法用来启动嵌入式的 Tomcat 并初始化 Spring 环境及 Spring 的各个组件。
打开 terminal,输入。
注:一定要在项目目录中运行 maven 命令,比如这里是 Spring Boot 目录。
mvn spring-boot:run
点击工具中的 Web 服务,访问 https://**************.simplelab.cn/shiyanlou
,如果出现 Hello Shiyanlou
,那么就说明我们成功了!
Spring Boot 中的 Starter
仔细的同学们可能发现了,Maven 中我们只添加了一个依赖,那就是 spring-boot-starter-web
。我们知道之前使用 Spring 创建 Web 项目的时候,maven 依赖可是很长一条,这里居然这么少,没错就是这么少,其实里面的依赖都被封装好了。我们现在只添加了 Web 项目的依赖,如果我们要添加其他的依赖怎么办呢?同样的,比如我们访问数据库,那么我们可以添加持久层框架,比如 spring-data-jpa
,我们只需要添加 spring-boot-starter-data-jpa
依赖就可以了。
同学们应该都发现了,他们有一个共同点,都是 spring-boot-starter
开头,后面接上特定的应用程序,这样可以帮助我们快速找到我们所需要的 starter。官方提供的 starter 一般为 spring-boot-starter-*
,第三方一般为 *-spring-boot-starter
。
接下来我们来看看 Spring Boot 官方提供了哪些 Starter:
Spring Boot 应用 Starter
Spring Boot 生产相关 Starter
Spring Boot 容器和日志 Starter
Spring Boot项目启动
Main() 方法启动
与普通的 Web 项目相比,Spring Boot 启动项目减少了几个中间步骤,不用去配置 Servlet 容器,也不用打包并且发布到 Servlet 容器再去启动,而是直接运行主方法即可启动项目,开发调试都十分方便也节省开发时间。在你的本机上开发项目时,可以直接在 Eclipse 或者 IDEA 中运行 Spring Boot 主程序类即可,比如现在的项目中有 Application 类,可以直接运行它的 run() 方法,项目就能够正常启动了。
Maven 插件启动
由于 pom.xml 文件中引入了 spring-boot-maven-plugin 插件依赖,也可以直接使用 Maven 命令来启动 Spring Boot 项目。插件配置如下,如果 pom.xml 文件中没有该 Maven 插件,是无法通过这种方式启动 Spring Boot 项目的,这一点需要注意。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
启动过程过程如下图所示,首先点击下方工具栏中的 Terminal 打开命令行窗口,之后在命令行中输入命令 mvn spring-boot:run
并执行该命令即可启动项目,如下图所示,Spring Boot 项目启动成功。
java -jar 命令启动
项目初始化时我们选择的打包方式为 Jar ,因此项目开发完成进行打包时的结果是一个 Jar 包, Java 运行 Jar 包的命令为 java -jar xxx.jar
,结合以上两个原因我们可以使用这种方式启动 Spring Boot 项目,接下来我们来演示这一过程。
- 首先,点击下方工具栏中的 Terminal 打开命令行窗口
- 之后使用 Maven 命令将项目打包,执行命令为:
mvn clean package -Dmaven.test.skip=true
,等待打包结果即可 - 打包成功后进入 target 目录,
cd target
- 最后就是启动已经生成的 Jar 包,执行命令为
java -jar springboot-demo-0.0.1-SNAPSHOT.jar
这种方式也是 Spring Boot 上线时常用的启动流程,希望不熟悉的朋友都按照以上过程练习几次。
自动配置原理解析
当初在学习和使用 Spring 时,我们在构建一个项目时,需要繁杂的配置才能进行业务逻辑的编写。例如要实现上方的这样一个入门案例,我们需要配置前端控制器、过滤器、视图解析器以及配置包的扫描路径等相关设置。而 Spring Boot 将所有的功能场景都抽取出来,做成一个个的 Starters(启动器),只需要在项目里面引入这些 Starter 相关场景的所有依赖都会导入进来,要用什么功能就导入什么场景的启动器。
下面我们将从源码的角度看看 Spring Boot 是如何帮助我们简化这些配置。由于实验楼环境的 WebIDE 暂时不支持查看源码,我们借助于类似 IDEA 的开发工具来查看源码。
@SpringBootApplication
@RestController
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@GetMapping("/hello")
public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
return String.format("Hello %s!", name);
}
}
观察上方的入门代码,思考一下跟之前学习过的 Spring 代码有何异同。通过观察我们可以发现,在类上仅仅多了一个 @SpringBootApplication
注解,但是却减少了大量的配置。下面我们来逐步的剖析一下这个注解,看看它到底帮我们做了什么。在 IDEA 中,按住 Ctrl 键,点击此注解,进入到该注解的详情页面(对源码进行了适当的删减,不影响整体的讲解)。
上方源码中的基本的元注解作用已经进行了标识。@ComponentScan
注解较为简单就是开启组件扫描。接下来,我们将着力分析@SpringBootConfiguration
、 @EnableAutoConfiguration
这两个注解的作用,看看它到底帮助我们做了哪些工作。
@SpringBootConfiguration 注解
此注解单从字面意思来理解的话,表示该注解标识的类是一个 Spring Boot 配置类。 具体作用我们来通过它的源代码看一下。
注意观察上方的源码,@SpringBootConfiguration
注解被 @Configuration
注解修饰。在之前学习 Spring 框架时,我们已经接触过 @Configuration
注解,该注解用于定义 Spring 的配置类(XML 配置文件的注解表现形式),同时该注解所标注的类可以被实例化到 IOC 容器中。
由此可见,@SpringBootConfiguration
注解的作用与 @Configuration
注解相同。都是标识一个能够被组件扫描器扫描到的配置类。@SpringBootConfiguration
注解只是对 @Configuration
注解进行了封装与命名。
@EnableAutoConfiguration 注解
接下来,我们继续看 @EnableAutoConfiguration
注解。从字面意思来理解的话,此注解的作用为开启自动配置。Spring Boot 相对于 Spring 的其中一个优点就是自动配置功能。下面我们来看看该注解到底帮我们做了哪些工作,使得开发工作中避免了繁杂的配置。
@EnableAutoConfiguration 注解的源码如上所示。该注解除了被基本的元注解标注外,还被额外的两个注解标注。先简单介绍一下这两个注解的作用,再剖析它们的实现过程。
-
@AutoConfigurationPackage
:自动配置包,相当于 Spring 中配置包的扫描路径,让程序知道哪些路径下的 Bean 需要被实例化到 Spring 容器中。在 Spring Boot 中,将主配置类(由@SpringBootApplication 注解所标注的类)所在包及下面所有子包里面的所有 Bean 扫描到容器中。
-
@Import(AutoConfigurationImportSelector.class)
:给容器中导入大量的自动配置类(xxxAutoConfiguration),自动配置类根据场景(启动器类型)导入所有的组件,并配置好组件。例如,本案例选择的是 Web 启动器,该步骤中与 Web 相关的自动配置类将会帮我们配置好 Web 相关的组件例如前端控制器、过滤器、视图解析器等。
接下来,我们来逐个分析这两个注解的实现过程。
@AutoConfigurationPackage 注解
该注解被 @Import
注解所标注。 @Import
注解是 Spring 中的一个底层注解,用于向 IOC 容器中注入组件。
@Import
注解有三种注入方式:
@Import
({ 要导入的容器中的组件的全类名 } ):容器会自动注册这些组件。@Import
({ 实现ImportSelector
接口的全类名} ):返回需要导入的组件的全类名数组,然后容器自动注入组件。@Import
({ 实现ImportBeanDefinitionRegistrar
接口的全类名} ):手动注册 bean 到容器中。
在 IDEA 中,按住 Ctrl 键,点击 AutoConfigurationPackages.Registrar.class
。下面是该类的源码。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//new PackageImports(metadata).getPackageNames().toArray(new String[0]) 为获取注解信息中的包名
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
...
}
从上面代码可以看出,@Import
注解通过实现 ImportBeanDefinitionRegistrar
接口,重写 registerBeanDefinitions 方法的方式来自动配置包。该方法主要是将主配置类(由@SpringBootApplication 所标注的类)的所在包及下面所有子包里面的所有 Bean 扫描到容器中。
@Import(AutoConfigurationImportSelector.class)
该注解的具体作用向容器中导入大量的自动配置类,下面来看具体实现过程。
由 @Import
注入 AutoConfigurationImportSelector 类,该类的 selectImports()方法最终会通过 SpringFactoriesLoader.loadFactoryNames() 从类路径下的 META-INF/spring.factories
文件中获取 EnableAutoConfiguration
指定的值(其实就是所有的自动配置类的类名),将这些值作为自动配置类导入到容器中,自动配置类再依据相应的条件生效,然后进行自动配置工作例如像容器中添加组件,配置组件属性等。
spring.factories 文件可以通过下图所示的位置找到,该文件是由大量的 key = value 式的键值对组成的,其中 EnableAutoConfiguration 的值就在其中。
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,\
...省略了很多\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
总而言之,@EnableAutoConfiguration
注解是帮我们干了两件事,第一件事是自动配置包的扫描路径, 由 @AutoConfigurationPackage
注解负责完成;第二件事是将所需场景相关的自动配置类导入到容器中,这些自动配置类再帮我们自动配置所需的环境,由 @Import(AutoConfigurationImportSelector.class)
注解负责完成 。
本文由 liyunfei 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jun 29,2022