SpringCloud Config(配置中心)实现配置自动刷新--svn_mameng1998的博客-程序员宅基地

技术标签: SpringCloud  

1 搭建一个svn仓库,存放springboot客户端的配置文件

配置文件命名方式参考官网,这里取其中一种:{application}-{profile}.yml

2 服务端搭建

新建一个springboot项目,添加依赖:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

bootstrap.yml文件配置如下:

server:
  port: 8087

spring:
  application:
    name: config-server-svn 
  profiles: 
    active: subversion     #使用svn作为配置仓库,必须显示声明profiles.active=subversion,不然还是用的git
  cloud: 
    config: 
      server: 
        svn: 
          uri: http://xxx.xx.xxx.xxx/springconfig/trunk/SpringCloudConfig    #配置svn仓库地址
          searchPaths: respo                                        #配置仓库路径
          username: xxxxxx                                          #访问svn仓库的用户名
          password: xxxxxx                                          #访问svn仓库的用户密码
          basedir: /data                                            #默认在系统临时目录下面,需要调整一下避免临时文件被系统自动清理
      label: trunk                                                  #配置svn的分支

  rabbitmq:
    host: xxx.xx.xxx.xxx
    port: 5672
    username: xxxxxxx
    password: xxxxxxxx

configServer的工作流程:
1 服务端注册客户端获取配置接口
2 健康检查时刷新svn仓库到本地
3 客户端启动和每次健康检查时调用该接口获取配置.

3 客户端搭建

另起一个客户端,依赖config,actuator以及bus-amqp

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
 
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
 
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

bootstrap.yml文件配置如下:

server:
  port: 8120

spring:
  application:
    name: microservice
  cloud:
    config:
      uri: http://config.xxxxxxxxx.com/          #指明配置服务中心的网址
      profile: test                                          #dev开发环境配置文件,test测试环境配置文件,prod生产环境配置文件
      label: trunk
      fail-fast: true                                        #拉取配置失败时快速退出,否则有时项目依旧会启动,造成某些依赖的组件为空

  rabbitmq:
    host: xxx.xxx.xx.xx
    port: 5672
    username: xxxx
    password: xxxxxxx

4.客户端配置热更新

至此仅实现客户端初始化时从配置中心拉取配置。修改配置需重启应用.如何实现客户端配置的热更新?主要是@RefreshScope这个注解,热更新redis示例:

/**
* 因为@RefreshScope注解的组件是懒加载的,所以如果有starter的话,可
* 能上下文中已经有了一个redisConnectionFactory,所以建议不要依赖自动* 装配的包,自己定义一个redis配置的组件
*/
@Configuration
@RefreshScope
public class RedisConnectionFactoryConf {

    @Value("${spring.redis.database}")
    private int database;

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.password}")
    private String password;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.timeout:2000}")
    private long timeout;

    @Value("${spring.redis.lettuce.pool.max-idle:5}")
    private int maxIdle;

    @Value("${spring.redis.lettuce.pool.min-idle:0}")
    private int minIdle;

    @Value("${spring.redis.lettuce.pool.max-active:10}")
    private int maxActive;

    @Value("${spring.redis.lettuce.pool.max-wait:2000}")
    private long maxWait;

    private LettuceConnectionFactory lettuceConnFactory() {

        // 单机版配置
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setDatabase(database);
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        redisStandaloneConfiguration.setPassword(RedisPassword.of(password));

        // 集群版配置
//        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
//        String[] serverArray = clusterNodes.split(",");
//        Set<RedisNode> nodes = new HashSet<RedisNode>();
//        for (String ipPort : serverArray) {
//            String[] ipAndPort = ipPort.split(":");
//            nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
//        }
//        redisClusterConfiguration.setPassword(RedisPassword.of(password));
//        redisClusterConfiguration.setClusterNodes(nodes);
//        redisClusterConfiguration.setMaxRedirects(maxRedirects);

        //连接池配置
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
        genericObjectPoolConfig.setMaxIdle(maxIdle);
        genericObjectPoolConfig.setMinIdle(minIdle);
        genericObjectPoolConfig.setMaxTotal(maxActive);
        genericObjectPoolConfig.setMaxWaitMillis(maxWait);

        LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                .commandTimeout(Duration.ofMillis(timeout))
                .poolConfig(genericObjectPoolConfig)
                .build();

        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig);
        lettuceConnectionFactory.afterPropertiesSet();
        return lettuceConnectionFactory;
    }

    @RefreshScope
    @Bean("lettuceRedisTemplate")
    public RedisTemplate<String, String> myTemplate() {
        LettuceConnectionFactory factory = this.lettuceConnFactory();
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        return template;
    }

}

配置文件为bootstrap.yml,配置基本数据,主要包括config客户端配置。svn配置hooks到config的/actuator/bus-refresh这个接口。当有svn push事件发生时,会调用该接口,从而通过spring bus通知到客户端,客户端删除@RefreshScope的Bean缓存,以重新创建基于新配置的bean。

流程如下:
1.svn仓库push事件
2.hooks->POST configServer/actuator/bus-refresh
3.configServer publish>>Bus
4.Client subscribe>>Bus
5.refresh

这里需要注意,如果是svn配置的hooks,因其body的payload的原因,config服务端可能会解析失败,此时有如下解决方案,配置一个filter,使此request的body为空:

@WebFilter(urlPatterns = "/actuator/bus-refresh")
public class RefreshFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;

        String url = httpServletRequest.getRequestURI();
        if (!url.endsWith("/actuator/bus-refresh")) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            EmptyRequestWrapper requestWrapper = new EmptyRequestWrapper(httpServletRequest);
            filterChain.doFilter(requestWrapper, servletResponse);
        }
        return;
    }

    @Override
    public void destroy() {

    }

    /**
     * 返回自定义的空request
     */
    private class EmptyRequestWrapper extends HttpServletRequestWrapper {
        public EmptyRequestWrapper(HttpServletRequest request) {
            super(request);
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            byte[] bytes = new byte[0];
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);

            return new ServletInputStream() {
                @Override
                public boolean isFinished() {
                    return byteArrayInputStream.read() == -1 ? true : false;
                }

                @Override
                public boolean isReady() {
                    return false;
                }

                @Override
                public void setReadListener(ReadListener readListener) {

                }

                @Override
                public int read() throws IOException {
                    return byteArrayInputStream.read();
                }
            };
        }
    }
}

参考文章:
1、https://blog.csdn.net/wtdm_160604/article/details/83720391
2、https://blog.csdn.net/Sadlay/article/details/84964839
3、https://blog.csdn.net/Michael_HM/article/details/78497583
4、https://blog.csdn.net/w405722907/article/details/86712781

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/mameng1988/article/details/91040943

智能推荐

get空对象中的属性不一定报空指针异常_get属性为空和报错_feeStc的博客-程序员宅基地

public class Test { public static void main(String[] args) { Student stu = null; System.out.println(stu.getName()); }}看到上述代码,运行结果是什么?NullPointerException?看下Student类吧。public class Student {

aspectJ最简单的HelloWorld例子_石头wang的博客-程序员宅基地

aspectJ最简单的HelloWorld例子这是aspectJ的入门。aspectJ和aop有什么区别? aspectJ也能够实现和aop功能,aop一般指spring的aop,就是指使用@Aspect/@Pointcut/@Before/@Around等注解的那一套,实现原理是动态代理。而aspectJ是更加高效的在编译器的层面上植入通知的可以猜测,aspectJ 和 lombok 类似,...

com.netflix.hystrix和org.springframework.cloud.netflix.hystrix两个包下都有HystrixCircuitBreaker_绅士jiejie的博客-程序员宅基地

com.netflix.hystrix.HystrixCircuitBreaker是接口,HystrixCircuitBreaker是Hystrix的核心组件,HystrixCircuitBreaker作为断路器使用,有着自己的核心方法:public interface HystrixCircuitBreaker { boolean allowRequest(); boolea...

3D游戏建模入门须知:次世代建模软件有哪些?零基础你都知道吗_Grape_3DModeler的博客-程序员宅基地

Hi~ o(* ̄▽ ̄*)ブ 小伙伴们,你想玩建模吗?次世代建模,一般是建模、雕刻、展UV、拓扑、贴图、做材质等几个步骤。在不同的步骤当中,所用到的软件有所不同。这里为大家科普下建模软件:高模:Maya、3Dmax、Zbrush中模:Maya、3Dmax低模:Maya、3Dmax、Topogun展UV:Maya、Zbrush、Unfold3D、Uvlayout烘焙:Maya、Zbrush、3Dmax、Xnormal、3DO、GrazyBump材质:Photoshop、Subst

对于verlog仿真的时候,数据打拍delay的问题_verilog打拍_ronaldo_hu的博客-程序员宅基地

这几天对于verlog里面reg变量赋值,导致数据delay的情况十分混论,这里理一理; 首先单独一个reg型变量在always块中,进行常数赋值或者自赋值,显然不会产生delayalways@( posedge clk or negedge rst_n )begin if( !rst_n )begin count_reg <= 0; end else

290种零食大统计,谁能唤起80、90后的童年回忆?|数据会说话_csdn业界要闻的博客-程序员宅基地

戳蓝字“CSDN云计算”关注我们哦!数据分析:喜欢果脯的朱小五内容撰写:只爱辣条的王小九本文转自公众号『凹凸数读』1块钱能买到什么?对于80、90后的童年来讲,1块钱是4...

随便推点

uniapp 二维码或图片转成base64格式并分享到qq或微信_兄弟连勇闯天涯的博客-程序员宅基地

断断续续的搞了两次,终于把这个功能实现了。1.二维码的插件2.转base64格式的工具(图像转换工具,可用于图像和base64的转换)3.uniapp安装// 以下路径需根据项目实际情况填写import { pathToBase64, base64ToPath } from '../../js/image-tools/index.js'4.pathToBase64从图像路径转...

RMAN-05501 RMAN-05001_aborting duplication of target database_Data & safety的博客-程序员宅基地

错误信息:RMAN-05501: aborting duplication of target databaseRMAN-05001: auxiliary file name /oracle/oradata/skatedb/tbs_statspack01.dbf conflicts with a file used by the target database在用rman duplicate创建dg的时候,抛出如上的错误,这里只列出用rman dumplicate的过程,具体操作步骤如下:.

电力系统潮流计算中的导纳矩阵计算,matlab源程序_潮流计算中导纳矩阵的计算 程序_山高一小的博客-程序员宅基地

电力系统导纳矩阵计算,MATLAB这学期在上大四专业选修课时,一个课后作业是写一个电力系统的导纳矩阵计算程序,我找了找资料肝了半天的程序如下图所示,希望能对大家有用。程序说明1.具有非标准变比的变压器处理如果变压器阻抗归算到非标准变比的K侧,则在参数输入脚本文件data中变压器参数第五列记为0;如果归算到非标准变比的1侧,则在参数输入脚本文件data中变压器参数第五列记为1。2.线路为双回线时,需要将两个节点之间线路阻抗减半,导纳加倍;同时,如果线路是双回线则在data线路参数中第五列记为1,否

使用ShaderGraph制作动漫人物眼睛部分_wakawaka555的博客-程序员宅基地

使用ShaderGraph制作动漫人物眼睛部分实现效果如下图:实现步骤:新建HDRP工程,创建Eye Graph(2019版还是处于预览版,正式项目慎用)节点图如下连接点这里就不详述了,官网上有详细的解释。2.人物模型使用资源为官方资源,百度链接如下:链接:https://pan.baidu.com/s/1K6SxpO7_PROLdAWKbPm5dw提取码:jkml3.新建Sample Texture 2D节点,然后创建两个Texture2D变量,分别显示眼睛和眼白图片:如上图所示,

html鼠标滚动效果代码,JS+CSS实现大气清新的滑动菜单效果代码_hi啊的博客-程序员宅基地

本文实例讲述了JS+CSS实现大气清新的滑动菜单效果代码。分享给大家供大家参考,具体如下:这是一款比较大气清新的滑动导航菜单,CSS和JavaScript配合完成,鼠标放到一级菜单上,会滑出二级的菜单,兼容性也不错,适合大多数网站使用,用到两张背景图片,请拷贝图片地址下载图片。运行效果截图如下:在线演示地址如下:具体代码如下:/p&gt;"http://www.w3.org/TR/xhtml1/D...

java查询WFS服务_weixin_30511039的博客-程序员宅基地

在我们访问wfs服务时候,有时候会遇到前台访问时候的跨域问题。这里给出java访问的一个小例子。 1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStream; 4 import java.io.InputStreamReader; 5 imp...

推荐文章

热门文章

相关标签