欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

springboot2.0整合使用Apollo配置中心

程序员文章站 2022-07-14 08:50:22
...

springboot 版本:2.1.9.RELEASE

Apollo 版本:1.4.0

一、背景

对于传统的单体应用,通常使用配置文件管理所有配置。比如Spring Boot开发的单体应用,配置内容可以放在application.yml文件,需要切换环境的话可以设置多个Profile并在启动应用时指定spring.pfofiles.active={profile}。

然而,在微服务架构中,配置管理一般有以下需求

  • 集中管理配置:一个使用微服务架构的应用系统可能会包含成千上万个微服务,因此集中管理配置是非常有必要的。
  • 不同环境不同配置:例如,数据源配置在不同的环境(开发、测试、预发布、生产等)中是不同的。
  • 运行期间可动态调整:例如,可根据各个微服务的负载情况,动态调整数据源连接池大小或熔断阈值,并且在调整配置时不停止微服务。
  • 配置修改后可自动更新。如配置内容发生变化,微服务能够自动更新配置。

所以,对于微服务架构而言,一个通用的配置管理机制是必不可少的,常见做法是使用配置服务器管理配置。

不管你的微服务项目是否使用Spring Cloud,相对于Spring Cloud Config,Apollo都是更好的选择。

springboot2.0整合使用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)。

springboot2.0整合使用Apollo配置中心

http://localhost:8080 如果出现eureka 的管理界面,说明服务启动正常。

springboot2.0整合使用Apollo配置中心

四 Apollo配置中心使用

1、创建项目,其中appid为springboot项目需要配置对应的 ,这个ID是应用的唯一标识

 

springboot2.0整合使用Apollo配置中心

springboot2.0整合使用Apollo配置中心

2、添加配置,此时添加的配置未发布 发布后生效。也可以回滚至上一个设置结果

springboot2.0整合使用Apollo配置中心

 

五、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