springboot2.0整合使用Apollo配置中心
springboot 版本:2.1.9.RELEASE
Apollo 版本:1.4.0
一、背景
对于传统的单体应用,通常使用配置文件管理所有配置。比如Spring Boot开发的单体应用,配置内容可以放在application.yml文件,需要切换环境的话可以设置多个Profile并在启动应用时指定spring.pfofiles.active={profile}。
然而,在微服务架构中,配置管理一般有以下需求
- 集中管理配置:一个使用微服务架构的应用系统可能会包含成千上万个微服务,因此集中管理配置是非常有必要的。
- 不同环境不同配置:例如,数据源配置在不同的环境(开发、测试、预发布、生产等)中是不同的。
- 运行期间可动态调整:例如,可根据各个微服务的负载情况,动态调整数据源连接池大小或熔断阈值,并且在调整配置时不停止微服务。
- 配置修改后可自动更新。如配置内容发生变化,微服务能够自动更新配置。
所以,对于微服务架构而言,一个通用的配置管理机制是必不可少的,常见做法是使用配置服务器管理配置。
不管你的微服务项目是否使用Spring Cloud,相对于Spring Cloud Config,Apollo都是更好的选择。
二、Apollo简介
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
服务端基于Spring Boot和Spring Cloud开发,打包后可以直接运行,不需要额外安装Tomcat等应用容器。
Java客户端不依赖任何框架,能够运行于所有Java运行时环境,同时对Spring/Spring Boot环境也有较好的支持。
更多介绍,请到GitHub了解:https://github.com/ctripcorp/apollo。
三、Apollo配置中心服务端
本文的重点在于Apollo在客户端的使用,所以Apollo服务端使用的是官网提供的 Quick Start(针对本地测试使用)。如果要部署到生产环境,还请另行参考分布式部署指南。
1、准备工作
1)Java
服务端要求1.8+,客户端要求1.7+。由于Quick Start会在本地同时启动服务端和客户端,所以需要在本地安装Java 1.8+。
2)MySQL
Apollo的表结构对timestamp
使用了多个default声明,所以需要5.6.5以上版本。
3)下载Apollo项目
git clone https://github.com/ctripcorp/apollo
4)创建数据库
创建以下两个数据库并导入初始化数据:
- ApolloConfigDB
- ApolloPortalDB
ApolloConfigDB 所在的文件目录:
${your_file_directory}\apollo\scripts\sql\apolloconfigdb
ApolloPortalDB
${your_file_directory}\apollo\scripts\sql\portaldb
在MySQL数据库中执行这两个SQL文件,完成数据库的创建和数据的初始化操作。
打包项目(build package)
将下载下来的 apollo 源码导入到idea中,我们需要关注的几个项目:
apollo-configservice | apollo-adminservice | apollo-protal |
---|---|---|
配置服务(meta server、eureka) | 配置管理服务 | apollo管理UI |
找到 /apollo/scripts/build.bat(Linux 是 bulid.sh)
@echo off
rem apollo config db info
set apollo_config_db_url="jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8"
set apollo_config_db_username="root"
set apollo_config_db_password=""
rem apollo portal db info
set apollo_portal_db_url="jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8"
set apollo_portal_db_username="root"
set apollo_portal_db_password=""
rem meta server url, different environments should have different meta server addresses
set dev_meta="http://localhost:8080"
set fat_meta="http://someIp:8080"
set uat_meta="http://anotherIp:8080"
set pro_meta="http://yetAnotherIp:8080"
set META_SERVERS_OPTS=-Ddev_meta=%dev_meta% -Dfat_meta=%fat_meta% -Duat_meta=%uat_meta% -Dpro_meta=%pro_meta%
rem =============== Please do not modify the following content ===============
rem go to script directory
cd "%~dp0"
cd ..
rem package config-service and admin-service
echo "==== starting to build config-service and admin-service ===="
call mvn clean package -DskipTests -pl apollo-configservice,apollo-adminservice -am -Dapollo_profile=github -Dspring_datasource_url=%apollo_config_db_url% -Dspring_datasource_username=%apollo_config_db_username% -Dspring_datasource_password=%apollo_config_db_password%
echo "==== building config-service and admin-service finished ===="
echo "==== starting to build portal ===="
call mvn clean package -DskipTests -pl apollo-portal -am -Dapollo_profile=github,auth -Dspring_datasource_url=%apollo_portal_db_url% -Dspring_datasource_username=%apollo_portal_db_username% -Dspring_datasource_password=%apollo_portal_db_password% %META_SERVERS_OPTS%
echo "==== building portal finished ===="
pause
更改数据库连接配置
rem apollo config db info
set apollo_config_db_url="jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8"
set apollo_config_db_username="root"
set apollo_config_db_password="root"
rem apollo portal db info
set apollo_portal_db_url="jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8"
set apollo_portal_db_username="root"
set apollo_portal_db_password="root"
更改 meta server(apollo-configservice/apollo-erueka) 地址
set dev_meta="http://localhost:8080"
set fat_meta="http://someIp:8080"
set uat_meta="http://anotherIp:8080"
set pro_meta="http://yetAnotherIp:8080"
修改完上面的配置之后,执行build.bat 批处理命令文件进行编译打包,在执行的过程中可能会出现一些异常(一般是maven依赖异常),自行百度解决之后,再重新执行。
打包成功之后,找到 apollo-configservice、apollo-adminservice、apollo-portal 下的 target 目录(build是执行 maven 的 package 命令),找到已经打好的三个jar包,copy 出来放到一个单独的目录(方便启动)。
进入jar 的当前目录,==依次==启动apollo-configservice、apollo-adminservice、apollo-portal 三个服务。
java -jar apollo-configservice-1.8.0-SNAPSHOT.jar
java -jar apollo-adminservice-1.8.0-SNAPSHOT.jar
java -jar apollo-portal-1.8.0-SNAPSHOT.jar
全部启动完成之后,打开浏览器输入:
http://localhost:8070 如果出现apollo 的登录界面,说明已经启动成功(登录名/密码:apollo/admin)。
http://localhost:8080 如果出现eureka 的管理界面,说明服务启动正常。
四 Apollo配置中心使用
1、创建项目,其中appid为springboot项目需要配置对应的 ,这个ID是应用的唯一标识
2、添加配置,此时添加的配置未发布 发布后生效。也可以回滚至上一个设置结果
五、Apollo配置中心客户端
1添加依赖
<!-- https://mvnrepository.com/artifact/com.ctrip.framework.apollo/apollo-client -->
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.ctrip.framework.apollo/apollo-core -->
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-core</artifactId>
<version>1.4.0</version>
</dependency>
2、项目启动类添加@EnableApolloConfig // 开启Apollo客户端
3、application.yml添加配置信息
可通过设置enable为false关闭热加载功能
app:
# 应用ID(在Apollo服务端新增项目添加的应用ID)
id: test001
apollo:
# apollo-config-service地址
meta: http://localhost:8080
bootstrap:
namespaces: application
#apollo针对@ConfigurationProperties属性配置不进行热部署 enabled默认为false不开启热部署配置(@value形式自动热部署)
enabled: true
4、添加热加载功能
package com.primeton.bps.config;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.context.scope.refresh.RefreshScope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
/**
* @author : xifanzhou
* @Description :
*/
@Configuration
@ConditionalOnClass(ConfigService.class)
@ConditionalOnProperty(prefix = ApolloConfig.APOLLO_CONFIG_PREFIX, name = "enabled",
havingValue = "true")
public class ApolloConfig implements ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(ApolloConfig.class);
public static final String APOLLO_CONFIG_PREFIX = "apollo.bootstrap";
@Value("${apollo.bootstrap.namespaces}")
private String[] namespaces;
/**
* spring控制器
*/
private ApplicationContext applicationContext;
/**
* 热加载控制器
*/
private final RefreshScope refreshScope;
public ApolloConfig(RefreshScope refreshScope) {
this.refreshScope = refreshScope;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 单个namespace配置方式
* "application"为apollo的namespace
* @param changeEvent 更新内容
*/
// @ApolloConfigChangeListener("application")
// //@ApolloConfigChangeListener({"application","application.yml"}) //监听多个namespace
// private void configChangeListter(ConfigChangeEvent changeEvent) {
// logger.info("**************Apollo动态修改配置**************");
// for (String changedKey : changeEvent.changedKeys()) {
// logger.info("changedKey :{}",changedKey);
// logger.info("changedValue :{}",changeEvent.getChange(changedKey));
// }
// refreshGatewayProperties(changeEvent);
// }
/**
* 多个namespace配置方式
* 启动时增加监听
*/
@PostConstruct
public void addRefreshListener() {
for (String namespace : namespaces) {
Config config = ConfigService.getConfig(namespace);
//对namespace增加监听方法
config.addChangeListener(changeEvent -> {
for (String key : changeEvent.changedKeys()) {
logger.info("changedKey :{}",key);
logger.info("changedValue :{}",changeEvent.getChange(key));
}
//将变动的配置刷新到应用中
refreshGatewayProperties(changeEvent);
});
}
}
/**
* 更新SpringApplicationContext对象,
*
* @param changeEvent 更新内容
*/
private void refreshGatewayProperties(ConfigChangeEvent changeEvent) {
try {
//更新配置
this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
logger.info("**************Apollo动态修改配置成功**************");
}catch (Exception e){
logger.error("**************Apollo动态修改配置失败**************",e);
}
}
}
上一篇: SpringBoot整合Apollo配置中心快速使用
下一篇: 浅谈数据结构
推荐阅读
-
springcloud使用consul作为配置中心
-
详解spring cloud config整合gitlab搭建分布式的配置中心
-
详解spring cloud config整合gitlab搭建分布式的配置中心
-
Zookeeper作为配置中心使用说明
-
SpringCloud学习系列之五-----配置中心(Config)和消息总线(Bus)完美使用版
-
SpringBoot2.0 基础案例(05):多个拦截器配置和使用场景
-
SpringCloud学习笔记(7):使用Spring Cloud Config配置中心
-
携程Apollo(阿波罗)配置中心在.NET Core项目快速集成
-
使用Spring Cloud Config搭建配置中心
-
使用Spring Cloud Config搭建配置中心