个人博客:http://blog.kunpw.cn/
SpringBoot
配置文件,主要有四个部分:
spring-boot-starter-parent
的依赖管理、控制版本和打包等内容;spring-boot-starter-web
用于实现HTTP接口(该依赖包含了Spring MVC,且使用Tomcat作为默认嵌入式容器),spring-boot-starter-test
是用于编写后续单元测试的依赖包:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
spring-boot-maven-plugin
,即打jar包插件;src/main/javaresource/application.properties
目录核心配置文件;# 直接更改项目端口号即可,修改之后再次访问该端口才能成功
server.port=8081
src/main/javaresource/banner.txt
目录文件;
// _ooOoo_ //
// o8888888o //
// 88" . "88 //
// (| ^_^ |) //
// O\ = /O //
// ____/`---'\____ //
// .' \\| |// `. //
// / \\||| : |||// \ //
// / _||||| -:- |||||- \ //
// | | \\\ - /// | | //
// | \_| ''\---/'' | | //
// \ .-\__ `-` ___/-. / //
// ___`. .' /--.--\ `. . ___ //
// ."" '< `.___\_<|>_/___.' >'"". //
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
// \ \ `-. \_ __\ /__ _/ .-` / / //
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永不宕机 永无BUG //
src/main/java/com/kun/XXXApplication.java
目录文件;//标注这是一个SpringBoot应用,加载所有资源类
@SpringBootApplication
public class Demo01Application {
//程序入口
//run,开启了一个服务,参数一:应用入口的类,参数二:命令行输入的参数类
/*SpringApplication实例化,做了以下四项工作:
1.判断该应用类型是普通java项目还是Web项目
2.查找并加载所有可用初始化器,设置到initializers属性中
3.找出所有的应用程序监听器,设置到listeners属性中
4.推断并设置main方法的定义类,找到运行的主类
* */
public static void main(String[] args) {
SpringApplication.run(Demo01Application.class, args);
}
}
test/java/com/kun/XXXApplicationTests.java
目录文件;src/main/java/com/kun/
最底层包目录下新建config
、controller
、dao
、pojo
等包,这些具体用到再详细讲解,也可以参考博客简略了解一下:https://www.cnblogs.com/tooyi/p/13340374.html;controller
包,并在该目录下新建HelloController.java
文件://使用Controller注解标注说明并被加载
@Controller
//使用Mapping类注解来映射请求,即请求/hello时响应回该类
@RequestMapping("/hello")
public class HelloController {
//在/hello地址请求之下再请求地址/hello即可获得下列响应
@GetMapping("/hello")
//当请求/hello/hello时,响应主体部分为hello()方法
@ResponseBody
public String hello(){
return "hello";
}
}
# 1.基础语法
# 修改自动配置的默认值,其中 : 后必须接空格
# yaml 对空格很敏感,很像python 而properties只能保存键值对
server:
port: 8081
# yaml基本语法
# 定义参数使用key-value
name: zhaoxiaoan
# 定义对象
student:
name: zhaoxiaoan
age: 3
# 对象的行内写法
teacher: {name: zhao,age 30}
# 定义数组
pets:
- cat
- dog
- pig
# 数组的行内写法
pet: [cat,dog,pig]
# EL表达式
age: ${random.int}
# 占位符
person:
hello: happy
dog:
name: ${person.hello:hello}_旺财
# 如果没有就直接为空,有则占位显示,即happy_旺财
package com.kun.pojo;
import org.springframework.stereotype.Component;
@Component
public class Dog {
private String name;
private Integer age;
//有参无参构造器、get/set方法以及toString方法,后续这些方法不再细列
public Dog() {
}
public Dog(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.kun.pojo;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
//省略各方法
}
赋值:
原生注解赋值:
//1.0
public class Dog {
@Value("zhaoxiaoan")
private String name;
@Value("3")
private Integer age;
}
# 2.0
person:
name: zhaoxiaoan
age: 3
happy: true
birth: 2020/10/22
maps: {k1: v1,k2: v2}
lists:
- code
- music
- study
dog:
name: 旺财
age: 3
@Component
/*@PropertySource(value = "classpath:application.yaml")
通过该注解设置装配文件
*/
//通过ConfigurationProperties(prefix = "person")注解绑定映射yaml文件中person对象
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
//1.0
@SpringBootTest
class DemoApplicationTests {
//自动装配类
//如果有多个对象Dog,可以通过@Qualifier选择具体的对象
@Autowired
private Dog dog;
@Test
void contextLoads() {
System.out.println(dog);
}
}
//输出为:
Dog{name=‘旺财’, age=3}
```java
@SpringBootTest
class DemoApplicationTests {
@Autowired
private Person person;
@Test
void contextLoads() {
System.out.println(person);
}
}
//输出为:
Person{name='zhaoxiaoan', age=3, happy=true, birth=Thu Oct 22 00:00:00 CST 2020, maps={k1=v1, k2=v2}, lists=[code, music, study], dog=Dog{name='旺财', age=3}}
功能:即yaml可以直接映射到对象而properties需要使用@Value一个一个赋值;
松散绑定:即yaml中的last-name和类中的lastName是一样的,-
后接的字母转为大写;
JSR303数据校验:可以在字段增加一层过滤验证,保证数据合法性;
复杂类型封装:yml中可以封装对象,使用@Value就不支持;
JSR303数据校验(类似于html中input标签中选中的url、email等功能,可以自动校验输入):
@Component
//@PropertySource(value = "classpath:application.yaml")
@ConfigurationProperties(prefix = "person")
@Validated//开启数据校验
public class Person {
@Email//对email赋值开启Email数据校验,假设对name属性开启Email验证
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
注意,在SpringBoot2.3以后版本由于spring-boot-starter-web的依赖项已经去除了validate依赖,所以需要手动添加依赖才能生效:
<dependency>
<groupId>org.hibernate.validatorgroupId>
<artifactId>hibernate-validatorartifactId>
<version>6.0.17.Finalversion>
<scope>compilescope>
dependency>
再次测试则会得到报错结果:
Description:
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'person' to com.kun.pojo.Person failed:
Property: person.name
Value: zhaoxiaoan
Origin: class path resource [application.yaml]:2:9
Reason: 不是一个合法的电子邮件地址
file:./config/
file:./
classpath:/config/
classpath:/
file即项目目录,classpath即src/main/resources
目录;
这既是yaml配置文件可存放的位置,也是其配置文件加载的优先级权重顺序,即按照权重覆盖相同属性及服务配置;
现实开发中可能会有三种环境版本:
yaml格式和properties格式配置环境对比:
在properties文件格式下徐亚单独配置多个文件才能生效;
而在yaml格式中则实现多文档模块,步骤更为简便:
server:
port: 8081
# 通过`---`符号分割不同配置环境,并使用spring.profiles属性说明即可
---
server:
port: 8082
spring:
profiles: dev
---
server:
port: 8083
spring:
profiles: test
从src/main/java/com/kun/XXXApplication.java
程序入口文件@SpringBootApplication
注解出发,依次查看父级文件,了解其自动装配原理:
—>@AutoConfigurationPackage:自动配置包
->@Import({Registrar.class}):自动配置包注册
->@Import({AutoConfigurationImportSelector.class}):自动配置导入选择器
->getAutoConfigurationEntry():获得自动配置的实体入口
->getCandidateConfigurations():获取候选配置
->protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class; //标注了EnableAutoConfiguration注解类的所有配置
}
->loadFactoryNames():获取所有的加载配置名字
->loadSpringFactories():加载所有的Spring工厂
->classLoader.getResources("META-INF/spring.factories"):加载项目资源
->ClassLoader.getSystemResources("META-INF/spring.factories"):加载系统资源
->META-INF/spring.factories:从该文件获取资源,自动装配的核心文件
META-INF/spring.factories
文件:存在于External Libraries中
所有已经配置好的依赖都在这里,其它只能自己配置;
随便进入一个源文件(可能只是.class文件,根据提示下载源java文件查看):
@ConditionalOnXXX //系列核心注解,其中每个文件都有,用来判断是否满足一系列条件才加载该文件
结论一:SpringBoot所有自动装配都是在启动的时候扫描并加载的,其中所有的自动装配类都在spring.factories
文件中,只有在pom.xml文件中添加了依赖才满足生效条件并且自动装配生效;
yaml文件内能够重写的服务实质上和spring.factories文件相关:
@EnableConfigurationProperties //某些自动装配文件中含有此注解,即标注可以在properties配置文件中重写属性值
//举例如下:
public HttpEncodingAutoConfiguration(ServerProperties properties) {
this.properties = properties.getServlet().getEncoding();
}
//其中ServerProperties文件中的属性即与yaml配置文件绑定,可以重写配置
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
//该注解中prefix值表示yaml文件中重写配置该类属性的前缀
结论二:springfactories中定义好的自动装配类XXXAutoConfiguration加载XXXProperties文件,而XXXProperties文件则与配置文件.properties/.yaml一一绑定,即可通过.yaml配置文件修改配置并被加载;
开启Debug,查看具体哪些配置类被加载:
# 在application.yaml文件中开启Spring调试类
debug: true
Positive matches: 已经启用生效的类
Negative matches: 没有开启生效的类
Unconditional classes: 没有条件的类
src/main/java/com/kun/XXXApplication.java
文件中:
SpringApplication.run(DemoApplication.class, args);
该方法主要分两部分:
做了四项工作:
开启Debug,查看具体哪些配置类被加载:
# 在application.yaml文件中开启Spring调试类
debug: true
Positive matches: 已经启用生效的类
Negative matches: 没有开启生效的类
Unconditional classes: 没有条件的类
src/main/java/com/kun/XXXApplication.java
文件中:
SpringApplication.run(DemoApplication.class, args);
该方法主要分两部分:
做了四项工作: