一、Spring Boot入门
1.Spring Boot 简介
https://blog.youkuaiyun.com/u011870547/article/details/80975623
- 简化Spring应用开发的一个框架
- 整个Spring技术栈的一个大整合
- J2EE开发的一站式解决方案
2.微服务
- 微服务:架构风格(服务微化)
- 一个应用应该是一组小型服务;可以通过HTTP的方式进行互通
- 单体应用:ALL IN ONE
- 微服务:每一个功能元素最终都是一个可独立替换和独立升级的软件单元; 详细参照微服务文档
3.MAVEN设置
给maven 的settings.xml配置文件的profiles标签添加:让Maven使用JDK1.8进行编译
<profile>
<id>jdk‐1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
4.开始第一个HelloWorld入门程序演示
- 4.1创建一个Maven项目,(打包为jar)。
- 4.2导入SpringBoot相关的依赖。
<!-- 使用spring‐boot‐starter‐parent作为父项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<!--导入springboot web相关的依赖-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
</dependency>
</dependencies>
- 4.3编写一个主程序;启动Spring Boot应用
/**
* @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
// Spring应用启动起来
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}
- 4.4编写相关的Controller
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public String hello(){
return "Hello World!";
}
}
-
4.5运行主程序测试
-
4.6简化部署
<!‐‐ 这个插件,可以将应用打包成一个可执行的jar包;‐‐>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐maven‐plugin</artifactId>
</plugin>
</plugins>
</build>
将这个应用打成jar包,直接使用java -jar的命令进行执行(java -jar HelloWorldMainApplication.jar
5.HelloWorld程序探究
- 5.1父项目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
SpringBoot的版本仲裁中心.
- 5.2启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
spring-boot-starter-web:
spring-boot-starter:spring-boot场景启动器;帮我们导入了web模块正常运行所依赖的组件;
Spring Boot将所有的功能场景都抽取出来,做成一个个的starters(启动器),只需要在项目里面引入这些starter
相关场景的所有依赖都会导入进来。要用什么功能就导入什么场景的启动器
- 5.3主程序类、主入口
/**
* @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
// Spring应用启动起来
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}
@SpringBootApplication: SpringBoot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
- 5.4注解详解@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 {
- 5.4.1@SpringBootConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@SpringBootConfiguration:Spring Boot的配置类; 标注在某个类上,表示这是一个Spring Boot的配置类;
@Configuration:配置类上来标注这个注解;表示该类是spring的配置类。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
通过这个源码可以发现配置类也是spring容器中的一个主件——@Component
- 5.4.2@EnableAutoConfiguration:开启自动配置功能
以前我们需要配置的东西,SpringBoot帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
- 5.4.2.1@AutoConfigurationPackage:自动配置包
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
@Import:spring的底层注解;作用是:用于给spring容器导入主件。
通过查看Registrar类的源码可以发现以下代码:
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//该句代码就是获取元注解所在的包,从而就可以发现(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()的值为@SpringBootApplication注解所在包下的包名
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
那么就有一个重要的结论:
@AutoConfigurationPackage注解最主要的作用就是:将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器;
- 5.4.2.2@Import({AutoConfigurationImportSelector.class})注解;
@Import({AutoConfigurationImportSelector.class})的作用:给容器导入一些主件。那么导入哪些主件呢?
就由AutoConfigurationImportSelector类来选择:将所有需要导入的主件以全类名的方式返回;
通过测试发现:会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件, 并配置好这些组件;有了自动配置类,免去了我们手动编写配置注入功能组件等的工作;
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader);
Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;以前我们需要自己配置的东西,自动配置类都帮我们配置好了;
J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-1.5.9.RELEASE.jar;
6.配置文件
SpringBoot使用一个全局的配置文件,配置文件名是固定的:application.properties或者application.yml
配置文件的作用: 修改SpringBoot自动配置的默认值;(SpringBoot在底层都给我们自动配置好了)。
6.1 yml介绍
YAML(YAML Ain’t Markup Language):
- YAML A Markup Language:是一个标记语言。
- YAML isn’t Markup Language:不是一个标记语言;
yaml 的区别:
YAML:以数据为中心,比json、xml等更适合做配置文件;
yaml例子:
server:
port: 8081
xml例子:
<server>
<port>8081</port>
</server>
6.2 yaml语法
6.2.1 基本语法
- k:(空格)v——>表示为一对键值对(注意:冒号后面必须有空格)
- 以空格的缩进表示层级关系
例子:
server:
port: 8081
path: /hello
- 属性和值是大小写敏感的
6.2.2 字面量:普通的值(数字,字符串,布尔)
使用"k: v"来写。(字符串默认不用加上单引号或者双引号;)
那么,如果加双引号和单引号又有什么含义呢?
- “”:双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思。
##通过双引号括起来的字符串有特殊字符就会转意其本身的含义:例如\n为换行符,那么输出的结果就会进行换行##
name: "zhangsan\nlisi"
- ‘’:单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据
##输出结果会把\n当成普通字符输出##
name: "zhangsan\nlisi"
6.2.3 对象、Map(属性和值)(键值对)
对象也是使用k: v的方式来写。在下一行来写对象的属性和值的关系;注意缩进。
举个例子:假设有一个friends对象。用yaml的写法有以下两种:
方式1:换行写法
friends:
lastName: zhangsan
age: 18
方式2:行内写法
friends: {lastName: zhangsan,age: 18}
6.2.4 数组(List、Set)
用 ”- “值表示数组中的一个元素。
例子:假设有一个pets数组。用yam的写法有两种:
方式1:换行写法
pets:
- cat
- dog
- pig
方式2:行内写法
pets: [cat,dog,pig]
6.2.5 配置文件值注入
我们下面就通过在配置文件中写一个person的配置,并把它一一映射到Person对象中做一个演示。
配置文件:
person:
lastName: 掌声
age: 18
boss: false
salary: 7000.8
birthday: 2018/12/12
maps: {k1: v1,k2: 12}
lists: [k1,lisi,18,2.3]
dog:
name: xiaogou
age: 2
bean对象:
/**
* 将配置文件中配置的每一个属性值,映射到组件中
* @ConfigurationProperties:告诉springboot将本类中的所有属性和配置文件中的相关配置进行绑定
* prefix: 配置文件中哪个配置下的属性进行一一对应
* 只有这个组件是容器中的组件,才能容器提供@ConfigurationProperties功能
*/
@ConfigurationProperties(prefix = "person")
@Component
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
private Double salary;
private Date birthday;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
主意:
<!‐‐导入配置文件处理器,配置文件进行绑定就会有提示‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐configuration‐processor</artifactId>
<optional>true</optional>
</dependency>
6.2.6 @Value获取值和@ConfigurationProperties获取值比较
@Value和@ConfigurationProperties 都是把配置文件中的配置和对象的属性进行绑定
1 | @ConfigurationProperties | @Value |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定 | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
6.2.7 @PropertySource&@ImportResource&@Bean
- @PropertySource:指定属性文件,让自定义属性文件被spring加载进来和bean对象的属性进行一一映射。
例子:
@PropertySource(value = {"classpath:person.properties"})
@ConfigurationProperties(prefix = "person")
@Component
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
private Double salary;
private Date birthday;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
- @ImportResource:导入Spring的配置文件,让配置文件里面的内容生效。
Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别;想让Spring的配置文件生效,加载进来;需要将@ImportResource标注在一个配置类上。
例子:我们创建一个自定义的bean.xml文件,并在bean.xml文件中添加一个bean到spring容器中。并让该bean.xml文件有效。
自定义spring配置文件bean.xml
<?xml version="1.0" encoding="UTF‐8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring‐beans.xsd">
<!--向spring容器中添加一个helloService组件-->
<bean id="helloService" class="com.atguigu.springboot.service.HelloService"></bean>
</beans>
为了让该配置文件生效,我们需要在配置类上添加一个@ImportResource注解来让该配置文件生效:那就在springboot主程序中添加。
@ImportResource(locations = {"classpath:bean.xml"})//让classpath目录下的bean.xml文件生效
@SpringBootApplication
public class SpringBootDemo04ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemo04ConfigApplication.class, args);
}
}
注意:在springboot不推荐使用配置文件的方式给spring容器添加组件,建议使用全组件的方式给spring容器添加组件
- @Bean:给spring容器添加组件
例子:使用@Bean的方式给spring容器添加组件。
/**
* @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件
* 在配置文件中用<bean><bean/>标签添加组件
*/
@Configuration
public class MyAppConfig {
//将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名
@Bean
public HelloService helloService02(){
System.out.println("配置类@Bean给容器中添加组件了...");
return new HelloService();
}
}
6.2.8 配置文件占位符
SpringBoot为我们在配置配置文件的时候提供了一种生成随机数方法、占位符。
例子:
person.lastName=张三${random.uuid} #使用${random.uuid}生成一个随机的uuid值
person.age = ${random.int} #使用${random.int}生成一个随机的整数
person.dog.name = ${person.lastName}的dog #通过${person.lastName}作为占位符
person.dog.age = ${dong.age:${random.int}} #通过${dong.age:${random.int}}指定占位符,如果占位符没有值就通过${random.int}获取一个随机的整数
7. Profile
Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活、指定参数等方式快速切换环境。
7.1 多Profile文件
我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml。在启动的时候没有指定激活哪个文件,springboot启动默认使用aplication.properties/yml。
yml支持多文档块的方式
每个properties代表自己独立的属性配置,在启动的时候可以指定让哪个属性文件生效。然而yml可以把不同的环境配置到同一个yml文件中,并在启动的时候指定让哪一个配置生效。原因是:yml文件中可以分为几个文档块,每个文档块就相当于独立的一个文件一样。这样在每次启动springboot项目的时候可以指定让哪个文档块生效。
例子:下面就给出一个yml文件中写两个文档块,并在第一个文档块中指定让哪个文档块生效。如果不指定,就默认第一个文档块生效
server:
port: 8080
spring:
profiles:
active: prod #指定激活的文档块
--- # 划分文档块
server:
port: 8081
spring:
profiles: dev #指定文档的名称
---
server:
port: 8082
spring:
profiles: prod
指定生效文件的方式
方式1:在默认配置文件中指定让哪个配置文件生效。
例子:我们在默认application.properties文件中对端口不进行修改默认为8080,我们再创建一个application-dev.properties文件。在默认文件启动的时候指定让哪个文件生效。
application.properties
spring.profiles.active= dev
application-dev.properties
server.port=8081
这样启动springboot项目后,使用的端口就是8081而不是8080.
方式2:使用命令行传入参数
首先对整个工程打成一个可执行的jar包。然后运行一下命令进行启动:
java -jar spring-boot-demo04-config-0.0.1-SNAPSHOT.jar -spring.profiles.active=prod
命令是通过 -spring.profiles.active=需要激活的主配置文件的profile名称 来传入命令行参数判断激活哪个主配置文件。
配置文件的加载位置
springboot启动的时候会扫描以下位置的application.properties/yml文件作为spring的默认配置文件。以下是按照优先级从高到低的顺序进行加载。所有位置的application.properties/yml都会被加载。如果内容相同,高优先级配置内容会覆盖低优先级配置的内容。如果内容不同,就会形成互补配置。当然:我们也可以通过配置sprig.config.location来改变默认配置
- file:./config/
- file:./ #代表当前项目的根目录下
- classpath:/config/
- classpath:/
项目打包后:我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定的配置文件和默认加载的哪些配置文件共同起作用形成互补配置。
--spring.config.location=指定配置文件的路径 #命令行参数
注意:通过命令行参数指定的配置文件的优先级级别最高。
外部配置文件加载顺序
springboot 支持多种外部配置方式。springboot可以从以下外部位置加载配。优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置
-
- 命令行参数
所有的配置都可以在命令行上进行指定
- 命令行参数
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar –server.port=8087 –server.context-path=/abc #通过命令行参数指定
-
- 来 自 java:comp/env 的 JNDI 属 性
-
- Java系统属性(System.getProperties())
-
- 操作系统环境变量
-
- RandomValuePropertySource配置的random.*属性值
由jar包外向jar包内进行寻找;优先加载带profile:
-
- jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
-
- jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
再来加载不带profile
- jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
-
- jar包外部的application.properties或application.yml(不带spring.profile)配置文件
-
- jar包内部的application.properties或application.yml(不带spring.profile)配置文件
-
- @Configuration注解类上的@PropertySource
-
- 通过SpringApplication.setDefaultProperties指定的默认属性所有支持的配置加载来源
8. 自动配置原理
配置文件到底能写什么?怎么写?关于自动配置怎么写就得说起自动配置原理啦!那么我接下来就来解释以下自动配置原理
自动配置原理:
-
- SpringBoot启动的时候加载主配置类,并且开启了自动配置功能 @EnableAutoConfiguration
-
- @EnableAutoConfiguration的作用:
利用EnableAutoConfigurationImportSelector给容器中导入一些组件,那么导入那些组件呢?
可以通过查看EnableAutoConfigurationImportSelector源码中的AutoConfigurationImportSelector类中的selectImports方法。
- @EnableAutoConfiguration的作用:
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
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.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
}
通过selectImports方法可以发现,该方法最终返回了一个configurations的一个list集合:
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
我们再进一步查看getCandidateConfigurations方法:
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;
}
通过这段代码可以发现configurations的list集合是通SpringFactoriesLoader.loadFactoryNames返回的。那么loadFactoryNames方法的作用又是什么呢? 接下来我们再进一步的查看loadFactoryNames方法的源码:
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
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();
List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
result.addAll((String)entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var9) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
}
}
}
通过上面这段代码我们不难发现loadFactoryNames()方法的作用是扫描META-INF/spring.factories文件。并把扫描到的内容包装成properties对象。从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中。
将 类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration的值加入到了容器中;
我们就给出一部分properties中的内容:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
每一个这样的 xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;然后再用他们来做自动配置
那么我们可以确认每一个 xxxAutoConfiguration类可以进行自动配置功能。
-
- 每一个自动配置类进行自动配置功能
- 每一个自动配置类进行自动配置功能
那么接下来:我们就以一个org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration的自动配置类来讲解是如何进行自动配置的。
HttpEncodingAutoConfiguration:
@Configuration //表示是一个配置类
@EnableConfigurationProperties(HttpEncodingProperties.class) //启用ConfigurationProperties功能;并将配置文件中的值和HttpEncodingProperties绑定起来。并把HttpEncodingProperties加入到ioc容器中。
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)//spring底层有一个@Conditional注解。它的作用:根据不同的条件、如果满足指定的条件,该配置类才能生效。@ConditionalOnWebApplication的作用:就是判断当前应用是否为web应用,如果是,当前配置类生效。
@ConditionalOnClass(CharacterEncodingFilter.class)//判断当前项目有没有CharacterEncodingFilter(springmvc进行乱码解决的过滤器类)类。如果有当前配置类就生效。
//判断配置文件中是否存在某个配置(存在spring.http.encoding.enabled)
//通过matchIfMissing属性可以发现就算配置文件中不存在spring.http.encoding.enabled也默认也是默认生效的
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
private final HttpEncodingProperties properties;
//只有一个有参构造器的情况下,参数的值从spring容器中获取
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean //给容器中添加一个主件(CharacterEncodingFilter),这个组件中的某些值要从properties中获取。
@ConditionalOnMissingBean//容器中配有没有该组件,@Bean就生效
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
根据当前不同的条件判断当前配置类是否生效.一旦,这个配置类生效,就会给spring容器中添加各种组件。而这写组件中的属性是从对应properties类中获取。而这个properties类中的属性又是和配置文件进行绑定哒。
HttpEncodingProperties:
@ConfigurationProperties(prefix = "spring.http.encoding") //从配置文件中获取指定的值来和bean进行绑定对应的bean(也就是HttpEncodingProperties)
public class HttpEncodingProperties {
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private Charset charset = DEFAULT_CHARSET;
private Boolean force;
private Boolean forceRequest;
private Boolean forceResponse;
private Map<Locale, Charset> mapping;
通过这段代码可以发现:所有在配置文件中配置的属性都是在xxxProperties类中进行封装着;配置文件中能配置什么就可以参考某个功能对应的这个属性类。
springboot自动配置总结:
-
1)SpringBoot启动会加载大量的自动配置类
-
2)我们看我们需要的功能有没有SpringBoot默认写好的自动配置类;(如果没有,我们就自己写一个配置类)
-
3)我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了)
-
4)给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这 些属性的值;
xxxxAutoConfigurartion:自动配置类; 给容器中添加组件
xxxxProperties:封装配置文件中相关属性;
@Conditional
@Conditional注解是spring中定义的原生注解。作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置里面的所有内容才生效;
springboot对@Conditional注解进行了扩展:
@Conditional扩展注解 作用(判断是否满足当前指定条件)
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定的类
@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项
自动配置类必须在一定的条件下才能生效; 我们怎么知道哪些自动配置类生效?
答案:我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;
注意:上面我们所提到的配合文件都是springboot的主配置文件既:application.properties/yml