灰度实战(三):Apollo配置中心(3)

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

强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan

【前言】

       在上一篇博文《灰度实战(二):Apollo配置中心(2)》中讲解了Apollo如何动态更改程序中通过@value配置值,在本篇博文中为大家带来如何通过Apollo动态更新程序和中间件的连接。

【实时推送演示】

         一、程序和第三方组件连接动态更改(在此以连接redis为例)---失败版

               1、演示代码(增加redis操作)

package com.zhanghan.grayapollo.controller;

import com.zhanghan.grayapollo.util.wrapper.WrapMapper;
import com.zhanghan.grayapollo.util.wrapper.Wrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@Api(value = "演示Apollo控制器",tags = {"演示Apollo控制器"})
public class DynamicController {

    @Value("${zh.int}")
    private Integer zhInt;

    @Autowired
    private RedisTemplate<String, String> strRedisTemplate;

    @ApiOperation(value="测试通过@value注入数据",tags = {"演示Apollo控制器"})
    @RequestMapping(value = "/test/value", method = RequestMethod.POST)
    public Wrapper testValue() {
        Map<String, Object> map = new HashMap();
        map.put("zhTest", zhInt);
        return WrapMapper.ok(map);
    }

    @ApiOperation(value="演示向redis中放数据",tags = {"演示Apollo控制器"})
    @RequestMapping(value = "/post/rdb", method = RequestMethod.POST)
    public Wrapper postDB() {
        strRedisTemplate.opsForValue().set("zh-test",zhInt.toString());
        Map<String, Object> map = new HashMap();
        map.put("putZhTest", zhInt.toString());
        return WrapMapper.ok(map);
    }

    @ApiOperation(value="演示从redis中获取数据",tags = {"演示Apollo控制器"})
    @RequestMapping(value = "/get/rdb", method = RequestMethod.POST)
    public Wrapper getDB() {
        String getZhInt = strRedisTemplate.opsForValue().get("zh-test");
        Map<String, Object> map = new HashMap();
        map.put("getZhTest", getZhInt);
        return WrapMapper.ok(map);
    }

}

               2、访问swagger给redis设置值

               3、访问swagger读取redis设置的值

               4、用redis可视化工具查看,此时存储在redis的1库中(此时2库中没有值)

               5、在Apollo上修改redis的库(由1改为2),并发布

               6、查看系统的日志,发现将变动已经推送到程序

               7、此时再次访问swagger的从redis中读取值接口

               8、小结:

                   竟然还可以读取到值,说明redis数据库并未切换;说明刚刚的配置变更只是推送到程序,而程序在第一次启动时已经和redis建立连接(其中含redis的database),推送并没有改变连接;

         二、程序和第三方组件连接动态更改(在此以连接redis为例)---成功版

               1、如何动态的更改那?

                     (1)增加Apollo的监听类并刷新程序配置

package com.zhanghan.grayapollo.refresh;

import com.ctrip.framework.apollo.model.ConfigChange;
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.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.stereotype.Component;

@Component
public class RedisPropertiesRefresher implements ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(RedisPropertiesRefresher.class);

    private ApplicationContext applicationContext;

    @Autowired
    private RefreshScope refreshScope;

    //此处配置的value值为Apollo的namespace名称
    @ApolloConfigChangeListener(value = "grayapollo")
    public void onChange(ConfigChangeEvent changeEvent) {

        boolean propertiesChanged = false;

        for (String changedKey : changeEvent.changedKeys()) {
            logger.info("===============================================================");
            logger.info("changedKey:{} value:{}", changedKey, changeEvent.getChange(changedKey));
            ConfigChange configChange = changeEvent.getChange(changedKey);
            configChange.getOldValue();
            propertiesChanged = true;
            break;
        }
        refreshProperties(changeEvent);
        if (propertiesChanged) {
            refreshProperties(changeEvent);
        }

    }

    private void refreshProperties(ConfigChangeEvent changeEvent) {
        this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
        refreshScope.refreshAll();
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


}

                     (2)redis工场增加@RefreshScope

package com.zhanghan.grayapollo.config;

import com.zhanghan.grayapollo.properties.RedisProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisPoolConfig;

@Component
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    @Autowired
    private RedisProperties redisProperties;

    @Bean
    @RefreshScope  //此注解用于动态刷新
    public JedisConnectionFactory jedisConnectionFactory() {
        RedisStandaloneConfiguration rf = new RedisStandaloneConfiguration();
        rf.setDatabase(redisProperties.getDatabase());
        rf.setHostName(redisProperties.getHost());
        rf.setPort(redisProperties.getPort());
        rf.setPassword(RedisPassword.of(redisProperties.getPassword()));
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpb =
                (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration.builder();
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(redisProperties.getMaxIdle());
        jedisPoolConfig.setMinIdle(redisProperties.getMinIdle());
        jedisPoolConfig.setMaxTotal(redisProperties.getMaxActive());
        jedisPoolConfig.setMaxWaitMillis(redisProperties.getMaxWait());
        jedisPoolConfig.setEvictorShutdownTimeoutMillis(redisProperties.getTimeout());
        jpb.poolConfig(jedisPoolConfig);
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(rf, jpb.build());
        return jedisConnectionFactory;
    }


    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    RedisTemplate<Object, Object> redisTemplate() {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        return redisTemplate;
    }

    @Bean
    RedisTemplate<String, String> strRedisTemplate() {
        final RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory());
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericToStringSerializer<>(String.class));
        template.setValueSerializer(new GenericToStringSerializer<>(String.class));
        return template;
    }

    @Bean
    RedisTemplate<String, Long> longRedisTemplate() {
        final RedisTemplate<String, Long> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory());
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericToStringSerializer<>(Long.class));
        template.setValueSerializer(new GenericToStringSerializer<>(Long.class));
        return template;
    }

    @Bean
    RedisTemplate<String, Boolean> booleanRedisTemplate() {
        final RedisTemplate<String, Boolean> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory());
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericToStringSerializer<>(Boolean.class));
        template.setValueSerializer(new GenericToStringSerializer<>(Boolean.class));
        return template;
    }

    @Bean
    RedisTemplate<String, Integer> intRedisTemplate() {
        final RedisTemplate<String, Integer> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory());
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
        return template;
    }
}

               2、此时清空本地redis,再重新做实验,进行验证;(程序启动时Apollo配置的redis的数据库为1,程序启动后动态改成连库2)

               3、访问swagger给redis设置值

               4、访问swagger读取redis设置的值

               5、用redis可视化工具查看,此时存储在redis的1库中(此时2库中没有值)

               6、在Apollo上修改redis的库(由1改为2),并发布

               7、此时再次访问swagger的从redis中读取值接口(惊喜出现了),说明换库了

               8、究竟是换的是不是1库那?我们此时再在swagger上调用放入redis值接口

               9、此时通过redis客户端查看库2中惊奇发现已经有刚才设置的值;说明已经成功的切库。

               10、至此实验成功;

         三、项目地址

               灰度实战:https://github.com/dangnianchuntian/gray

【总结】

         1、本节第一部分为大家证实,如果不配置Apollo监听以及redis连接工程的动态更新,不能动态的更改程序与中间件连接。

         2、本节第二部分为大家演示如何接收Apollo动态更新连第三方中间件的连接池(以redis连接池为例)。

猜你喜欢

转载自blog.csdn.net/u012829124/article/details/94601303