SpringBoot(一)自动装配原理_配置文件yaml/properties_多环境配置_运行jar_JSR303校验

什么是springboot

什么是Spring

Spring是一个开源框架,2003年兴起的一个轻量级的Java开发框架,作者: Rod Johnson 。

Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。

Spring是如何简化Java开发的?

为了降低Java开发的复杂性,Spring采用了以下4种关键策略:

  1. 基于POJO的轻量级和最小侵入性编程;
  2. 通过IOC,依赖注入(DI)和面向接口实现松耦合;
  3. 基于切面(AOP)和惯例进行声明式编程;
  4. 通过切面和模版减少样式代码;
什么是SpringBoot

学过javaweb的同学就知道,开发一个web应用,从最初开始接触Servlet结合Tomcat,跑出一个Hello Wolrld程序,是要经历特别多的步骤;后来就用了框架Struts,再后来是SpringMVC,到了现在的SpringBoot,过一两年又会有其他web框架出现;

什么是SpringBoot呢,就是一个javaweb的开发框架,和SpringMVC类似,对比其他javaweb框架的好处,官方说是简化开发,约定大于配置, you can “just run”,能迅速的开发web应用,几行代码开发http接口。

Spring Boot基于 Spring 开发,Spirng Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring 的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。SpringBoot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数Spring Boot应用只需要很少的Spring配置。同时它集成了大量常用的第三方库配置(例如Redis、MongoDB、Jpa、RabbitMQ、Quartz等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用,
简单来说就是SpringBoot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包, spring boot整合了所有的框架。

Spring Boot的主要优点:

  • 为所有Spring开发者更快的入门
  • 开箱即用,提供各种默认配置来简化项目配置
  • 内嵌式容器简化Web项目
  • 没有冗余代码生成和XML配置的要求

微服务

一个服务一个jar,将一个项目打包成多个jar。

比如淘宝:购买东西服务在一个服务器上,数据库在另一个服务器上。

可以减少并发时间,更高效、快速,便于修改更新代码。

第一个Springboot程序

项目创建
  1. 官网快速搭建
  2. idea快速构建
要点
  • 写代码的文件或文件夹创建的位置必须和XXXApplication程序主入口文件同级。
  • pom.xml。不用写版本号,版本号被父依赖所管理。

父依赖,管理项目的资源过滤和插件:

<!--    父依赖-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

启动器(spring-boot-starter-xx):

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
</dependency>
  1. spring-boot-starter-xx:spring-boot的场景启动器

  2. spring-boot-starter-web:帮助我们导入web模块正常运行所依赖的组件(tomcat)

  3. SpringBoot将所有的功能场景都抽取出来,做成一个个start(启动器),只需要在项目中引入这些start即可,所有的依赖都会导入进来。我们要使用什么功能就导入相应场景的启动器即可

  • Maven打包成jar包,一个一个微服务jar包
运行jar包

Maven执行package打包,在target目录下找到jar包,在target目录下cmd

java -jar XXXX.jar

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cgcBfQ7H-1663495341123)(springboot笔记/image-20220905161104483.png)]

自定义banner

在resource文件夹下创建banner.txt文件。注意看图标右下角是否有springboot识别到的角标标识。

   ____     (_)     _           __      __
  |_  /     | |    (_)    __ _  \ \    / /
   / /     _/ |    | |   / _` |  \ \/\/ / 
  /___|   |__/_   _|_|_  \__,_|   \_/\_/  
_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|  
"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'  

自动装配原理

Pom.xml文件

父依赖

pom.xml文件中,有一个父依赖(也可以说是该pom.xml文件依赖一个父项目),主要是管理项目的资源过滤和插件!

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.6.7</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>

点进去是个名为spring-boot-starter-parent 的pom文件,发现该项目也依赖一个父项目(名为spring-boot-dependencies)

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.6.7</version>
  </parent>

这里才是真正的管理SpringBoot应用里面所有依赖版本的位置,SpringBoot的版本控制中心

之后我们导入依赖默认是不需要写版本号的,但是如果导入的包没有在依赖管理中,就需要我们手动来进行版本的配置了

**启动器(spring-boot-starter-xx) **

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
</dependency>

spring-boot-starter-xx:spring-boot的场景启动器

spring-boot-starter-web:帮助我们导入web模块正常运行所依赖的组件

SpringBoot将所有的功能场景都抽取出来,做成一个个start(启动器),只需要在项目中引入这些start即可,所有的依赖都会导入进来;我们要使用什么功能就导入深夜场景的启动器即可;我们也可以自定义start启动器

主启动类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p8OaAXWH-1663495341125)(springboot笔记/1fd91c97246b45c3bf9aad068b8bd382.png)]

默认的主启动类:XXXXApplication

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootFirstApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootFirstApplication.class, args);
    }

}

@SpringBootApplication

作用:标注在哪个类上,就说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用

点进注解:@SpringBootApplication==>

//元注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
  excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
  ), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
  )}
)
public @interface SpringBootApplication {}

@SpringBootConfiguration

作用:SpringBoot的配置类,标注在哪个类上,表示的哪个就是SpringBoot的配置类

@SpringBootConfiguration==>(进入@SpringBootConfiguration注解里面)

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented

@Configuration
@Indexed
public @interface SpringBootConfiguration {}

@Configuration

这里的@Configuration,说明这相当于是一个Spring的xml配置文件

@Configuration==>(进入@Configuration注解里面)

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented

@Component
public @interface Configuration {}

@Component

这里的@Component,说明启动类本身也是一个组件,负责启动应用

@EnableAutoConfiguration

  • 开启自动配置功能(以前我们需要手动配置,现在SpringBoot可以帮我们自动配置)

  • @EnableAutoConfiguration注解“通知”SpringBoot开启自动配置功能,这样自动配置功能才能生效

  • @EnableAutoConfiguration==>

@AutoConfigurationPackage(自动配置包)

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}
  • @Import:Spring底层注解,给容器中导入一个组件
  • @Import({AutoConfigurationImportSelector.class}):给容器导入组件
  • AutoConfigurationImportSelector:自动配置导入选择器

AutoConfigurationImportSelector类

1、AutoConfigurationImportSelector类中有一个这样的方法

//获得候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  //这里的getSpringFactoriesLoaderFactoryClass返回的就是我们最开始看的启动自动导入配置文件的注解类:@EnableAutoConfiguration
  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;
}

2、这个方法调用了SpringFactoriesLoader类的静态方法,我们进入SpringFactoriesLoader类的loadFactoryNames方法

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
  ClassLoader classLoaderToUse = classLoader;
  if (classLoader == null) {
    classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
  }

  String factoryTypeName = factoryType.getName();
  //这里它又调用loadSpringFactories方法
  return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

3、我们进入loadSpringFactories方法

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
  //获取classloader,我们这里得到的就是@EnableAutoConfiguration标注的类本身
  Map<String, List<String>> result = (Map)cache.get(classLoader);
  if (result != null) {
    return result;
  } else {
    HashMap result = new HashMap();

    try {
      //取获取一个资源:"META-INF/spring.factories"
      Enumeration urls = classLoader.getResources("META-INF/spring.factories");
	//将读取到的资源遍历,封装成为一个Properties
      while(urls.hasMoreElements()) {
        URL url = (URL)urls.nextElement();
        UrlResource resource = new UrlResource(url);
        Properties properties = PropertiesLoaderUtils.loadProperties(resource);
        Iterator var6 = properties.entrySet().iterator();

        while(var6.hasNext()) {
          Entry<?, ?> entry = (Entry)var6.next();
          String factoryTypeName = ((String)entry.getKey()).trim();
          String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
          String[] var10 = factoryImplementationNames;
          int var11 = factoryImplementationNames.length;

          for(int var12 = 0; var12 < var11; ++var12) {
            String factoryImplementationName = var10[var12];
            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
              return new ArrayList();
            })).add(factoryImplementationName.trim());
          }
        }
      }

      result.replaceAll((factoryType, implementations) -> {
        return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
      });
      cache.put(classLoader, result);
      return result;
    } catch (IOException var14) {
      throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
    }
  }
}

4、发现多次出现:spring.factories

@AutoConfigurationPackage==>

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {}

Registrar.class:将主动类所在包及包下面所有子包里面的所有组件扫描到Spring容器中

spring.factories

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t0yAyd7W-1663495341126)(springboot笔记/36c475decd4f40d69ee3180e88da04c9.png)]

根据源头打开spring.factories,看到很多自动配置的文件,这就是自动配置根源所在!

我们在上面的自动配置类里面随便打开一个,比如:WebMvcAutoConfiguration

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gg0saDJZ-1663495341136)(springboot笔记/2ee3139e283645ce92b90f6b15b3a842.png)]

可以看到这些都是JavaConfig配置类(就是Spring框架中,可以用Java的方式来配置Spring,代替Spring自带的application.xml配置文件)

所有,自动配置真正实现是从classpath中搜索所有的META-INF/spring.factories配置文件,并将其中对应的 org.springframework.boot.autoconfigure 包下的配置项通过反射实例化成为标注了 @Configuration的JavaConfig形式的IOC容器配置类,然后将这些汇总成为一个实例并加载到IOC容器中。

自动配置总结:
  • SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值

  • 将这些值作为自动配置类导入容器,自动配置类就会生效,帮我们进行自动配置工作

  • 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包

  • 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件

  • 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作

SpringApplication

最初以为就运行一个main方法,没想到开启了一个服务

@SpringBootApplication
public class SpringBootFirstApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootFirstApplication.class, args);
    }
}

SpringApplication.run分析

  • SpringApplication的实例化
  • run方法的执行

**SpringApplication **

这个类主要做了一下四件事:

  • 推断应用的类型是普通的项目还是Web项目

  • 查找并加载所有可用初始化器 , 设置到initializers属性中

  • 找出所有的应用程序监听器,设置到listeners属性中

  • 推断并设置main方法的定义类,找到运行的主类

SpringApplication类的构造器:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  this.sources = new LinkedHashSet();
  this.bannerMode = Mode.CONSOLE;
  this.logStartupInfo = true;
  this.addCommandLineProperties = true;
  this.addConversionService = true;
  this.headless = true;
  this.registerShutdownHook = true;
  this.additionalProfiles = Collections.emptySet();
  this.isCustomEnvironment = false;
  this.lazyInitialization = false;
  this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
  this.applicationStartup = ApplicationStartup.DEFAULT;
  this.resourceLoader = resourceLoader;
  Assert.notNull(primarySources, "PrimarySources must not be null");
  this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
  this.webApplicationType = WebApplicationType.deduceFromClasspath();
  this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
  this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
  this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
  this.mainApplicationClass = this.deduceMainApplicationClass();
}

yaml语法配置

什么是yaml

这种语言以数据做为中心,而不是以标记语言为重点,而用反向缩略语重命名。

配置文件:SpringBoot使用一个全局的配置文件,配置文件名称是固定的

作用:修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了

  • application.yaml
    • 语法结构:key :空格 value
  • application.properties
    • 语法结构:key.XXX=value
yaml基本语法格式
  • 空格
  • 以缩进来控制层级关系
  • 属性和值的大小写都是十分敏感
  • 字面量直接写在后面就可以 , 字符串默认不用加上双引号或者单引号

注意:

  • “… ” 双引号,会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;

比如 :name: “kuang \n shen” 输出 :kuang 换行 shen

  • ‘ …’ 单引号,不会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出

比如 :name: ‘kuang \n shen’ 输出 :kuang \n shen

要点
  • springboot官方推荐使用yaml,优点多,比properties功能更全面

  • .yaml文件对空格的要求很高

  • 当.properties和.yaml文件同时存在时,properties的优先级更高

  • properties文件只能key.XXX=value,较复杂且不方便。yaml文件支持普通键值对、数组、对象等结构

  • yaml可以给实体类赋值

yaml支持语法结构:

#普通key-value
server:
  port: 8081

#对象
student:
  name: ZjiaW
  age: 18
#支持行内写法
student1: {name: ZjiaW , age: 18}

#数组
animal:
  - pig
  - fish
  - dog
#支持行内写法
animal1: [pig,fish,dog]

properties语法结构:

server.port=8084
yaml格式给实体类赋值

yaml文件给实体类赋值需要使用@ConfigurationProperties(prefix = "dog")注解

prefix前缀指明是哪个对象

  1. 创建dog实体类、person实体类、添加lombok依赖

lombok依赖:

<!--        lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>

dog:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "dog")
public class Dog {
    private String name;
    private Integer age;
}

person:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private Boolean isHappy;
    private Date birth;
    private Map<String ,Object> maps;
    private List<Object> lists;
    private Dog dog;
}
  1. 编写yaml文件,为实体类赋值
dog:
  name: 旺财
  age: 3

person:
  name: ZjiaW
  age: 18
  isHappy: false
  birth: 2022/9/6
  maps: {k1: v1,k2: v2}
  lists: [code,dog,music]
  Dog:
    name: 旺财2
    age: 6
  1. 添加依赖,来防止使用@ConfigurationProperties(prefix = "person") 注解时实体类爆红提示
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
  1. 测试(用springboot自带的测试类)
 
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class FirstSpringbootApplicationTests {
    @Autowired
    Dog dog;
    @Autowired
    Person person;

    @Test
    void contextLoads() {
        System.out.println(dog);
        System.out.println(person);
    }
}
  1. 也可对yaml使用占位符:
person:
	name: jia${random.uuid} # 随机uuid
	age: ${random.int}  # 随机int
	happy: false
	birth: 2000/01/01
	maps: {k1: v1,k2: v2}
	lists:
		- code
		- girl
		- music
	dog:
		name: ${person.hello:other}_旺财    # person.hello存在时显示该值,不存在显示“other”
		age: 1

properties格式给实体类赋值
  • @PropertySource("classpath:XXXX.properties")注解,标识用的是哪个配置资源文件
  • 获取配置中实体类的值通过SPEL表达式获取@Value("${dog.name}")

dog实体类:

package com.zjw.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
//@ConfigurationProperties(prefix = "dog")
@PropertySource("classpath:application.properties")
public class Dog {
    @Value("${dog.name}")
    private String name;
    @Value("${dog.age}")
    private Integer age;
}

properties文件:

dog.name=hi
dog.age=2

使用properties很可能出现乱码问题,因idea默认properties为ASCII码

若出现乱码问题,在setting中找到 file Encoding

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dXq7204I-1663495341138)(springboot笔记/image-20220906213214079.png)]

两个文件的对比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sfiajpGE-1663495341139)(springboot笔记/image-20220906214949282.png)]

  • @ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加
  • 松散绑定: 比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的
  • JSR303数据校验 , 这个就是我们可以在字段中增加一层过滤器验证 , 可以保证数据的合法性
  • 复杂类型封装,yml中可以封装对象 , 使用value就不支持

总结:

  • 如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value;
  • 如果说,我们专门编写了一个JavaBean来和配置文件进行一一映射,就直接@configurationProperties

JSR303校验

在字段中增加一层过滤器验证 , 可以保证数据的合法性

使用方法
  • 新版本的Springboot默认不支持JSR303校验,需要手动添加validation依赖,而老版本的默认自动配置了validation
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
  • 为实体类添加@VAlidated注解

  • 在属性上添加验证方式

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.Email;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
    @Email(message = "这不是邮箱格式,请检查")
    private String name;
    @Max(value = 120,message = "最大不超过120")
    private int age;
    @NotNull(message = "是否开心不能为空")
    private Boolean isHappy;
    private Date birth;
    private Map<String ,Object> maps;
    private List<Object> lists;
    private Dog dog;
}
常见的参数
@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")
private String email;

空检查
@Null       验证对象是否为null
@NotNull    验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank   检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty   检查约束元素是否为NULL或者是EMPTY.
    
Booelan检查
@AssertTrue     验证 Boolean 对象是否为 true  
@AssertFalse    验证 Boolean 对象是否为 false  
    
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
@Length(min=, max=) string is between min and max included.

日期检查
@Past       验证 DateCalendar 对象是否在当前时间之前  
@Future     验证 DateCalendar 对象是否在当前时间之后  
@Pattern    验证 String 对象是否符合正则表达式的规则

.......等等
除此以外,我们还可以自定义一些数据校验规则

多环境配置及配置文件位置

配置文件位置优先级
  1. file:./config/

  2. file:./

  3. classpath:/config/

  4. classpath:/

file:指项目根目录下

classpath:指java/resource下

properties多环境配置

默认配置文件名为application.properties

开发环境或测试环境的配置文件名字为:在application加上-dev/-test

在默认的配置文件下指定激活哪个配置文件:spring.profiles.active=XX

  • 创建三个properties文件(application.properties,application-dev.properties,application-test.properties)

application.properties:

server.port=8084
spring.profiles.active=dev

application-dev.properties:

server.port=8085

application-test.properties:

server.port=8086
  • 运行项目端口号为dev的端口号
  • 若不指定激活哪个配置文件,默认执行application.properties配置文件
yaml多环境配置

yaml多环境配置通过**三个-**来分隔不同的配置环境

spring:

​ profiles: 指定配置文件名字

(yaml也适用properties中使用-XX文件名进行多环境配置)

server:
  port: 8081

spring:
  profiles:
    active: test
    
---

server:
  port: 8082

spring:
  profiles: dev
  
---

server:
  port: 8083

spring:
  profiles: test

自动配置再理解

配置文件该怎么写

在SpringBoot的配置文件中,给特定功能的属性赋值来实现自定义的功能;

但是这些属性名(就是在配置过程中给出的属性名的提示)其实是来自XxProperties类中进行定义的,因此可以参照XxProperties相关类来了解相应属性名的含义

自动配置原理

逐步进入底层源码,可以看到最后SpringFactoriesLoader 类里面定义了一个静态常量public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

值得注意的是META-INF/spring.factories这个文件最后被加载并转换成了Properties类型

我们通过文件名全局搜索找到了spring.factories文件

然后随便点进一个熟悉的:HttpEncodingAutoConfiguration配置类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q9cKxRZ5-1663495341140)(springboot笔记/9f1981e584284afeb5252333bb78de30.png)]

/部分代码

//出现这个@Configuration和@Bean标志着这个类是个配置类(JavaConfig)--学习Spring中,Java配置类代替Spring的配置文件
@Configuration(
  proxyBeanMethods = false
)

//启动指定类的ConfigurationProperties功能;
  //进入这个ServerProperties查看,将配置文件中对应的值和ServerProperties绑定起来;
  //并把ServerProperties加入到ioc容器中
@EnableConfigurationProperties({ServerProperties.class})

//Spring底层@Conditional注解
  //根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效;
  //这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(
  type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
  prefix = "server.servlet.encoding",
  value = {"enabled"},
  matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
  private final Encoding properties;

  public HttpEncodingAutoConfiguration(ServerProperties properties) {
    this.properties = properties.getServlet().getEncoding();
  }

  @Bean
  判断容器没有这个组件?
  @ConditionalOnMissingBean
  public CharacterEncodingFilter characterEncodingFilter() {
    CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
    filter.setEncoding(this.properties.getCharset().name());
    filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
    filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
    return filter;
  }

总结:

  • 一但这个配置类生效,这个配置类就会给容器中添加各种组件

  • 这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的

  • 所有在配置文件中能配置的属性都是在xxxxProperties类中封装着

  • 配置文件能配置什么就可以参照某个功能对应的这个属性类

在进入ServerProperties这个类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6VTTrM28-1663495341142)(springboot笔记/5a6c84997a6d41409da879aa50aae809.png)]

这就是自动装配的大概流程!

总结精华
  • SpringBoot启动会加载大量的自动配置类
  • 我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中
  • 我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
  • 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可
  • xxxxAutoConfigurartion:自动配置类给容器中添加组件
  • xxxxProperties:封装配置文件中相关属性
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值