本文最后编辑于 前,其中的内容可能需要更新。
话不多说,过一下配置文件
yml配置文件主要写法
参数写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| mystarter.config: enable: true
size: 18
address: beijing date: 2021/01/01
user:
username: root password: 123456 map: ip: 10.0.0.1 loginName: root
array: - aaa - bbb - ccc list: - ddd - eee set: - fff - ggg
|
激活配置文件或配置块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| spring: application: name: demo-test profiles:
active: dev1 server: port: 8080 --- server: port: 8081 spring: profiles: dev1 --- server: port: 8082 spring: profiles: dev2
|
另外,properties文件,特殊#—注释用于标记文档拆分
1 2 3 4
| spring.application.name=MyApp
spring.config.activate.on-cloud-platform=kubernetes spring.application.name=MyCloudApp
|
外部配置加载顺序
SpringBoot也可以从以下位置加载配置﹔优先级从高到低﹔高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置,以下列举实用的外部配置,官网文档
命令行参数,多个参数用空格分开
1
| java -jar spring-boot-xxx-0.0.1-SNAPSHOT.jar --server.port=9090
|
来自java:comp/env的JNDI属性
Java系统属性( System.getProperties() )
操作系统环境变量
RandomValuePropertySource配置的random.*属性值
jar包外部的application-{profile}.properties或application.yml(带spring.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指定的默认属性
优先级从 1 > 2 > … > 11,jar包外 > jar包内,带{profile} > 不带{profile} ;
@ConfigurationProperties
从配置文件给bean配置属性
基本用法
搭配组件型注解,如@Component
,指定前缀,以属性名进行赋值,依赖于空构造函数;
ignoreInvalidFields
当配置文件中的值无法映射给bean的属性。如字符串给数字赋值等,SpringBoot应用会抛异常而起动失败,而ignoreInvalidFields属性设置为true(默认为false)时可以使应用不会停止,即使用属性默认的值。
ignoreUnknownFields
忽略位置属性;当配置文件中出现了类中没有定义的属性时,即出现了未知的属性,SpringBoot默认时忽略它的(ignoreUnknownFields默认为true),ignoreUnknownFields设为false时,表示要对未知属性“斤斤计较”,结果自然是启动失败。
1 2 3 4 5 6 7 8 9 10
| @ConfigurationProperties(prefix = "ordinary.bind", ignoreInvalidFields = true, ignoreUnknownFields = false) @Slf4j @NoArgsConstructor @Data @Component public class OrdinaryPropertiesBindExample {
private String name; private Boolean enable = true; }
|
使用 Spring Boot Configuration Processor自动补全
pom.xml中加入Spring Boot Configuration Processor的依赖,并重新build之后,IDEA中编写配置文件时就可以自动补全了
1 2 3 4 5
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
|

标记配置属性为 Deprecated
使用@DeprecatedConfigurationProperty
注解作用与属性的get方法上,表示该属性已经过时,重新build之后,属性对应的自动补全提示也会发生改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @ConfigurationProperties(prefix = "ordinary.bind", ignoreInvalidFields = true, ignoreUnknownFields = false) @Slf4j @NoArgsConstructor @Data @Component public class OrdinaryPropertiesBindExample {
private String name; private Boolean enable = true;
@DeprecatedConfigurationProperty(reason = "我已经过时", replacement = "none") public Boolean getEnable() { return this.enable; } }
|

搭配@ConstructorBinding
@ConstructorBinding
注解,顾名思义,构造绑定,通过构造方法,从配置文件获取值给bean设置属性。使用此方式时,需要通过@EnableConfigurationProperties
注解修饰的配置类来扫描该类加入IOC,不能对通过常规Spring机制创建的bean使用构造函数绑定,即不能添加组件型注解(如@Component
)这样的注解加入IOC,原因也很简单,这里不作解释。
搭配@ConstructorBinding
的配置方式,一般在给类内为 final的属性初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @ConstructorBinding @ConfigurationProperties("constructor.bind") @Slf4j @Data public class ConstructorPropertiesBindExample {
private final String name;
public ConstructorPropertiesBindExample(String name) {
log.info("构造方法被调用"); this.name = name; } }
|
1 2 3 4 5
| @EnableConfigurationProperties(ConstructorPropertiesBindExample.class) @Component public class ConstructorPropertiesBindExampleActive {
}
|
搭配@Bean
搭配@Bean
注解时,不依赖该bean的无参构造,仅在bean实例化后进行属性设置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Slf4j @Configuration public class ExampleConfiguration {
@ConfigurationProperties("atbean.bind") @Bean public ExampleBean exampleBean() {
return new ExampleBean(); } @NoArgsConstructor @AllArgsConstructor @Data public static class ExampleBean {
private String examName; } }
|
@ConfigurationPropertiesBinding与自定义转换器
实现org.springframework.core.convert.converter.Converter
接口实现自定义转换器,使用@ConfigurationPropertiesBinding
声名为Spring可用的转换器
设置性别类。不设置枚举是因为Spring默认支持枚举的字符串配置了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Sex {
public static final Sex MAN = new Sex("man"); public static final Sex WOMAN = new Sex("woman");
private String value;
private Sex(String value) {
this.value = value; }
public String getValue() { return value; } }
|
实现性别类的转换器,接收不符合规则的String抛出IllegalArgumentException
异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @ConfigurationPropertiesBinding @Component public class SexConverter implements Converter<String,Sex> {
private static final Map<String,Sex> SEX_VALUE_SET = Arrays.stream(new Sex[]{Sex.MAN,Sex.WOMAN}).collect(Collectors.toMap(Sex::getValue,sex -> sex));
@Override public Sex convert(String source) {
if (SEX_VALUE_SET.containsKey(source)) {
return SEX_VALUE_SET.get(source); }else {
throw new IllegalArgumentException("The sex string value must in " + SEX_VALUE_SET.keySet().toString()); }
} }
|
建立一个pojo
1 2 3 4 5 6 7 8 9
| @ConfigurationProperties(prefix = "sexbean") @Component @AllArgsConstructor @NoArgsConstructor @Data public class ExampleSexBean {
private Sex sex; }
|
yml文件如下配置即可达到目的,配置的值不是 man或woman则抛出异常
一般来说像上面这种情况使用枚举即可,这里为了举例不使用枚举。
条件注入
仅列举常用的条件注入(有必要的话,可以取去了解SpringBootCondition
)
@ConditionalOnProperty
根据【配置文件是否存在对应的键值对】作为注入条件
以下配置可理解为:配置文件存在 “ex.config.flag=true”时注入bean,若不存在该key值则默认为false(不注入)
1 2 3 4 5
| @ConditionalOnProperty(prefix = "ex.config", name = "flag", havingValue = "1", matchIfMissing = false) @Component public class ExampleConfiguration {
}
|
@ConditionalOnBean
根据【容器内是否存在符合条件的bean】作为注入条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public @interface ConditionalOnBean {
Class<?>[] value() default {};
String[] type() default {};
Class<? extends Annotation>[] annotation() default {};
String[] name() default {};
SearchStrategy search() default SearchStrategy.ALL;
Class<?>[] parameterizedContainer() default {}; }
|
1 2 3 4 5
| @ConditionalOnBean(value = SpringbootAnnotationApplication.class)
@Component public class ExampleConditionalOnBean { }
|
@ConditionalOnClass
根据【工程中引入是否存在该class】作为注入条件
1 2 3 4 5
| @ConditionalOnClass(SpringbootAnnotationApplication.class)
@Component public class ExampleConditionalOnClass { }
|
@ConditionalOnJava
根据【当前使用的java版本与配置的版本对比结果】作为注入条件
1 2 3 4 5 6
| @ConditionalOnJava( value = JavaVersion.EIGHT, // java 1.8 range = ConditionalOnJava.Range.EQUAL_OR_NEWER) @Component public class ExampleConditionalOnJava { }
|
@ConditionalOnExpression
根据【spel表达式结果】作为注入条件,注解内值不符合表达式规则则抛出异常
1 2 3 4
| @ConditionalOnExpression("1 + 1 == 2") @Component public class ExampleConditionalOnExpression { }
|
@ConditionalOnMissingBean
根据【容器内是否不存在符合条件的bean】作为注入条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @Conditional(OnBeanCondition.class) public @interface ConditionalOnMissingBean {
Class<?>[] value() default {};
String[] type() default {};
Class<?>[] ignored() default {};
String[] ignoredType() default {};
Class<? extends Annotation>[] annotation() default {};
String[] name() default {};
SearchStrategy search() default SearchStrategy.ALL; }
|
1 2 3 4
| @ConditionalOnMissingBean(name = "springbootAnnotationApplication999") @Component public class ExampleConditionalOnMissingBean { }
|
@ConditionalOnMissingClass
根据【容器内是否不存在该class的bean】作为注入条件
1 2 3 4
| @ConditionalOnMissingClass("ws.springboot.springbootannotation.SpringbootAnnotationApplication999") @Component public class ExampleConditionalOnMissingClass { }
|
@ConditionalOnMissingFilterBean
根据【容器内是否不存在该过滤器】作为注入条件
1 2 3 4
| @ConditionalOnMissingFilterBean(CorsFilter.class) @Component public class ExampleConditionalOnMissingFilterBean { }
|
根据【应用所处云平台】作为注入条件
1 2 3 4
| @ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) @Component public class ExampleConditionalOnCloudPlatform { }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public enum CloudPlatform {
NONE,
CLOUD_FOUNDRY,
HEROKU,
SAP,
KUBERNETES }
|
@ConditionalOnWebApplication
根据【应用是否所处于web环境】作为注入条件
1 2 3 4 5 6 7
| @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.ANY)
@Component public class ExampleConditionalOnWebApplication { }
|
@ConditionalOnNotWebApplication
根据【应用是否所不处于web环境】作为注入条件
1 2 3 4
| @ConditionalOnNotWebApplication @Component public class ExampleConditionalOnNotWebApplication { }
|
@ConditionalOnResource
根据【资源是否存在】作为注入条件,如日志的相关配置等
1 2 3 4
| @ConditionalOnResource(resources = "classpath:application.yml") @Component public class ExampleConditionalOnResource { }
|
@ConditionalOnSingleCandidate
根据【容器内是否存在该class的bean,且只有一个实例或为首选的】作为注入条件,即容器中存在该class的bean的实例,且只有一个时注入条件为true,当存在多个实例时,有一个实例为首选的(如加上了@Primary
注解),注入条件也为true,即在其它bean中注入该class的bean时,如使用@Autowired
且不指定bean名称时,不会发生依赖注入失败,这个时候,以这个calss为value的@ConditionalOnResource
注解条件匹配结果就是true。
1 2 3 4 5 6 7 8 9 10
| @ConditionalOnSingleCandidate(value = I.class) @Component public class ExampleConditionalOnSingleCandidate { }
interface I{} @Component class A implements I{} @Component class B implements I{}
|
1 2 3 4 5 6 7 8 9 10 11
| @ConditionalOnSingleCandidate(value = I.class) @Component public class ExampleConditionalOnSingleCandidate { }
interface I{} @Primary @Component class A implements I{} @Component class B implements I{}
|
条件注入的组合
组合条件 AND
在类上使用多个@ConditionalOnXxxx
1 2 3 4 5
| @ConditionalOnClass(name = "ws.springboot.springbootannotation.SpringbootAnnotationApplication") @ConditionalOnJava(value = JavaVersion.EIGHT, range = ConditionalOnJava.Range.EQUAL_OR_NEWER) @Component public class ExampleConditionalAnd1 { }
|
自定义注解上使用其它条件注入注解
1 2 3 4 5 6 7
| @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @ConditionalOnClass(name = "ws.springboot.springbootannotation.SpringbootAnnotationApplication") @ConditionalOnJava(value = JavaVersion.EIGHT, range = ConditionalOnJava.Range.EQUAL_OR_NEWER) public @interface MyConditionalAndAnno { }
|
应用到要进行条件注入的组件上
1 2 3 4
| @MyConditionalAndAnno @Component public class ExampleConditionalAnd3 { }
|
继承AllNestedConditions
类封装条件,使用静态内部类标注条件,所有条件将进行【逻辑与】操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public class MyConditionalAnd extends AllNestedConditions {
public MyConditionalAnd() { super(ConfigurationPhase.PARSE_CONFIGURATION); }
@ConditionalOnClass(name = "ws.springboot.springbootannotation.SpringbootAnnotationApplication") static class OnClass{} @ConditionalOnJava(value = JavaVersion.EIGHT, range = ConditionalOnJava.Range.EQUAL_OR_NEWER) static class OnJava{} }
|
1 2 3 4 5
| @Conditional(MyConditionalAnd.class) @Component public class ExampleConditionalAnd2 {
}
|
其中ConfigurationPhase
枚举的两个值意义如下
1 2 3 4 5 6 7 8 9 10 11
| enum ConfigurationPhase {
PARSE_CONFIGURATION,
REGISTER_BEAN }
|
组合条件 OR
继承AnyNestedCondition
类封装条件,使用静态内部类标注条件,所有条件将进行【逻辑或】操作
1 2 3 4 5 6 7 8 9 10
| public class MyConditionalOr extends AnyNestedCondition { public MyConditionalOr() { super(ConfigurationPhase.PARSE_CONFIGURATION); }
@ConditionalOnClass(name = "ws.springboot.springbootannotation.SpringbootAnnotationApplication") static class OnClass{} @ConditionalOnJava(value = JavaVersion.NINE, range = ConditionalOnJava.Range.EQUAL_OR_NEWER) static class OnJava{} }
|
1 2 3 4
| @Conditional(MyConditionalOr.class) @Component public class ExampleConditionalOr { }
|
组合条件 NOT
继承NoneNestedConditions
类封装条件,使用静态内部类标注条件,所有条件将进行【逻辑非】操作
1 2 3 4 5 6 7 8 9 10
| public class MyConditionalNot extends NoneNestedConditions {
public MyConditionalNot() { super(ConfigurationPhase.PARSE_CONFIGURATION); } @ConditionalOnClass(name = "ws.springboot.springbootannotation.SpringbootAnnotationApplication999") static class OnClass{} @ConditionalOnJava(value = JavaVersion.NINE, range = ConditionalOnJava.Range.EQUAL_OR_NEWER) static class OnJava{} }
|
1 2 3 4
| @Conditional(MyConditionalNot.class) @Component public class ExampleConditionalNot { }
|
Servlet组件的扫描
ServletComponentScan
在@SpringBootApplication
上使用@ServletComponentScan
注解后,Servlet、Filter、Listener可以直接通过@WebServlet
、@WebFilter
、@WebListener
注解自动注册,无需其他代码。
1 2 3 4 5 6 7 8 9
| @ServletComponentScan @SpringBootApplication public class DemoApplication {
public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
|