SpringBoot使用redis发布订阅方式更新配置信息

原来项目中使用枚举类定义了一些模块信息,在使用springboot后,想让这些枚举信息变成可编辑的配置信息,能随时通过页面进行编辑,然后在不停止服务的前提下更新数据,尝试了几种方案,最后觉得使用redis的发布订阅方式比较不错,下面就是记录的我的做法:

  1. 添加依赖
        <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-redis</artifactId>
       </dependency>
       <dependency>
           <groupId>org.apache.commons</groupId>
           <artifactId>commons-pool2</artifactId>
       </dependency>
  1. 添加监听器:用于监听处理redis发布的最新数据通知
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.List;

public class ConsumePubTableConfigListener implements MessageListener {
    private static final Logger log = LoggerFactory.getLogger(ConsumePubTableConfigListener.class);
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UpdateConfig config;
    @Autowired
    private IAppInfoDao iAppInfoDao;
    @Autowired
    private IModuleInfoDao iModuleInfoDao;

	@Override
	public void onMessage(Message message, byte[] pattern) {
        log.info("receive message ......");
		handleMessage(message);
	}

	public void handleMessage(Message message) {
		Object channel = stringRedisTemplate.getValueSerializer().deserialize(message.getChannel());
		Object value = stringRedisTemplate.getValueSerializer().deserialize(message.getBody());
		String channelStr =  String.valueOf(channel);
		String messageStr =  String.valueOf(value);
        log.info("message channel from :"+ channelStr + ":::::::: consumer message: "+ messageStr);
        //一种配置 处理
        if(SysConstants.TABLE_CONFIG_APP_UPDATE.equals(channelStr)){
            log.info("reload appConfig from table....");
            List<SmsAppInfo> infos = iAppInfoDao.queryAll();
            for(SmsAppInfo info:infos){
                config.getSmsApp().setSmsAppInfo(info);
            }
        }
        //另一种配置处理
        if(SysConstants.TABLE_CONFIG_MODULE_UPDATE.equals(channelStr)){
            log.info("reload moduleConfig from table....");
            List<SmsModuleInfo> infos = iModuleInfoDao.queryAll();
            for(SmsModuleInfo info:infos){
                config.getSmsModule().setSmsModuleInfo(info);
            }
        }
	}

}
  1. 把监听器添加到系统的配置中
import com.borui.lejane.listener.ConsumePubTableConfigListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

/**
 * 表配置变更
 */
@Configuration
public class ChangeConfig {
	@Autowired
	private LettuceConnectionFactory lettuceConnectionFactory;
	
	//刚才的监听器
	@Bean
	public ConsumePubTableConfigListener getConsumerRedis() {
		return new ConsumePubTableConfigListener();
	}
	
	@Bean
	public ChannelTopic appTopic() {
		return new ChannelTopic("business-topic-app");
	}
	@Bean
	public ChannelTopic moduleTopic() {
		return new ChannelTopic("business-topic-module");
	}
    //让监听器监听关心的话题
	@Bean
	public RedisMessageListenerContainer setRedisMessageListenerContainer() {
		RedisMessageListenerContainer container = new RedisMessageListenerContainer();
		container.setConnectionFactory(lettuceConnectionFactory);
		//话题1
		container.addMessageListener(getConsumerRedis()	, appTopic());
		//话题2
		container.addMessageListener(getConsumerRedis()	, moduleTopic());
		return container;
	}

}
  1. 系统启动时的数据加载
@Configuration
public class UpdateConfig {

    @Bean(initMethod = "loadDataFromDb")
    public BusinessApp getApp(){
        return new BusinessApp();
    }

    @Bean(initMethod = "loadDataFromDb")
    public BusinessModule getModule(){
        return new BusinessModule();
    }
}
  1. 业务类的处理
public class SmsApp {
    private static final Logger log = LoggerFactory.getLogger(SmsApp.class);
    private ConcurrentHashMap<String,SmsAppInfo> projectsMap = new ConcurrentHashMap<>();
    @Autowired
    private IAppInfoDao projectInfoDao;

    public void loadDataFromDb() {
        log.info("load app datas from db ...");
        List<AppInfo> projects = projectInfoDao.queryAll();
        for(AppInfo project:projects){
            if(project.getStatus()){
                projectsMap.put(project.getAppId(),project);
            }
        }
        log.info("load app datas from db end");
    }

    public AppInfo getProjectByAppId(String appId){
        return projectsMap.get(appId);
    }

    public boolean haveAppId(String appId){
        return projectsMap.containsKey(appId);
    }

    public Map<String, AppInfo> getProjectsMap() {
        return projectsMap;
    }

    public void setAppInfo(AppInfo info){
         String key = info.getAppId();
         if(!projectsMap.containsKey(key) && info.getStatus()){
             log.info("add new app info to sys");
             projectsMap.put(key,info);
         }else if(projectsMap.containsKey(key) && !info.equals(projectsMap.get(key))){
             if(info.getStatus()){
                 log.info("reset app info to sys");
                 projectsMap.put(key,info);
             } else{
                 log.info("delete app info to sys");
                 projectsMap.remove(key);
             }
         }
    }
}
展开阅读全文

没有更多推荐了,返回首页