java编程有一条不成文的规定就是:“约定大于配置,配置大于代码”,从而解耦。
1,配置文件
在Spring Boot项目中,把很多配置信息写入配置文件(properties或者yml文件),但每次修改配置后必须重启服务。
不管yml文件还是properties文件,都接受spring样式占位符$ {...}
来写入环境变量。
1)YAML文件
- 文件后缀为 .yml
如、
文件名可自定义,要在项目启动时指定配置文件的名字。 - 基本语法
大小写敏感;
使用缩进(tab,相同层级的元素左对齐)表示层级关系;
'#'表示注释。 - 同时存在yml和propertries文件,前者优先级更高。
1>支持数据类型
- 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
keytype:
child-key: value
child-key2: value2
- 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
stages:
# 静态检查
- pre_verify
# 项目构建
- build
# 运行时检查
- verify
# 自动化测试
- auto_test
# 部署
- deploy
# 测试
- test
# 发布
- release
- 纯量(scalars):单个的、不可再分的值
boolean:
- TRUE #true,True都可以
- FALSE #false,False都可以
float:
- 3.14
- 6.8523015e+5 #可以使用科学计数法
int:
- 123
- 0b1010_0111_0100_1010_1110 #二进制表示
null:
nodeName: 'node'
parent: ~ #使用~表示null
string:
- 哈哈
- 'Hello world' #可以使用双引号或者单引号包裹特殊字符
- newline
newline2 #字符串可以拆成多行,每一行会被转化成一个空格
date:
- 2018-02-17 #日期必须使用ISO 8601格式,即yyyy-MM-dd
datetime:
- 2018-02-17T15:02:31+08:00 #时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区
2>引用
& 锚点和 * 别名,可以用来引用:
# & 用来建立锚点(defaults)
defaults: &defaults
adapter: postgres
host: localhost
development:
database: myapp_development
# << 表示合并到当前数据,* 用来引用锚点
<<: *defaults
test:
database: myapp_test
<<: *defaults
defaults:
adapter: postgres
host: localhost
development:
database: myapp_development
adapter: postgres
host: localhost
test:
database: myapp_test
adapter: postgres
host: localhost
3>项目位置及优先级
首先在Spring Boot中可以写在四个不同的位置,优先级依次降低(相同属性高优先级覆盖低优先级):
- 项目根目录下的config目录中
- 项目根目录下
- classpath下的config目录中
- classpath目录下
启动加载配置有3种方式:
java -jar --=app 4个位置里的配置文件名
或者 这种定义方式会覆盖掉默认的四个位置
或者 -location 表示在四个位置的基础上,再添加几个位置,新添加的位置的优先级大于原本的位置
4>java读取yaml数据
- 对象
yaml见上文举例;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.HashMap;
@Component
//把环境变量中以mkeytype打头的属性都绑定到类的成员变量上,并完成对应类型的转换
@ConfigurationProperties(prefix = "mkeytype")
public class KeyTypeMap extends HashMap<String, String> {
}
通过ApplicationContextAware接口加载对应的bean:
KeyTypeMap keyTypeMap = SpringContextUtils.getBean(KeyTypeMap.class);
- 数组
redis:
redisConfigs:
- host: 192.168.66.128
port: 6379
- host: 192.168.66.129
port: 6380
@Component
@ConfigurationProperties(prefix = "redis")
public class RedisCluster {
private List<SingleRedisConfig> redisConfigs;
//省略getter/setter
}
- 单值
通过@Value("${}")
获取。
2)properties文件
String driver="";//mysql提供的Driver接口的实现类
String jdbcUrl="jdbc:mysql:///user";//此处为"jdbc:mysql://localhost:3306/user"的简化形式,user为数据库名
String user="root";
String password="451535";
(driver);//通过反射动态实例化mysql数据库驱动类
Connection conn= (jdbcUrl,user,password);
- 文件后缀为“.properties”,属文本文件;
- 内容格式:“键=值”
- 无序
- “#”作为注释
- 场景:将配置文件(如数据库密码)等与java代码解耦。
- 通过
可以读取或者输出Properties文件
2,配置中心
- 远程配置内容与本地配置内容重叠时,以远程配置内容为准;
1)优点
- 统一管理配置;
- 修改配置后不需要手动打包;
- 修改配置后不需要重启服务。
2)常用组件
在Spring Cloud中,Spring Cloud Config是最早的配置中心,目前有一些用的比较多的开源的配置中心,比如携程的 Apollo、蚂蚁金服的 disconf 等,对比 Spring Cloud Config,这些配置中心功能更加强大。
3)Spring Cloud Config三大组件
1>config-server
提供给客户端获取配置。
2>Git
用于存储和修改配置。除了 git 外,还可以用数据库、svn、本地文件等作为存储。
3>Spring Cloud Bus
通知客户端配置变更。
4)demo
1)config 文件
git存储配置:
spring:
application:
name: config-server # 应用名称
cloud:
config:
server:
git:
uri: https:///config-demo #配置文件所在仓库
username: github 登录账号
password: github 登录密码
default-label: master #配置文件分支
search-paths: config #配置文件所在根目录
数据库存储配置:
spring:
application:
name: config-server
profiles:
active: jdbc
cloud:
config:
server:
jdbc:
sql: SELECT KEY, VALUE from CONFIG_INFO where LABEL=?
order: 0
default-label: master
security:
#配置后每次访问config-server 都需要验证
user:
name: root
password: security密码
2>在 Application 启动类上注解 @EnableConfigServer
@SpringBootApplication
@EnableConfigServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
maven依赖:
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring cloud config 服务端包 -->
<dependency>
<groupId></groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
3>通过浏览器访问配置中心
ip和port为config-service对应的ip和端口。
查询链接: ip:port/查询规则
如:上文中数据库的查询,通过链接10.3.3.3:8888/master
可以返回所有满足要求的查询(config_info表中label为mater的结果)。
4>使用配置
- maven依赖
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring cloud config 客户端包 -->
<dependency>
<groupId></groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
spring:
profiles: dev
application:
name: config-single-client
cloud:
config:
uri: http://localhost:3301
label: master
profile: dev
#设为true,如果无法连接config service,启动时会抛异常,并停止服务
fail-fast: true
- 读取配置
要读取配置中心的内容,需要增加相关的配置类,Spring Cloud Config 读取配置中心内容的方式和读取本地配置文件中的配置是一模一样的。可以通过 @Value 或 @ConfigurationProperties 来获取。
区别在于@ConfigurationProperties 配合下文的@RefreshScope可以自动刷新配置信息,但是@Value不可以,所以不推荐使用@Value。
@Data
@Component
public class GitConfig {
@Value("${}")
private String env;
@Value("${}")
private String username;
或者:
private String psw;
@Value("${:abc}")
public void setPsd(String psw){
this.psw= psw;
}
}
或者:
@Component
@Data
@ConfigurationProperties(prefix = "data")
public class GitAutoRefreshConfig {
public static class UserInfo {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "UserInfo{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
private String env;
private UserInfo user;
}
- 实现自动刷新配置
spring-cloud-config提供了一个刷新机制,但是需要我们主动触发。那就是 @RefreshScope 注解并结合 actuator ,注意要引入 spring-boot-starter-actuator 包。
yml中增加,然后在需要读取配置的类上增加 @RefreshScope 注解。
management:
endpoint:
shutdown:
enabled: false
endpoints:
web:
exposure:
include: "*"
我们提供一个接口,每次调用这个接口就可以自动刷新配置信息。
@GetMapping(value = "autoShow")
public Object autoShow(){
return gitAutoRefreshConfig;
}
但其实每次修改配置后都需要主动调用这个接口,git提供了webhook的方式,当有代码变更的时候,会调用我们设置的地址,从而达到自动刷新的目的。如果端比较多,webhook需要一个个调用刷新配置,此时使用Spring Cloud Bus的广播功能,让client端都订阅配置更新事件,以此批量更新。
5>结合Eureka
Spring Cloud Config 注册到 Eureka 之上,方便其他服务消费者使用,并且可以注册多个配置中心服务端,以实现高可用。
config-service只需要把自己注册到Eureka即可。
config客户端同样需要先注册到Eureka,修改配置信息:
spring:
application:
name: test-service
cloud:
config:
discovery:
enabled: true
#指定配置中心服务端的server-id
service-id: config-service
#设为true,如果无法连接config server,启动时会抛异常,并停止服务
fail-fast: true
username: root
password: security密码
profile: dev
label: master
retry:
initial-interval: 1000
multiplier: 1.3
max-attempts: 6
max-interval: 3000