springboot使用一个全局配置文件,配置文件名是固定的:html
配置文件的做用:修改springboot自动配置的默认值。springboot在底层都给咱们自动配置好了;java
配置文件位于src/resources下面。web
yaml a markup language 是一个标记语言,以数据为中心,比其余类型的标记语言更适合做为配置文件。 标记语言:之前的配置文件大多都使用XXX.xml文件,spring
YAML:shell
server: port: 8081
XML:json
<server> <port>8081</port> </server>
properties:tomcat
server.port = 8081
person: lastName: zhaoyi list: - list1 - list2 maps: k1: v1 k2: v2 age: 25 boss: false dog: name: xiaohuang age: 30
// person类 @Component @ConfigurationProperties(prefix = "person") public class Person { private String lastName; private List<Object> list; private Map<String, Object> maps; private Integer age; private Boolean boss; private Dog dog; @Override public String toString() { return "Person{" + "lastName='" + lastName + '\'' + ", list=" + list + ", maps=" + maps + ", age=" + age + ", boss=" + boss + ", dog=" + dog + '}'; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public List<Object> getList() { return list; } public void setList(List<Object> list) { this.list = list; } public Map<String, Object> getMaps() { return maps; } public void setMaps(Map<String, Object> maps) { this.maps = maps; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Boolean getBoss() { return boss; } public void setBoss(Boolean boss) { this.boss = boss; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } } // dog类 package com.zhaoyi.hello1.com.zhaoyi.hello1.bean; public class Dog { private String name; private int age; @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
导入配置文件处理器,这样就会有提示编写资源的信息;springboot
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
只有组件是容器中的组件,才能使用ConfigurationProperties提供的功能;app
springboot单元测试:能够在测试期间很方便的相似编码同样进行自动注入等容器功能;dom
@RunWith(SpringRunner.class) @SpringBootTest public class Hello1ApplicationTests { @Autowired Person person; @Test public void contextLoads() { System.out.println(person); } }
注释掉application.yml的配置文件信息,新建一个application.properties文件,写入和applicatio.yml相同功能的配置
person.age=14 person.last-name=张三 person.boss=false person.maps.k1=v1 person.maps.k2=v2 person.list=a,b,c person.dog.name=小狗 person.dog.age=5
运行测试后发现有关中文部分的输出是乱码。
idea使用的是utf-8编码,在setting处查询file encoding,设置为utf-8,并选择在运行时转化为ascll(勾选)
Spring中配置一个Bean:
<bean class="person"> <property name="lastName" value="zhangsan"></property> </bean>
其中,value能够:
#{SPEL}
而@Value其实效果和其同样,好比,在类属性上写
@Value("person.lastName") private String lastName @Value("#{11*2}") private Integer age
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
支持松散绑定 | 不支持松散绑定 | |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
注: |
从上面的说明咱们能够知道,二者在配置上基本能够相互替换,彼此功能也大致一致,那么,咱们在业务场景中,该选用哪种进行编码呢?
@Value
.@RestController public class HelloController { @Value("${person.last-name}") private String name; @RequestMapping("/") public String hello(){ return "hello world, " + name; } }
@ConfigurationProperties
;
@PropertySource
加载指定的配置文件。
咱们知道,@ConfigurationProperties默认从全局配置文件(application.properties)中获取值,但一般咱们会将相关的配置文件放到某个配置文件中,例如,咱们将有关person的配置信息放到person.properties中去。为了使组件类Person可以找到配置文件的配置信息,须要使用增长新的注解@PropertySource
指定从哪里加载配置等相关信息。
@PropertySource("classpath:person.properties") @Component @ConfigurationProperties(prefix = "person") public class Person { }
@ImportResource
导入Spring的配置文件,让配置文件里面的内容生效。
package com.zhaoyi.hello1.service; public class HelloService { }
<?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"> <bean id="helloService" class="com.zhaoyi.hello1.service.HelloService"></bean> </beans>
那么问题来了,在spring-boot中显然是不会加载此bean的,咱们测试一下。
@RunWith(SpringRunner.class) @SpringBootTest public class Hello1ApplicationTests { @Autowired ApplicationContext ioc; @Test public void testBean(){ System.out.println("Is have helloService bean? " + ioc.containsBean("helloService")); } }
测试结果:
Is have helloService bean? false
Spring boot里面是没有Spring的配置文件,咱们本身编写的配置文件,也不能自动识别,想让Spring的配置文件生效,则须要手动指示将其加载进行,使用@ImportResource
标注在一个配置类(例如应用程序启动类,他也是一个配置类)上:
@ImportResource(locations = {"classpath:bean.xml"}) @SpringBootApplication public class Hello1Application { public static void main(String[] args) { SpringApplication.run(Hello1Application.class, args); } }
这时候运行测试用例就会发现,bean已经出如今容器中了。
@ImportResource(locations = {"classpath:bean.xml"})
通常咱们不会使用6中所提到的这种方式,由于xml配置方式实在是写了太多的无用代码,若是xml的标签声明,以及头部的域名空间致使。所以,SpringBoot推荐给容器中添加组件的方式:全注解方式。也就是用配置类来充当bean配置文件。以下,即为一个配置类:
/** * @Configuration 指明当前类是一个配置类 */ @Configuration public class MyConfig { // 将方法的返回值添加到容器中:容器中这个组件的id就是方法名 @Bean public HelloService helloService(){ return new HelloService(); } }
经过该配置类,能够为容器中添加了一个名为helloService
的bean。
不管是使用yaml仍是properties都自持文件占位符配置方式
${random.value}
${random.int}
${random.long}
${random.int(10)}
${random.int[1024,65536]}
person.age=14 person.last-name=张三${random.uuid} person.boss=false person.maps.k1={person.xxx:novalue} person.maps.k2=v2 person.list=a,b,c person.dog.name=${person.last-name}_小狗狗 person.dog.age=${random.int}
Person{lastName='张三1b9fbbb1-6c58-4a35-8165-ad23800d7456', list=[a, b, c], maps={k2=v2, k1=novalue}, age=14, boss=false, dog=Dog{name='张三b3a355d7-54ce-4afd-9ae6-d3be4aeb4165_小狗狗', age=-122850975}}
注意:留意默认值那一项设置,咱们如愿的成功设置了默认值novalue。在实际项目中,这种状况比较经常使用,稍微留意一下。若是没有默认值,则会将${xxx}这一段做为值,这显然是错误的。
profile通常是spring用来作多环境支持的,能够经过激活指定参数等方式快速的切换当前环境。
咱们在主配置文件编写的时候,文件名能够是 application-{profile}.properties(yml)
例如: application-dev.properties、application-prod.properties等。
spring.profiles.active=dev
--spring.profiles.active=dev
edit configuration
,在environment配置节中的Program arguments
写入spring.profiles.active=dev便可。java -jar your-jar-name.jar --spring.profiles.active=dev
便可。Program arguments
上一项即为虚拟机参数激活,不过填写的内容为-Dspring.profiles.active=dev
,即多了一个-D
而已。若咱们使用properties,则须要编写多个不一样的配置文件,但若是咱们使用yml的话,则能够经过多文档配置节实现单文件管理。注:有关yml相关的知识参考此文档的前半部分。
能够看到,咱们经过---
三个横线实现文档分割,同时在每个文档块处指定了各个profile的不一样配置信息,即dev环境下启动服务使用8082端口,prod环境下使用8083端口。而指定哪个profile则是经过默认的文档块(即第一块)中的spring.profiles.active进行配置。完成如上配置以后咱们启动服务,显然此时是以激活的prod环境所配置的端口8083运行的,以下启动日志所示:
com.zhaoyi.hello1.Hello1Application : The following profiles are active: prod o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8083 (http)
也就说,当咱们选定一个profile后,对应的文档块的配置就会所有生效。
SpringBoot启动会扫描如下位置的application.properties或者application.yml文件做为SpringBoot的默认配置文件:
以上是按照优先级顺序从高到低,全部位置的文件都会被加载,但对于相同配置:高优先级配置内容会覆盖低优先级配置的内容,其余的则互补。
咱们也能够经过spring.config.location参数来设置默认的配置文件位置。项目打包好之后,使用命令行参数形式来指定配置文件的新位置,指定的配置文件和默认加载的配置互补起做用。而且咱们指定的该配置文件优先级是最高的。
SpringBoot支持多种外部配置方式,他能够从如下位置加载配置,按优先级从高到低排列以下(高优先级配置覆盖低优先级配置,全部配置会造成互补配置):
java -jar package_name_version.jar --server-port=8080 --server.context-path=/hello
多个参数之间用空格分开,用--parameter_name=value
进行配置。
都是由jar包外向jar包内进行寻找,高优先级的配置覆盖低优先级的配置。而后 优先加载带profile的:
在jar文件的同级目录放一个application.properties文件,其配置内容会被加载;
再来加载不带profile的:
官方文档列出了比这里更多的配置文档,请参考,版本更迭地址会常常变更,可自行前往官方网站进行查看。
配置文件的配置属性能够参照官方文档:前往
@EnableAutoConfiguration
。public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
扫描全部jar包类路径下META-INF/spring.factories
文件,吧扫描到的这些文件的内容包装成properties对象;从properties中获取到EnableAutoConfiguration.class类对应的值,而后把他们添加在容器中;
说到底,就是将类路径下META-INF/spring.factories
里面配置的全部EnableAutoConfiguration的值加入到了容器中。
# 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.CloudServiceConnectorsAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ ...(more)
每个这样的xxxAutoConfiguration类都会是容器中的一个组件,都加入到了容器中,用他们来作自动配置。
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
为例:@Configuration @EnableConfigurationProperties({HttpProperties.class}) @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({CharacterEncodingFilter.class}) @ConditionalOnProperty( prefix = "spring.http.encoding", value = {"enabled"}, matchIfMissing = true ) public class HttpEncodingAutoConfiguration { @Bean @ConditionalOnMissingBean public CharacterEncodingFilter characterEncodingFilter() { CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter(); filter.setEncoding(this.properties.getCharset().name()); filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST)); filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE)); return filter; } ... }
咱们能够看到该类的注解以下:
@Configuration
毫无疑问,代表这是一个配置类,和咱们要自定义一个配置文件同样,实现给容器中添加组件;@EnableConfigurationProperties
启动指定类的ConfigurationPropertiesg功能,这样就能够将配置文件中对应的值和HttpEncodingProperties绑定起来;并把HttpEncodingProperties加入到ioc容器中;@ConditionalOnWebApplication
Spring底层@Conditional
注解,根据不一样的条件,若是知足指定的条件,整个配置类里面的配置就会生效;此处判断的就是当前应用是否是Web应用;不然配置不生效;@ConditionalOnClass
判断当前项目有没有类(CharacterEncodingFilter
),这是SpringMVC中进行乱码解决的过滤器;@ConditionalOnProperty
判断配置文件中是否存在某个配置 spring.http.encoding.enabled
;若是不存在,则判断成立,若是没有配置,则此处将其设置为true
;@Bean
给容器中添加Bean组件,该组件的某些值须要从properties中获取,此处即为HttpEncodingProperies,显然此刻他的取值已经和springboot的properties文件进行注入了;根据不一样的条件进行判断当前这个配置类是否生效。一单这个配置类生效,这个配置类就会给容器中添加各类组件;这些组件的属性均来自于其对应的Properties类的,这些Properties类里面的每个属性,又是和配置文件绑定的。
@EnableConfigurationProperties
指定的properties类HttpProperties
:@ConfigurationProperties( prefix = "spring.http" ) public class HttpProperties {
xxxAutoConfiguration 这种类就是用来作自动配置的,他会给容器中添加相关的组件,其对应的Properties则对应了配置的各类属性;也就是说,经过这些配置类,咱们之前须要在SpringMVC中写配置类、文件实现的东西,如今,只须要在Properites配置文件中加入相关的配置便可,再也不那么麻烦了。
固然,一些特殊的配置仍是得本身写组件的哦。
只有其指定的条件成立,配置类的全部类型才会生效,更小范围的,例如注释在某个Bean组件上面的相关条件注解成立,才会生成该Bean。
@Conditional扩展注解 | 做用(判断是否知足当前指定条件) |
---|---|
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定Bean |
@ConditionalOnMissingBean | 容器中不存在指定Bean |
@ConditionalOnExpression | 知足SpEL表达式指定 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定资源文件 |
@ConditionalOnWebApplication | 当前是web环境 |
@ConditionalOnNotWebApplication | 当前不是web环境 |
@ConditionalOnJndi | JNDI存在指定项 |
咱们能够发现,尽管咱们拥有许多的自动配置类,其仍是得必须知足必定条件才会生效,该机制就是有@Conditinal派生注解等控制的,常见的是
@ConditionalOnClass
,即判断当前系统具不具有相关的类。
配置文件application.properties中添加配置,开启Debug模式:
debug=true
默认状况下debug的值为false,经过启用debug=true
属性,让控制台打印相关的报告,例如那些自动配置类启用(positive matches)、没启用(negative matches)等。