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);
             }
         }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章