Spring Boot
瞻山识璞,临川知珠
1. 概述
- 定义
SpringBoot是一个基于Spring4.0的javaweb快速开发框架,策略:开箱即用和约定优于配置,作者:Pivotal团队
- 与SSM区别
序号 | SSM | SpringBoot |
---|---|---|
1 | Tomcat:war包 | 内嵌Tomcat :jar包 |
- 微服务
微服务是一种高内聚,低耦合架构风格,James Lewis,Martin Fowler
- SpringBoot 2.7.8要求
工具 | Version |
---|---|
jdk | Java 8 |
Spring Framework | 5.3.25 |
Maven | 3.5+ |
Gradle | 6.8.x, 6.9.x, and 7.x |
Tomcat 9.0 | 4.0 |
Jetty 9.4 | 3.1 |
Jetty 10.0 | 4.0 |
Undertow 2.0 | 4.0 |
2. 项目结构分析
2.1 创建方式
- 阿里云镜像导入
- spring官网导入
- idea创建(推荐)选择spring initalizr
2.2 项目结构
1、程序的主启动类(程序的主入口)
2、一个 application.properties 配置文件(SpringBoot的核心配置文件)
3、一个 测试类
4、一个 pom.xml
- 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--有一个父项目 控制版本与打包-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xxy</groupId>
<artifactId>helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>helloworld</name>
<description>first project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<!--所有的SpringBoot依赖都是spring-boot-starter开头-->
<dependencies>
<!--Web依赖:tomact.dispatcherServlet.xml-->
<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>
<!--热部署开发工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<!--jar包插件-->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.3 修改配置
- 修改端口
server.port=8081
- 修改运行图标
-
banner.txt
__
/\ .-" /
/ ; .' .'
: :/ .'
\ ;-.'
.--""""--..__/ `.
.' .' `o \
/ ` ;
: \ :
.-; -. `.__.-'
: ; \ , ;
'._: ; : (
\/ .__ ; \ `-.
没有bug ; "-,/_..--"`-..__)
'""--.._:
3. 原理初探
3.1 自动配置
-
pom.xml文件
- spring-boot-starter-parent 核心依赖在父工程中spring-boot-dependencies,锁定了版本,不需要写版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
- 启动器【springBoot 启动场景】
- spring-boot-starter,我们需要什么功能,找到对应的启动器就可以了,
starter
,比如spring-boot-starter-web就是自动导入web环境所有依赖
- spring-boot-starter,我们需要什么功能,找到对应的启动器就可以了,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
- 主程序
package com.xxy.helloworld;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//@SpringBootApplication 标注这是一个Spring Boot的应用,启动类
@SpringBootApplication
public class HelloworldApplication {
public static void main(String[] args) {
//将springBoot应用启动
//run 开启了一个服务
//SpringApplication 判断普通项目还是web项目,初始化器,监听器,找到Main的运行方法或者主类
SpringApplication.run(HelloworldApplication.class, args);
}
}
-
@SpringBootApplication下的注解
-
springboot配置
@SpringBootConfiguration
-
spring自动配置 全面接管SpringMVC的配置
@EnableAutoConfiguration
-
springboot自动配置扫描:有判断条件,只有导入了先对应的start,自动装配才会生效
@ComponentScan
@org.springframework.boot.SpringBootConfiguration //springboot的配置 - @Configuration //spring 配置类 -- @Component //说明者也是一个Spring的组件 @org.springframework.boot.autoconfigure.EnableAutoConfiguration //自动配置ioc注入类 - @AutoConfigurationPackage //自动配置包 --@Import({ Registrar.class}) //自动配置 ‘包注册’ - @Import({ AutoConfigurationImportSelector.class})//自动配置导入选择器 //获取所有(候选)的配置 -- protected List<String> getCandidateConfigurations AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");//自动配置中的核心文件 return configurations; }
-
-
结论:
springboot所有自动配置都是启动时进行加载:spring.factories,里面有判断条件,条件不满足,就会无效,有了启动器,自动装配才会生效;
自动装配的原理
- SpringBoot启动会加载大量的自动配置类
- 寻找我们的功能是否在默认自动配置中
- 查看自动配置类中配置了哪些组件 (没有就需要手动配置)
- 添加组件时会从properties类中获取一部分属性
- XX AutoConfigurartion:给容器添加组件
- XX Properties:封装配置文件的属性,.yaml
- 可以通过yml文件
debug: true
来查看自动配置的生效
3.2 SpringApplication类
- SpringApplication做了下面四件事
-
推断应用的类型是普通的项目还是Web项目
-
查找并加载所有可用初始化器 , 设置到initializers属性中
-
找出所有的应用程序监听器,设置到listeners属性中
-
推断并设置main方法的定义类,找到运行的主类
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
// ......
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.setInitializers(this.getSpringFactoriesInstances();
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
- run():
①配置环境参数
②推断并设置main方法的定义类,找到运行的主类
③run方法里面有一些监听器,这些监听器是全局存在的,它的作用是获取上下文处理一些bean,所有的bean无论是加载还是生产初始化多存在。
3.3 自动配置加深
- 自动配置原理
Spring Boot通过@EnableAutoConfiguration注解开启自动配置,对jar包下的spring.factories文件进行扫描,这个文件中包含了可以进行自动配置的类,当满足@Condition注解指定的条件时,便在依赖的支持下进行实例化,注册到Spring容器中。
通俗的来讲,springboot的自动配置就是用注解来对一些常规的配置做默认配置,简化xml配置内容,使你的项目能够快速运行。
- @Conditional派生注解
序号 | 注解名称 | 作用 |
---|---|---|
1 | @Conditional | 作用(判断是否满足当前指定条件) |
2 | @ConditionalOnJava | 系统的java版本是否符合要求 |
3 | @ConditionalOnBean | 容器中存在指定Bean |
4 | @ConditionalOnMissingBean | 容器中不存在指定Bean |
5 | @ConditionalOnExpression | 满足SpEL表达式指定 |
6 | @ConditionalOnClass | 系统中有指定的类 |
7 | @ConditionalOnMissingClass | 系统中没有指定的类 |
8 | @ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
9 | @ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
10 | @ConditionalOnResource | 类路径下是否存在指定资源文件 |
11 | @ConditionalOnWebApplication | 当前是web环境 |
12 | @ConditionalOnNotWebApplication | 当前不是web环境 |
13 | @ConditionalOnJndi | JNDI存在指定项 |
4. 注入配置文件
结论:用yaml更好,除了SPEL表达式;如果yml和properties同时都配置了端口,默认会使用properties配置文件的!
4.1 导入文件处理器
<!-- 防止@ConfigurationProperties(prefix = "person")注入报红-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
4.2 编写配置文件
- application.properties文件
# Spring Boot配置文件,修改SpringBoot自动配置的默认值
# 格式 key=value
- application.yaml文件
# Spring Boot yaml配置
# 规范: key:空格value
# yaml一般是utf-8格式,可以注入配置文件
# 设置服务器端口号
server:
port: 8081
# person对象赋值
person:
name: lisi${
random.uuid}
age: ${
random.int}
isHappy: false
birth: 2000/10/22
maps: {
k1: v1,k2: v2}
# hello: jj
lists:
- code
- music
- girl
dog:
name: ${
person.hello:hello}_旺财
age: 3
# 数组
pets: [cat,dog,pig]
# 行内规范对象
student: {
name: hh, age: dd}
4.3 进行绑定注入
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private int age;
private boolean isHappy;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
//get、set、toString方法
}
@Component
//加载指定的配置文件
@PropertySource(value = "classpath:dog.properties")
public class Dog {
//通过SPEL表达式取出配置文件的值
@Value("${name}")
private String name;
@Value("5")
private int age;
//get\set\toString方法
}
4.4 松散绑定
yaml可以是-和_和驼峰式命名相互绑定,根据set方法赋值
4.5 JSR303校验
@Validated//Spring数据验证 @Valid:JDK提供的(标准JSR-303规范),不知道用哪个可以直接找源码javax.validation.constraints
<!--jsr303验证-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
约束注解名称 | 约束注解说明 |
---|---|
@Null | 用于验证对象为null |
@NotNull | 用于对象不能为null,无法查检长度为0的字符串 |
@NotBlank | 只用于String类型上,不能为null且trim()之后的size>0 |
@NotEmpty | 用于集合类、String类不能为null,且size>0。但是带有空格的字符串校验不出来 |
@Size | 用于对象(Array,Collection,Map,String)长度是否在给定的范围之内 |
@Length | 用于String对象的大小必须在指定的范围内 |
@Pattern | 用于String对象是否符合正则表达式的规则 |
用于String对象是否符合邮箱格式 | |
@Min | 用于Number和String对象是否大等于指定的值 |
@Max | 用于Number和String对象是否小等于指定的值 |
@AssertTrue | 用于Boolean对象是否为true |
@AssertFalse | 用于Boolean对象是否为false |
@Past | 验证 Date 和 Calendar 对象是否在当前时间之前 |
@Future | 验证 Date 和 Calendar 对象是否在当前时间之后 |
4.6 配置文件yaml优先级(从高到低);互补配置;可以通过spring.config.location改变默认位置
– file:./config/
– file:./
–classpath:/config/
–classpath:/
4.7 配置文件服务端口配置(建议)
# 设置服务器端口号
server:
port: 8081
spring:
profiles:
active: dev
---
server:
port: 8082
spring:
profiles: dev
active: dev
---
server:
port: 8083
spring:
profiles: test
---
5. SpringBoot Web开发
5.1 静态资源
- WebMvcAutoConfiguration类源码
//源码
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
//判断是否自定义
logger.debug("Default resource handling disabled");
} else {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{
"/webjars/**"}).addResourceLocations(new String[]{
"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}//第一个静态资源的位置
String staticPathPattern = this.mvcProperties.getStaticPathPattern();//获取静态资源的路径
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{
staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
}
-
引入jquery静态资源
<!--引入jquery包-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
静态资源放的位置:(优先级从高到低),自己定义路径
# 自定义静态资源位置
spring.mvc.static-path-pattern=/hello/,classpath:/xxy/
- 导入依赖包,classpath:/META-INF/resources/webjars/
- classpath:/resources/
- classpath:/static/(默认)
- classpath:/public/
- /**
5.2 首页
- 源码
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
return welcomePageHandlerMapping;
}
private Optional<Resource> getWelcomePage() {
String[] locations = WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations());
return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}
private Resource getIndexHtml(String location) {
return this.resourceLoader.getResource(location + "index.html");
}
package com.xxy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//在templates目录下的所有页面,只能通过Controller来跳转
//需要模板引擎的支持 thymeleaf依赖
@Controller
public class IndexController {
@RequestMapping("/index")
public String index() {
return "index";
}
}
5.3 模板引擎(比较少用,大多数前后端分离,用来渲染,vue使用pug)
<!--导入Thymeleaf模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
5.4 装配扩展SpringMVC
- 自定义视图解析器
package com.xxy.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org