Springboot
一个SpringBoot项目
创建POM配置文件
首先导入一个特殊的依赖:spring-boot-starter-parent
,这个是一个SpringBoot启动器,如果需要开发web项目,需要导入spring-boot-starter-web
启动器,常用的启动器还有:
spring-boot-starter-aop
:使用 Spring AOP 和 AspectJ 进行面向方面编程的启动器;spring-boot-starter-amqp
:使用 Spring AMQP 和 Rabbit MQ 的启动器;spring-boot-starter-data-jdbc
:使用 Spring Data JDBC 的启动器;spring-boot-starter-data-redis
:将 Redis 键值数据存储与 Spring Data Redis 和 Lettuce 客户端一起使用的启动器;spring-boot-starter-mail
:使用 Java Mail 和 Spring Framework 的电子邮件发送支持的启动器;spring-boot-starter-security
:使用 Spring Security 的启动器;spring-boot-starter-thymeleaf
:使用 Thymeleaf 视图构建 MVC Web 应用程序的启动器;spring-boot-starter-validation
:使用带有 Hibernate Validator 的 Java Bean Validation 的启动器;spring-boot-starter-websocket
:使用 Spring Framework 的 WebSocket 支持构建 WebSocket 应用程序的启动器;spring-boot-starter-logging
:使用 Logback 进行日志记录的启动器。默认日志记录启动器;spring-boot-starter-log4j2
:使用 Log4j2 进行日志记录的启动器;
Maven依赖管理
Spring Boot 的每个版本都提供了它支持的依赖项的精选列表。实际上,我们不需要在构建配置中为任何这些依赖项提供版本,因为 Spring Boot 会为我们自动管理,很好的避免了环境冲突造成的问题;
dependencyManagement: 一个对所依赖jar包进行版本管理的管理器,只对jar进行版本管理,不会导入相关的jar包;下面定义dependencies标签,对于没有使用version指定jar包版本,maven就会到dependencyManagement标签里面去找有没有对该artifactId和groupId进行过版本声明,如果有,就继承它,如果没有就会报错,告诉你必须为dependency声明一个version;
一般dependencyManagement标签在父工程中使用,在子工程中引用,可以保证项目中各个子工程的版本一致;properties: 可以用来指定${}标签的值,方便同一管理;
scope: 指定导入依赖的作用空间;
executions: 执行器,可以在Maven中指定执行目标goals,执行相应的命令,一般使用:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
如果使用了spring-boot-starter-parent
导入项目,则不需要该配置;
layout: 存档的类型,可能的值为JAR
, WAR
, ZIP
, DIR
, NONE
;
includes: 要包含的工件定义的集合,该元素定义了强制groupId
和artifactId
属性以及可选的强制groupId
和artifactId
属性以及可选classifier
属性;
excludes: 要排除的工件定义的集合;
excludeDevtools: 从重新打包的存档中排除 Spring Boot devtools;
spring-boot-starter-parent
spring-boot-starter-parent的作用是
- Java 1.8 作为默认编译器级别;
- UTF-8 源编码;
- 一个从 POM 继承的依赖管理部分,
spring-boot-dependencies
用于管理公共依赖的版本。这种依赖管理允许您在自己的 POM 中使用这些依赖项时省略version标签; - 具有执行 ID的
repackage
目标的执行; - 合理的资源过滤;
- 合理的插件配置;
- 对特定于配置文件的文件(application.yml、application-dev.properties、application-dev.yml)进行合理的资源过滤;
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
devtools热部署
Devtools 通过监视类路径的变化来工作。这意味着必须“构建”静态资源更改才能使更改生效,在 IDEA 中,Make Project 命令会触发必要的构建;在生产环境下,不可以使用Devtool工具,在使用Maven打包时需要使用excludeDevtools标签将Devtools排除打包;
如果您使用 Thymeleaf,请设置spring.thymeleaf.cache
为false
.
原理:
重新启动功能是通过使用两个类加载器实现的,一个类加载器主要是不可修改的类,一个是程序员自定义的类,当修改时,只会重新加载修改部分的类加载器,所以重启速度很快;
在IDEA中通过构建项目 ( Build +→+ Build Project
) ;
常用的配置项:
spring:
devtools:
restart:
# 禁用日志报告
log-condition-evaluation-delta: true
# 不需要修改触发重启的文件目录
# 默认:META-INF/maven/**,META-INF/resources/**,resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class,git.properties,META-INF/build-info.properties
exclude: application.yml
# 默认配置下还需要在新增的排除目录
additional-exclude:
# 添加需要监视修改文件后重启的路径
additional-paths:
# 是否禁用自动重启
enabled: true
YAML文件
用于为 Bean读入数据,主要的导入YAML文件的方法有几种:
- 在Java类中使用
@ConfigurationProperties
的prefix
属性绑定YAML文件的数据前缀,使用从文件中导入数据到Java类中的变量值; - 还有一种方法,可以通过
@Componet
和@Value
实现外部数据的导入; - 使用
@PropertySource
导入文件的相对路径,搭配@Value
注解使用EL表达式导入外部数据,或者搭配@ConfigurationProperties
各种数据类型:
person:
name: dazhou
age: 18
email: 1231414144@qq.com
maplist:
- name1: name1
value1: value1
- name2: name2
value2: value2
map:
key1: value1
key2: value2
list:
- value1
- value2
- value3
切换开发环境
在YAML文件中,切换不同的开发环境的几种方法:
-
在一个YAML文件中,使用
---
符号,分割不同的YAML文档:这个方法写入一个YAML文件,使用
---
分隔不同的文件块,使用spring.profiles.active: test
激活对应的文件块,spring.config.activate.on-profile: dev
指定不同的文件块对应不同开发环境; -
多个YAML文件,分为一个主配置文件和多个不同开发环境的YAML文件:
使用多个YAML文件,在主配置文件
application.yaml
文件中使用spring.profiles.active: dev
切换不同的开发环境配置文件,其他配置文件命名为application-dev.yaml
,其中dev为主配置文件中的切换配置文件的标识符;
JSR303数据校验
导入依赖,在实体类中使用注解@Validaed
标注,在指定的属性名上使用注解@Email
等,如果属性值不满足注解的要求就会报错;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
@Validated
public class Person {
private String name;
private Integer age;
/*
error==>Reason: 不是一个合法的电子邮件地址
*/
@Email //要求为电子邮件
private String email;
}
松散赋值
在yaml文件中,a_b与aB对于yaml文件来说是一样的。
日志配置
门面模式:SLF4j
门面模式,其核心为外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用,SLF4j是门面模式的典型代表,不同的系统项目可能使用了不同的日志配置,比如Logback,Log4j等,所以我们需要通过SLF4j对日志进行统一的管理,让调用端不用关注日志是如何打印的,只需要关注打印日志本身,由SLF4j决定使用什么日志进行日志打印;slf4j只是一个日志标准,并不是日志系统的具体实现;
slf4j的主要功能
- 提供了日志的接口;
- 提供了获取具体日志对象的方法;
SLF4j的使用方法
-
需要导入相关的依赖:
导入slf4j的依赖,导入slf4j直接或间接实现的日志依赖包;
-
在Java类中调用日志打印:
Logger logger = LoggerFactory.getLogger(Object.class);
可以使用logger打印对应的日志,info,error,warn等
- 在xml文件中配置自定义的日志格式,见logback详解
Thymeleaf
导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Thymeleaf模板引擎的作用是,渲染动态数据成静态页面,类似于jsp模板引擎;在springboot中,可以发现thymeleaf的默认解析为下所示,将html页面放到templates目录中,才会被视图解析器识别,后缀指定为html文件;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
html页面中引入依赖
thymeleaf基本语法
-
变量表达式:
${...}
-
选择变量表达式:
*{...}
-
消息表达式:
#{...}
-
链接 URL 表达式:
@{...}
-
片段表达式:
~{...}
-
迭代:
th:each
在我们的模板中使用来迭代对象列表
<p th:each="user:${users}" th:text="${user}"></p>
<p th:each="user:${users}">[[${user}]]</p>
<p th:if="3>2" th:text="${msg}"></p>
<div th:each="user:${users}" th:switch="${user}">
<p th:case="'user1'">user1-1</p>
<p th:case="'user7'">user2-2</p>
</div>
主启动类
主启动类即使用了注解@SpringApplication
标注的类,这个类在启动时,会完成以下四件事情:
- 判断当前的项目是普通项目还是web项目
- 查找并加载所有可用的初始化器,设置到initializers属性中
- 找出所有的应用程序监听器,设置到listeners属性中
- 推断并设置main方法的定义类
自动装配原理
Spring Boot 自动配置尝试根据您添加的 jar 依赖项自动配置您的 Spring 应用程序。可以在一个类上使用@Configuration
注解来说明该类是一个spring配置类,方法上使用@Bean
注解来说明该方法是一个springBean;使用注解@EnableAutoConfiguration
注解说明启用springboot的自动配置机制,同时需要使用@SpringBootConfiguration
注解来允许在上下文中注册额外的 bean 或导入额外的配置类,即自定义配置类;
@SpringBootApplication
该注解中包含了@SpringBootConfiguration
和@EnableAutoConfiguration
和@ComponentScan
三个注解;
@EnableAutoConfiguration
的实现:
在@EnableAutoConfiguration
注解中导入了@Import({AutoConfigurationImportSelector.class})
,即选择器;在选择器中,使用方法getAutoConfigurationEntry()
得到自动配置的实体类,该方法调用getCandidateConfigurations()
来得到候选的配置类,该方法又使用getSpringFactoriesLoaderFactoryClass()
来加载被配置的类,方法中返回EnableAutoConfiguration.class,即被@EnableAutoConfiguration
标注的类;
但不是所有自动配置类都会生效,在boot中有以一种注解@ConditionalOnClass
,即条件变量,只有当满足了设置条件时,才可以使自动配置生效;所有的自动配置类都记录在spring.factories文件中
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
//获得自动配置的类
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//获得候选的配置类
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
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;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
@ConditionalOnClass
注解的理解
这一类注解起到了条件判定的作用,只有当被标注的类满足了该注解设定的条件,自动配置类才会在该类中生效;