Spring Boot相信在接触Spring的过程中听到了很多次,其实就是一个用来简化Spring应用开发的初始搭建和开发过程,在之前我们无论是使用Spring还是Spring MVC或者Spring Security,总要先进行各种各样的配置,而且很多配置也依然是模板化的。
约定大于配置逐渐成为了开发者的共识,Spring 4就从XML配置转向各种注解,但是相比很多脚本语言和其他后端,Spring的开发方式略显笨重。
Spring Boot是伴随着Spring 4一同发布的一个产品,也是基于Spring框架的IOC容器。从根本上讲,Spring就是一些库的有机集合,是Spring的一个封装,所有用Spring做的事情,也可以用Spring Boot来做,很好的对应了现在的微服务的开发趋势。
Spring Boot的官网是https://spring.io/projects/spring-boot,可以找到详细的文档。
有了Spring的基础,学习的目标就是通过Spring Boot来创建一个完整的增删改查应用。
要创建一个Spring应用,要考虑的事情还真不少,比如:
- 选用哪种Maven原型
- 使用哪些依赖
- 使用哪种形式配置Spring,XML还是Java呢?
- 使用哪种HTTP服务,Tomcat还是JBOSS还是其他?
即使选择好了,也只是个开始,还要写几百行的配置,依赖,很多还是样板代码,比如前段转发器,视图解析器,数据库连接。如果配置写错了,还不太容易发现问题。
Spring Boot的出现就为了解决这些问题,可以减小手工配置的工作量,通过props文件或者classpath自动配置,解决依赖冲突,甚至还集成HTTP服务,一启动直接就可以访问。
https://start.spring.io/提供了一个初始化工具,用于快速的创建一个Spring Boot项目。
Spring Boot可以将项目打包成一个jar文件,直接运行就是一个Web服务,还提供了命令行工具,用于直接运行项目,也可以打包成War文件用于传统的部署方式。
Spring Boot 第一个简单项目
访问https://start.spring.io/,可以看到里边有很多选项:
Project
,是项目构建类型,可以选择是Maven项目还是Grandle项目
Language
,是采用的语言,可以选择Java,Kotlin和Groovy
Spring Boot
,是采用的Spring Boot的版本,目前稳定的大版本是最后的不带SNAPSHOT的版本2.1.3和1.5.19
Project Metadata
,是项目的源信息,就是Maven项目里的那些网站名,项目名称等。
Packaging
,这个配置需要展开More Options,Jar表示独立的Jar包,而War用于传统部署方式。
Java version
,8或者11。
Dependencies
,项目依赖,这个很重要,可以选下边的See all查看所有的依赖类型。有很多不同类型的应用可以开发。
下边就来创建一个Web项目,选择Maven项目,Java语言,2.1.3版本的Spring Boot,Group里填写cc.conyli.springbootdemo,Artifact中填写mydemo,选择Jar包和Java 8版本。
之后在项目依赖中选择Web大类下边的第一个Web,包含Tomcat服务器和Spring MVC。
然后点击最下边的Generate Project - alt + ⏎
按钮,会下载一个和Artifact同名的zip文件。这个ZIP文件解压到同名目录中,其实就是一个项目目录。
进入Intellij,选择File --> New --> Project From Existing Sources,然后选择下边的导入Maven项目,之后会识别出这个项目,如果已经打开Maven自动检测的话,现在Intellij就会开始配置这个项目了。
项目配置结束之后,可以看到自动写了一个类:
package cc.conyli.springbootdemo.mydemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MydemoApplication {
public static void main(String[] args) {
SpringApplication.run(MydemoApplication.class, args);
}
}
虽然还没有开始学,但是看这个代码,大概是知道SpringApplication是一个启动器,来运行我们这个类。其实这个时候能够看到Intellij右上角已经将这个类加入到了可运行中,而不像普通的Web项目需要配置服务器。先运行一下看看。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.3.RELEASE)
2019-03-26 16:31:56.300 INFO 101568 --- [ main] c.c.s.mydemo.MydemoApplication : Starting MydemoApplication on minko with PID 101568 (D:\Coding\Java\mydemo\target\classes started by Minko in D:\Coding\Java\mydemo)
2019-03-26 16:31:56.302 INFO 101568 --- [ main] c.c.s.mydemo.MydemoApplication : No active profile set, falling back to default profiles: default
2019-03-26 16:31:57.451 INFO 101568 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-03-26 16:31:57.481 INFO 101568 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-03-26 16:31:57.481 INFO 101568 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.16]
2019-03-26 16:31:57.487 INFO 101568 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:\Program Files\Java\jdk1.8.0_191\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\VanDyke Software\Clients\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;c:\users\minko\appdata\local\programs\python\python36\Scripts;C:\WINDOWS\System32\OpenSSH\;D:\Software\MySQL\bin\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;D:\Software\Redis\;D:\Software\Git\cmd;D:\Software\Nodejs\;D:\Software\dev\node\lib\;C:\Program Files (x86)\Brackets\command;C:\Program Files\Java\jdk1.8.0_191\bin;;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Users\Minko\AppData\Local\Programs\Python\Python36\Scripts\;C:\Users\Minko\AppData\Local\Programs\Python\Python36\;C:\Users\Minko\AppData\Local\Microsoft\WindowsApps;C:\Users\Minko\AppData\Roaming\npm;D:\Software\Microsoft VS Code\bin;C:\Program Files\IntelliJ IDEA 2018.3.2\bin;;.]
2019-03-26 16:31:57.568 INFO 101568 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-03-26 16:31:57.568 INFO 101568 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1213 ms
2019-03-26 16:31:57.777 INFO 101568 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-03-26 16:31:57.966 INFO 101568 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-03-26 16:31:57.969 INFO 101568 --- [ main] c.c.s.mydemo.MydemoApplication : Started MydemoApplication in 2.172 seconds (JVM running for 3.263)
Wow,这是什么。仔细查看一下,发现Tomcat initialized with port(s): 8080 (http),启动了Tomcat。访问localhost:8080
,出现了如下页面:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Mar 26 16:34:37 CST 2019
There was an unexpected error (type=Not Found, status=404).
No message available
没有配置/对应的路径,虽然是个错误页面,但是知道,这个Spring Boot程序已经成功运行,并且成为一个Web服务了。那后边就可以编写具体应用了。
Spring Boot REST 控制器
先来看看Spring Boot里怎么使用控制器,来尝试着写一个简单的REST控制器:
package cc.conyli.springbootdemo.mydemo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
@RestController
public class MyRestController {
@GetMapping("/")
public String sayHello() {
return "Hello! Time on server is " + LocalDateTime.now();
}
}
停止掉运行的Spring Boot程序,再重新运行,再访问localhost:8080
,结果发现输出已经有所改变。
刚才做的,实际上是Spring Boot为简化了配置,只需要简单的启动一个Java类,具体配置不用怎么关心,就可以编写业务代码了,而且可以发现,业务代码的编写与Spring MVC中是完全一致。
成功运行了第一个项目,现在可以来深入看一下Spring Boot了。
Spring Boot 项目结构与注解配置详解
项目结构
来看一下从https://start.spring.io/下载到的压缩包内的文件,这就是基础的项目文件:
src/main/java/自定义包名
,存放Java源代码的地方
src/main/test/java/自定义包名
,存放单元测试代码的地方
src/main/resources
,存放应用所需的配置文件,其实就是classpath对应的地方
mvnw.cmd 和 mvnw
,是Maven Wrapper File,让用户没有安装Maven也可以运行这个来下载和安装Maven进而配置项目,.cmd用于windows系统,mnvw用于linux系统。如果是用支持Maven的IDE,这两个文件可以忽略
pom.xml
,Maven配置文件。
项目入口类
再来看一下压缩包里自动生成的那个类:
package cc.conyli.springbootdemo.mydemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MydemoApplication {
public static void main(String[] args) {
SpringApplication.run(MydemoApplication.class, args);
}
}
这个类之前相当于是启动项目的一个入口。这里要解释的是@SpringBootApplication
注解,这个注解相当于同时具有以下三个注解的功能:
@EnableAutoConfiguration
,启用Spring Boot的自动配置
@ComponentScan
,启用默认的扫描Bean的功能
@Configuration
,将当前类当做配置类,并且可以导入其他配置类
后两个其实就是Spring 原始的注解。这里要注意的是,由于这个入口类使用了@ComponentScan
,所以默认扫描的范围就是这个类所在的同级类和包。一定要注意这一点。一般开发中,将这个入口程序放在你的程序包的根目录。
如果确实需要自己配置扫描路径,就采用如下写法:
@SpringBootApplication(scanBasePackages = {"cc.conyli","controller"})
public class MydemoApplication {
public static void main(String[] args) {
SpringApplication.run(MydemoApplication.class, args);
}
}
resources目录
这个目录之下有一个application.properties文件,这个文件是Spring Boot启动时自动创建的,默认为空,在其中可以添加Spring Boot的设置以及自定义的键值对。来添加两个:
server.port=8000
daughter.name=cony
然后在代码中,就可以使用取值表达式来取得其中的内容,修改一下我们的Rest控制器:
@RestController
public class MyRestController {
@Value("${daughter.name}")
private String name;
@GetMapping("/")
public String sayHello() {
return "Hello " + name + "! Time on server is " + LocalDateTime.now();
}
}
再启动服务,此时端口变成了8000端口,响应也读出了自定义的属性。
这里有一点要注意的是,如果要打包成Jar文件,不要使用src/main/webapp目录,否则会被大部分构建工具忽略,只有War文件需要部署到服务器目录下边之后,才需要这个目录。
对于Web开发,这个目录下有static目录,用于存放静态文件。
还有templates目录,用于存放模板文件,也就是JSP或者其他模板文件。Spring Boot对于一些第三方模板引擎都支持,比如FreeMarker,Thymeleaf,Mustache等。默认情况下Spring Boot就会从这个目录内载入模板文件。
最后就是单元测试的目录,测试也是很重要的一环,之后还是要好好学习一下测试的。
Spring Boot Starter
看完了项目结构,来实际看一下pom.xml
文件:
<dependencies>
<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>
</dependency>
</dependencies>
这里没有像之前我们要一个一个将所有的依赖写好,直接使用了两个spring-boot的依赖,这个配置就来自于在https://start.spring.io/中选择的内容。
这其中还自动配置了Maven-plugin,可见真的非常方便。
那么starter-web和starter-test究竟是什么呢,其实就是封装好的一个所有兼容的版本库,省去一个一个配置具体需要的依赖。在https://start.spring.io/生成压缩包的时候,选择依赖的地方就有全部的starter依赖可供选择。
常用的Web开发的依赖有:
spring-boot-starter-web
,包含
spring-boot-starter-security
,包含Spring Security
spring-boot-starter-data-jpa
,包含JPA的支持,比如Hibernate
在官网文档可以查看所有的starter依赖。
如果还是想要知道实际的依赖有哪些,Intellij中可以选择View --> Tool Windows --> Maven,然后在右侧的Dependencies中可以详细查看所有实际的依赖内容。经过查看可以看到里边包含有Spring MVC和全套依赖,Hibernate的Validator,集成Tomcat,Jackson等,涵盖了之前使用的大部分包。
对于这些配置在依赖里的starter,无需提供版本号。
Spring Boot还提供了一个特殊的Starter Parent
,这是提供为Maven项目提供一些初始配置,可以在pom.xml文件中看到这样一段:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
与普通的starter不同的是,这个parent需要配置版本号。
只要使用网站上的项目生成器,就会自动包含这个parent。parent主要是配置了默认的编译级别(选的是Java 8),然后启用UTF-8支持,还有其他的一些配置。如果要修改parent的配置,需要在与parent标签同级的properties标签中设置具体的键(标签名)和值。
Spring Boot devtools
现在我们每修改一次代码,就要关闭然后重新运行项目入口。通过在pom.xml中加入一个依赖,就可以实现自动更新代码:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
devtools的文档在此。还有很多功能如果有空可以慢慢研究。
顺便一提的是这个功能现在很多IDE也可以实现。
Spring Boot Actuator
说到Spring Boot,不能不提的就是Actuator。这个是一个特殊的Spring Boot模块,不像其他模块用于业务开发,这个模块专门通过端点(就是URL路径)来向外界暴露当前应用的信息,很显然,这是一个非常好的开发辅助工具。这个工具就是Actuator。
要启用很容易,只需要在pom.xml中加入如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
在启用之后,项目自动会增加一个路径/actuator
,可以通过这个路径获得各种信息,都是REST风格的JSON,常用的有:
/actuator
,简单的查询指南
/actuator/health
,应用运行状态
/actuator/info
,项目信息
/actuator/beans
,查看容器里所有的Bean
/actuator/mappings
,查看所有的URL映射关系
/actuator/health
返回的JSON是:
{
"status": "UP"
}
/actuator/info
默认返回空,因为没有配置信息,可以在application.properties文件中配置一些:
info.app.name=SB Project
info.app.description=Sekiro is good and easy to play!
info.app.version=0.0.1
之后再访问,可以获得如下的JSON:
{
"app": {
"name": "SB Project",
"description": "Sekiro is good and easy to play!",
"version": "0.0.1"
}
}
在这里还能看到更多的暴露的端点,但是这里要注意的是,通过观察Spring Boot的启动日志以及文档,可以发现HTTP方式下默认仅暴露了2个端点health和info。
可以在application.properties文件中写一句来打开全部端点:
management.endpoints.web.exposure.include=*
端点信息安全防护
如果不想将信息暴露给外界,可以添加Spring Security:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Spring Security会自动配置Spring Boot Actuator相关的验证,而不像我们之前要创建初始化类和配置文件。观察控制台的输出:
Using generated security password: e0d04d71-b283-430e-948a-4e20a48f2422
可以得到密码,用户名默认是user
,再访问除了/health和/info之外的端点,就会被要求输入用户名和密码。
如果想自定义用户名和密码,需要在application.properties文件中配置:
spring.security.user.name=cony
spring.security.user.password=li
这样就可以用自定义的用户名和密码来访问Spring Boot Actuator
如果要更详细的配置,比如通过Spring Security从数据库中读取用户和角色控制,可以具体配置Spring Security,针对/actuator
下边的具体路径配置即可。
默认/health和/info无需认证,还可以在application.properties文件中配置关闭这两个端点:
management.endpoints.web.exposure.exclude=health,info
这样就在启用Spring Boot Actuator的同时用Spring Security进行了保护,防止信息泄露。
通过命令行运行Spring Boot
现代开发一般都通过使用IDE进行开发,运行程序也是通过IDE来运行。很多时候如果需要简单启动项目,可能需要在没有IDE的情况下运行。
在命令行模式下运行Spring Boot有两种方式:
- 在命令行下使用
java -jar
- 在命令行下使用
mvnw spring-boot:run
java -jar方式
以下是Windows的操作。关闭IDE,到项目的根目录下,运行:
mvnw package
会提示发现maven-wrapper.jar,如果没有安装Maven,就会自动下载,然后会慢慢将项目及所有依赖进行打包。这里要按几下回车才开始打包工作。看到如下内容说明打包成功:
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:3.1.1:jar (default-jar) @ mydemo ---
[INFO] Building jar: D:\Coding\Java\mydemo\target\mydemo-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.1.3.RELEASE:repackage (repackage) @ mydemo ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:44 min
[INFO] Finished at: 2019-03-27T15:23:24+08:00
[INFO] ------------------------------------------------------------------------
如果已经安装了Maven,直接使用这条命令:
mvn package
就可以进行打包。
打包完成后可以看到提示,生成了mydemo\target\mydemo-0.0.1-SNAPSHOT.jar
文件。
然后进入target目录,调用java虚拟机执行这个jar文件:
java -jar mydemo-0.0.1-SNAPSHOT.jar
之后可以在控制台看到和在IDE里一样的Spring Boot启动信息,测试一下访问,发现成功启动了。
mvnw spring-boot:run方式
将另外一个方法生成的jar包删除。在项目根目录输入:
mvnw spring-boot:run
可以看到编译了类之后直接启动了项目。