当前位置: 首页 > news >正文

京东的网站是哪家公司做的中山网站建设文化

京东的网站是哪家公司做的,中山网站建设文化,别墅庭院园林景观设计公司,50m专线做视频网站文章目录 sentinel持久化push推模式微服务端的实现具体实现源码分析读数据源写数据源的实现 微服务端解析读数据源流程 修改源码的实现官方demo修改源码实现配置类flowauthoritydegreadparamsystemgateway修改源码 测试补充 前置知识 pull模式 sentinel持久化push推模式 pull拉… 文章目录 sentinel持久化push推模式微服务端的实现具体实现源码分析读数据源写数据源的实现 微服务端解析读数据源流程 修改源码的实现官方demo修改源码实现配置类flowauthoritydegreadparamsystemgateway修改源码 测试补充 前置知识 pull模式 sentinel持久化push推模式 pull拉模式的缺点以保存本地文件举例 定时任务是每隔3s执行一次去判断规则持久化文件的最后修改时间。这里有一定时间的延迟但如果时间设置的太短有影响服务器的性能我们的微服务是集群部署的其他服务实例可读取不到我这台服务器的本地文件 所以还有一种push推送模式。我们一般会引入第三方中间件来实现以Nacos为例。我们修改了nacos中的配置它就会将更新后的数据推送给微服务。 push模式有两种实现方式 在微服务端添加读数据源为dataId添加监听器当规则配置文件更改之后我就获取到更改后的规则内存并更新内存中的数据再添加一个写数据源每当dashboard中更新了规则我除了更新内存中的数据之外我通过ConfigService.publishConfig()方法还往Nacos端进行写入 在dashboard源码中进行更改在获取规则内容、更新规则内容的接口中不要和微服务端进行交互直接去和Nacos通信通过ConfigService.publishConfig()和ConfigService.getConfig()来实现。这种方式主要注意dashboard端的规则实体对象和微服务端的规则实体对象不一致问题需要经过转换相关的操作。sentinel默认情况下就直接把规则实体转换为json字符串推送给NacosNacos配置文件更改了又推送给微服务微服务这边再把json字符串转换为规则实体对象这一步就会发现转换失败了某些属性对应不上。进而就导致了dashboard端设置的规则在微服务这边未生效。 微服务端的实现 具体实现 引入读数据源的依赖 dependencygroupIdcom.alibaba.csp/groupIdartifactIdsentinel-datasource-nacos/artifactId /dependency配置文件中添加规则持久化的dataId server:port: 8806spring:application:name: mall-user-sentinel-rule-push #微服务名称#配置nacos注册中心地址cloud:nacos:discovery:server-addr: 127.0.0.1:8848sentinel:transport:# 添加sentinel的控制台地址dashboard: 127.0.0.1:8080datasource:# 名称自定义可以随便定义字符串flow-rules:nacos:server-addr: 127.0.0.1:8848# dataId取了微服务名字后面再拼接字符串dataId: ${spring.application.name}-flow-rules# 我这里在Nacos配置中心单独使用了一个组groupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: flowdegrade-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-degrade-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: degradeparam-flow-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-param-flow-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: param-flowauthority-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-authority-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: authoritysystem-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-system-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: system在Nacos配置中心中创建对应的配置文件 编写java类定义写数据源 import com.alibaba.cloud.sentinel.SentinelProperties; import com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;/*** 添加往Nacos的写数据源只不过未使用InitFunc* 如果要使用就需要放开注解*/ Configuration(proxyBeanMethods false) AutoConfigureAfter(SentinelAutoConfiguration.class) public class SentinelNacosDataSourceConfiguration {BeanConditionalOnMissingBeanpublic SentinelNacosDataSourceHandler sentinelNacosDataSourceHandler(SentinelProperties sentinelProperties) {return new SentinelNacosDataSourceHandler(sentinelProperties);} }import com.alibaba.cloud.sentinel.SentinelProperties; import com.alibaba.cloud.sentinel.datasource.RuleType; import com.alibaba.cloud.sentinel.datasource.config.DataSourcePropertiesConfiguration; import com.alibaba.cloud.sentinel.datasource.config.NacosDataSourceProperties; import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler; import com.alibaba.csp.sentinel.datasource.WritableDataSource; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; import com.alibaba.csp.sentinel.slots.system.SystemRule; import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry; import com.alibaba.fastjson.JSON; import org.springframework.beans.factory.SmartInitializingSingleton;import java.util.List;/*** sentinel 规则持久化到 nacos配置中心*/ public class SentinelNacosDataSourceHandler implements SmartInitializingSingleton {private final SentinelProperties sentinelProperties;public SentinelNacosDataSourceHandler(SentinelProperties sentinelProperties) {this.sentinelProperties sentinelProperties;}Overridepublic void afterSingletonsInstantiated() {// 遍历我们配置文件中指定的多个spring.cloud.sentinel.datasource的多个配置sentinelProperties.getDatasource().values().forEach(this::registryWriter);}private void registryWriter(DataSourcePropertiesConfiguration dataSourceProperties) {// 只获取application.yml文件中 nacos配置的数据源final NacosDataSourceProperties nacosDataSourceProperties dataSourceProperties.getNacos();if (nacosDataSourceProperties null) {return;}// 获取规则类型然后根据各个类型创建相应的写数据源final RuleType ruleType nacosDataSourceProperties.getRuleType();switch (ruleType) {case FLOW:WritableDataSourceListFlowRule flowRuleWriter new NacosWritableDataSource(nacosDataSourceProperties, JSON::toJSONString);WritableDataSourceRegistry.registerFlowDataSource(flowRuleWriter);break;case DEGRADE:WritableDataSourceListDegradeRule degradeRuleWriter new NacosWritableDataSource(nacosDataSourceProperties, JSON::toJSONString);WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWriter);break;case PARAM_FLOW:WritableDataSourceListParamFlowRule paramFlowRuleWriter new NacosWritableDataSource(nacosDataSourceProperties, JSON::toJSONString);ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWriter);break;case SYSTEM:WritableDataSourceListSystemRule systemRuleWriter new NacosWritableDataSource(nacosDataSourceProperties, JSON::toJSONString);WritableDataSourceRegistry.registerSystemDataSource(systemRuleWriter);break;case AUTHORITY:WritableDataSourceListAuthorityRule authRuleWriter new NacosWritableDataSource(nacosDataSourceProperties, JSON::toJSONString);WritableDataSourceRegistry.registerAuthorityDataSource(authRuleWriter);break;default:break;}} }import com.alibaba.cloud.sentinel.datasource.config.NacosDataSourceProperties; import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.csp.sentinel.datasource.WritableDataSource; import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.PropertyKeyConst; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.exception.NacosException; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils;import java.util.Properties; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;/*** 将sentinel规则写入到nacos配置中心* param T*/ Slf4j public class NacosWritableDataSourceT implements WritableDataSourceT {private final ConverterT, String configEncoder;private final NacosDataSourceProperties nacosDataSourceProperties;private final Lock lock new ReentrantLock(true);private ConfigService configService null;public NacosWritableDataSource(NacosDataSourceProperties nacosDataSourceProperties, ConverterT, String configEncoder) {if (configEncoder null) {throw new IllegalArgumentException(Config encoder cannot be null);}if (nacosDataSourceProperties null) {throw new IllegalArgumentException(Config nacosDataSourceProperties cannot be null);}this.configEncoder configEncoder;this.nacosDataSourceProperties nacosDataSourceProperties;final Properties properties buildProperties(nacosDataSourceProperties);try {// 也可以直接注入NacosDataSource然后反射获取其configService属性this.configService NacosFactory.createConfigService(properties);} catch (NacosException e) {log.error(create configService failed., e);}}private Properties buildProperties(NacosDataSourceProperties nacosDataSourceProperties) {Properties properties new Properties();if (!StringUtils.isEmpty(nacosDataSourceProperties.getServerAddr())) {properties.setProperty(PropertyKeyConst.SERVER_ADDR, nacosDataSourceProperties.getServerAddr());} else {properties.setProperty(PropertyKeyConst.ACCESS_KEY, nacosDataSourceProperties.getAccessKey());properties.setProperty(PropertyKeyConst.SECRET_KEY, nacosDataSourceProperties.getSecretKey());properties.setProperty(PropertyKeyConst.ENDPOINT, nacosDataSourceProperties.getEndpoint());}if (!StringUtils.isEmpty(nacosDataSourceProperties.getNamespace())) {properties.setProperty(PropertyKeyConst.NAMESPACE, nacosDataSourceProperties.getNamespace());}if (!StringUtils.isEmpty(nacosDataSourceProperties.getUsername())) {properties.setProperty(PropertyKeyConst.USERNAME, nacosDataSourceProperties.getUsername());}if (!StringUtils.isEmpty(nacosDataSourceProperties.getPassword())) {properties.setProperty(PropertyKeyConst.PASSWORD, nacosDataSourceProperties.getPassword());}return properties;}Overridepublic void write(T value) throws Exception {lock.lock();// todo handle cluster concurrent problemtry {String convertResult configEncoder.convert(value);if (configService null) {log.error(configServer is null, can not continue.);return;}// 规则配置数据推送到nacos配置中心final boolean published configService.publishConfig(nacosDataSourceProperties.getDataId(), nacosDataSourceProperties.getGroupId(), convertResult);if (!published) {log.error(sentinel {} publish to nacos failed., nacosDataSourceProperties.getRuleType());}} finally {lock.unlock();}}Overridepublic void close() throws Exception {} }启动微服务进行测试。 dashboard中为某个接口定义一个流控规则 调用接口测试发送三次请求 查看Nacos中的配置文件就会发现也成功写入了 源码分析 读数据源 引入读数据源的依赖我们来看看具体是怎么实现的 dependencygroupIdcom.alibaba.csp/groupIdartifactIdsentinel-datasource-nacos/artifactId /dependency实现思路 和文件的读数据源一样继承了AbstractDataSource类这样就不需要我们再去写一遍加载配置、更新内存中的配置 在源码中的这个扩展包下面就有nacos读数据源的实现 我们先看看NacosDataSource类的父类的代码 创建一个DynamicSentinelProperty对象主要作用是更新内存中的规则配置加载配置、解析配置 public abstract class AbstractDataSourceS, T implements ReadableDataSourceS, T {protected final ConverterS, T parser;protected final SentinelPropertyT property;public AbstractDataSource(ConverterS, T parser) {if (parser null) {throw new IllegalArgumentException(parser cant be null);}// 子类传过来的解析器this.parser parser;// 更新内存中的配置// 我们会经常看见 getProperty().updateValue(newValue); 这样的代码this.property new DynamicSentinelPropertyT();}Overridepublic T loadConfig() throws Exception {// 调用子类的readSource()方法一般会得到一个String// 在通过解析器Converter 并解析配置转换成对应的对象return loadConfig(readSource());}public T loadConfig(S conf) throws Exception {// 解析配置T value parser.convert(conf);return value;}Overridepublic SentinelPropertyT getProperty() {return property;} }读配置源的具体实现: 通过Nacos的serverAddr构建一个Properties对象该对象会用于初始化ConfigService接口的对象利用线程池中唯一一个线程创建一个监听器监听dataId当配置中心的配置更改后就会调用微服务客户端微服务客户端这边有一个while阻塞队列实现的轮询机制它调用监听器的方法监听器里面会更新内存中的规则配置初始化configService对象并通过configService.addListener(…)为指定的dataId添加监听器微服务刚启动会调用父类的loadConfig()方法父类最终又会调用本类中的readSource()方法得到配置中心中的数据并进行解析再更新内存中的规则配置 public class NacosDataSourceT extends AbstractDataSourceString, T {private static final int DEFAULT_TIMEOUT 3000;// 创建一个只有一个线程的线程池用来执行dataId的监听器private final ExecutorService pool new ThreadPoolExecutor(...);private final Listener configListener;private final String groupId;private final String dataId;private final Properties properties;private ConfigService configService null;public NacosDataSource(final String serverAddr, final String groupId, final String dataId,ConverterString, T parser) {this(NacosDataSource.buildProperties(serverAddr), groupId, dataId, parser);}public NacosDataSource(final Properties properties, final String groupId, final String dataId,ConverterString, T parser) {super(parser);if (StringUtil.isBlank(groupId) || StringUtil.isBlank(dataId)) {throw new IllegalArgumentException(...);}AssertUtil.notNull(properties, Nacos properties must not be null, you could put some keys from PropertyKeyConst);this.groupId groupId;this.dataId dataId;this.properties properties;// 创建一个监听器this.configListener new Listener() {Overridepublic Executor getExecutor() {return pool;}Overridepublic void receiveConfigInfo(final String configInfo) {RecordLog.info(...);// 通过转换器进行转换T newValue NacosDataSource.this.parser.convert(configInfo);// 调用父类的SentinelProperty对象更新内存中的规则配置getProperty().updateValue(newValue);}};// 初始化configService对象并通过configService.addListener(..)为指定的dataId添加监听器initNacosListener();// 微服务刚启动会从Nacos配置中心加载一次配置loadInitialConfig();}private void loadInitialConfig() {try {// 调用父类的loadConfig() 父类最终又会调用本类中的readSource()方法得到配置中心中的数据并进行解析T newValue loadConfig();if (newValue null) {RecordLog.warn([NacosDataSource] WARN: initial config is null, you may have to check your data source);}// 调用父类的SentinelProperty对象更新内存中的规则配置getProperty().updateValue(newValue);} catch (Exception ex) {RecordLog.warn([NacosDataSource] Error when loading initial config, ex);}}private void initNacosListener() {try {// 初始化configService对象this.configService NacosFactory.createConfigService(this.properties);// Add config listener.// 通过configService.addListener(..)为指定的dataId添加监听器configService.addListener(dataId, groupId, configListener);} catch (Exception e) {RecordLog.warn([NacosDataSource] Error occurred when initializing Nacos data source, e);e.printStackTrace();}}Overridepublic String readSource() throws Exception {if (configService null) {throw new IllegalStateException(Nacos config service has not been initialized or error occurred);}// 通过ConfigService接口中的getConfig()方法从Nacos配置中心获取配置return configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT);}Overridepublic void close() {if (configService ! null) {configService.removeListener(dataId, groupId, configListener);}pool.shutdownNow();}private static Properties buildProperties(String serverAddr) {// 构建一个Properties对象该对象会在初始化ConfigService时会用上Properties properties new Properties();properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverAddr);return properties;} }写数据源的实现 写数据源源码实现流程相对简单。我们知道dashboard更新配置后调用微服务端微服务这边的ModifyRulesCommandHandler类会处理规则更改的请求。这里会有一个写数据源相关的操作 // 注意name setRules这就是控制台请求服务端的url路径 CommandMapping(name setRules, desc modify the rules, accept param: type{ruleType}data{ruleJson}) public class ModifyRulesCommandHandler implements CommandHandlerString {public CommandResponseString handle(CommandRequest request) {//......// 处理流控规则if (FLOW_RULE_TYPE.equalsIgnoreCase(type)) {ListFlowRule flowRules JSONArray.parseArray(data, FlowRule.class);FlowRuleManager.loadRules(flowRules);// 关键一步这里会有一个写数据源的操作。默认情况下是没有WritableDataSource我们可以在这里进行扩展if (!writeToDataSource(getFlowDataSource(), flowRules)) {result WRITE_DS_FAILURE_MSG;}return CommandResponse.ofSuccess(result);// 处理权限规则} else if (AUTHORITY_RULE_TYPE.equalsIgnoreCase(type)) {...// 处理熔断规则} else if (DEGRADE_RULE_TYPE.equalsIgnoreCase(type)) {...// 处理系统规则} else if (SYSTEM_RULE_TYPE.equalsIgnoreCase(type)) {...}return CommandResponse.ofFailure(new IllegalArgumentException(invalid type));} }所以我们要做的事情就是创建一个写数据源并进行注册写数据源WritableDataSourceRegistry。我们先来看看源码中的Demo通过读写文件的方式实现的读写数据源。 public void init() throws Exception {// 文件保存路径String flowRuleDir System.getProperty(user.home) File.separator sentinel File.separator rules;String flowRuleFile flowRule.json;String flowRulePath flowRuleDir File.separator flowRuleFile;// 添加读数据源ReadableDataSourceString, ListFlowRule ds new FileRefreshableDataSource(flowRulePath, source - JSON.parseObject(source, new TypeReferenceListFlowRule() {}));FlowRuleManager.register2Property(ds.getProperty());// 添加写数据源WritableDataSourceListFlowRule wds new FileWritableDataSource(flowRulePath, this::encodeJson);WritableDataSourceRegistry.registerFlowDataSource(wds); }我在定义一个往Nacos的写数据源一个简单的实现具体项目中能用的请参考上面 具体实现一章 。这里只是用更少的代码来理解nacos的写数据源 import com.alibaba.csp.sentinel.datasource.WritableDataSource; import com.alibaba.csp.sentinel.init.InitFunc; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry; import com.alibaba.fastjson.JSON;import java.util.List;public class NacosDataSourceInitFunc implements InitFunc {Overridepublic void init() throws Exception {//流控规则WritableDataSourceListFlowRule writableDataSource new NacosWritableDataSource(127.0.0.1:8848, DEFAULT_GROUP, mall-user-sentinel-rule-push-demo-flow, JSON::toJSONString);WritableDataSourceRegistry.registerFlowDataSource(writableDataSource);} }import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.csp.sentinel.datasource.WritableDataSource; import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.PropertyKeyConst; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigType; import com.alibaba.nacos.api.exception.NacosException;import java.util.Properties; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class NacosWritableDataSourceT implements WritableDataSourceT {private final String serverAddr;private final String groupId;private final String dataId;private final Properties properties;private ConfigService configService;private final ConverterT, String configEncoder;private final Lock lock new ReentrantLock(true);public NacosWritableDataSource(String serverAddr, String groupId, String dataId, ConverterT, String configEncoder) {this.serverAddr serverAddr;this.groupId groupId;this.dataId dataId;// 通过serverAddr构建一个properties对象this.properties NacosWritableDataSource.buildProperties(serverAddr);this.configEncoder configEncoder;initConfigService();}private void initConfigService() {try {// 通过properties对象初始化ConfigServicethis.configService NacosFactory.createConfigService(properties);} catch (NacosException e) {e.printStackTrace();}}private static Properties buildProperties(String serverAddr) {Properties properties new Properties();properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverAddr);return properties;}Overridepublic void write(T t) throws Exception {lock.lock();try {// 通过ConfigService往Nacos配置中心写入数据configService.publishConfig(dataId, groupId, this.configEncoder.convert(t), ConfigType.JSON.getType());} finally {lock.unlock();}}Overridepublic void close() throws Exception {}}微服务端解析读数据源流程 我们引入了下面的依赖 dependencygroupIdcom.alibaba.csp/groupIdartifactIdsentinel-datasource-nacos/artifactId /dependency并在配置文件中指定了多个读数据源。这些数据源是如何创建的嘞 server:port: 8806spring:application:name: mall-user-sentinel-rule-push #微服务名称#配置nacos注册中心地址cloud:nacos:discovery:server-addr: 127.0.0.1:8848sentinel:transport:# 添加sentinel的控制台地址dashboard: 127.0.0.1:8080datasource:# 名称自定义可以随便定义字符串# 每一个都是一个读数据源flow-rules:nacos:server-addr: 127.0.0.1:8848# dataId取了微服务名字后面再拼接字符串dataId: ${spring.application.name}-flow-rules# 我这里在Nacos配置中心单独使用了一个组groupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: flow# 读数据源degrade-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-degrade-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: degradeparam-flow-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-param-flow-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: param-flowauthority-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-authority-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: authoritysystem-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-system-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: system源码的入口是SentinelDataSourceHandler类它实现了SmartInitializingSingleton接口这是Spring中的接口所有非懒加载单例bean创建完成之后会调用这个接口的实现类 在构造函数中依赖注入SentinelProperties对象该对象中保存了我们配置文件中所有读数据源的配置遍历SentinelProperties对象中的读数据源并为每一个读数据源生成一个beanName为每一个读数据源对象 beanName 创建一个BeanDefinition将BeanDefinition添加进BeanFactory中BeanFactory.getBean(beanName) 创建读数据源对象。该对象其实是FactoryBean类型的上方的getBean()方法最终会调用至NacosDataSourceFactoryBean.getObject()方法在这里创建NacosDataSource对象。该对象就是上方引入maven依赖中的读数据源对象。 public class SentinelDataSourceHandler implements SmartInitializingSingleton {//......// SentinelProperties中保存着MapString, DataSourcePropertiesConfiguration datasource// 也就是我们上方yml文件中定义的多个数据源我们自定义的名字就是Stringprivate final SentinelProperties sentinelProperties;// 构造方法中进行依赖注入 sentinelProperties对象public SentinelDataSourceHandler(DefaultListableBeanFactory beanFactory,SentinelProperties sentinelProperties,...) {//...this.sentinelProperties sentinelProperties;}// 遍历MapString, DataSourcePropertiesConfiguration集合最终取出我们的每一个配置的数据源Overridepublic void afterSingletonsInstantiated() {sentinelProperties.getDatasource().forEach((dataSourceName, dataSourceProperties) - {try {ListString validFields dataSourceProperties.getValidField();// ...// AbstractDataSourceProperties就是我们在配置文件中具体的每一个配置对象的公共父类AbstractDataSourceProperties abstractDataSourceProperties dataSourceProperties.getValidDataSourceProperties();abstractDataSourceProperties.setEnv(env);abstractDataSourceProperties.preCheck(dataSourceName);// 把我们配置的每一个数据源还有这里字符串凭借的一个beanName。调用下面的registerBean()方法// beanName为 flow-rules -sentinel- nacos -datasource// flow-rules是我们在yml文件中自定义的名字nacos就是下面的validFields.get(0)值registerBean(abstractDataSourceProperties, dataSourceName -sentinel- validFields.get(0) -datasource);}catch (Exception e) {log.error(...);}});}private void registerBean(final AbstractDataSourceProperties dataSourceProperties,String dataSourceName) {// 对我们的数据源生成一个BeanDefinitionBeanDefinitionBuilder builder parseBeanDefinition(dataSourceProperties,dataSourceName);// 将BeanDefinition添加进BeanFactory中this.beanFactory.registerBeanDefinition(dataSourceName,builder.getBeanDefinition());// 通过beanFactory.getBean(dataSourceName)方法创建bean对象// 我们配置文件中定义的每一个读数据源就变为了一个一个的bean// 注意我们的读数据源它是一个FactoryBean这里的getBean()方法最终会去到NacosDataSourceFactoryBean.getObject()AbstractDataSource newDataSource (AbstractDataSource) this.beanFactory.getBean(dataSourceName);// 将读数据源添加进对应的规则管理器中dataSourceProperties.postRegister(newDataSource);} public class NacosDataSourceFactoryBean implements FactoryBeanNacosDataSource {//......Overridepublic NacosDataSource getObject() throws Exception {// 为properties对象赋值Properties properties new Properties();if (!StringUtils.isEmpty(this.serverAddr)) {properties.setProperty(PropertyKeyConst.SERVER_ADDR, this.serverAddr);}else {properties.setProperty(PropertyKeyConst.ENDPOINT, this.endpoint);}if (!StringUtils.isEmpty(this.contextPath)) {properties.setProperty(PropertyKeyConst.CONTEXT_PATH, this.contextPath);}if (!StringUtils.isEmpty(this.accessKey)) {properties.setProperty(PropertyKeyConst.ACCESS_KEY, this.accessKey);}if (!StringUtils.isEmpty(this.secretKey)) {properties.setProperty(PropertyKeyConst.SECRET_KEY, this.secretKey);}if (!StringUtils.isEmpty(this.namespace)) {properties.setProperty(PropertyKeyConst.NAMESPACE, this.namespace);}if (!StringUtils.isEmpty(this.username)) {properties.setProperty(PropertyKeyConst.USERNAME, this.username);}if (!StringUtils.isEmpty(this.password)) {properties.setProperty(PropertyKeyConst.PASSWORD, this.password);}// 创建一个Nacos读数据源对象这里也就是上方源码分析 —— 读数据源 的那一个对象return new NacosDataSource(properties, groupId, dataId, converter);}// ...... }修改源码的实现 我们需要在Sentinel源码中进行修改将dashboard和微服务之间的通信改为dashboard和nacos的通信。在通过Nacos配置中心的推送机制去更新微服务内存中的规则配置。 从 Sentinel 1.4.0 开始Sentinel 控制台提供 DynamicRulePublisher 和 DynamicRuleProvider 接口用于实现应用维度的规则推送和拉取 DynamicRuleProvider: 拉取规则 DynamicRulePublisher: 推送规则 在dashboard工程下的com.alibaba.csp.sentinel.dashboard.rule包下创建nacos包然后把各种场景的配置规则拉取和推送的实现类写到此包下 可以参考Sentinel Dashboard test包下的流控规则拉取和推送的实现逻辑 官方demo 我们看看官方的demo是如何实现的 首先创建一个NacosConfigUtil类用来定义常量 public final class NacosConfigUtil {// 其实demo中也就用到了上面两个常量// 定义配置中心的分组名这里需要和微服务端进行配对不然dashboard推送一个分组微服务结果从另一个分组去读取配置public static final String GROUP_ID SENTINEL_GROUP;// 定义配置文件dataId的一个后缀一般命名就是 serviceName 后缀。当然dataId也要和微服务那边读取配置保存一样// 避免你写一个dataId微服务从另一个dataId去读public static final String FLOW_DATA_ID_POSTFIX -flow-rules;public static final String PARAM_FLOW_DATA_ID_POSTFIX -param-rules;public static final String CLUSTER_MAP_DATA_ID_POSTFIX -cluster-map;public static final String CLIENT_CONFIG_DATA_ID_POSTFIX -cc-config;public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX -cs-transport-config;public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX -cs-flow-config;public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX -cs-namespace-set;private NacosConfigUtil() {} }创建一个NacosConfig配置类这里就定义了流控规则相关的转换器 Configuration public class NacosConfig {// 流控规则相关 定义 ListFlowRuleEntity 到 String的转换器Beanpublic ConverterListFlowRuleEntity, String flowRuleEntityEncoder() {return JSON::toJSONString;}// 流控规则相关 定义 String 到 ListFlowRuleEntity的转换器Beanpublic ConverterString, ListFlowRuleEntity flowRuleEntityDecoder() {return s - JSON.parseArray(s, FlowRuleEntity.class);}// 根据一个Nacos的serverAddr创建ConfigService对象。推送配置/拉取配置都是通过该对象来完成的Beanpublic ConfigService nacosConfigService() throws Exception {return ConfigFactory.createConfigService(localhost);} }接下来我们来看看dashboard推送规则配置的实现代码它实现了DynamicRulePublisher接口 Component(flowRuleNacosPublisher) public class FlowRuleNacosPublisher implements DynamicRulePublisherListFlowRuleEntity {// 注入上面配置类的中定义的ConfigService和Converter转换器Autowiredprivate ConfigService configService;Autowiredprivate ConverterListFlowRuleEntity, String converter;Overridepublic void publish(String app, ListFlowRuleEntity rules) throws Exception {AssertUtil.notEmpty(app, app name cannot be empty);if (rules null) {return;}// 调用Nacos的configService.publishConfig(..)方法 推送配置// dataId为 appName 最上方的常量文件后缀-flow-rules 分组为最上方定义的常量SENTINEL_GROUP 并对规则配置集合转换为json字符串configService.publishConfig(app NacosConfigUtil.FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, converter.convert(rules));} }接下来我们来看看dashboard拉取规则配置的实现代码它实现了DynamicRuleProvider接口 Component(flowRuleNacosProvider) public class FlowRuleNacosProvider implements DynamicRuleProviderListFlowRuleEntity {// 注入上面配置类的中定义的ConfigService和Converter转换器Autowiredprivate ConfigService configService;Autowiredprivate ConverterString, ListFlowRuleEntity converter;Overridepublic ListFlowRuleEntity getRules(String appName) throws Exception {// 调用Nacos的configService.getConfig(dataId, group, timeoutMs)方法 拉取配置String rules configService.getConfig(appName NacosConfigUtil.FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, 3000);if (StringUtil.isEmpty(rules)) {return new ArrayList();}// 将json字符串转换为 ListFlowRuleEntity 规则实体对象集合return converter.convert(rules);} }官方Demo这种方式功能上的确是实现了与Nacos通信对Nacos配置中心进行读写。但存在一个小问题。那就是dashboard这边规则实体对象是FlowRuleEntity但是微服务端规则实体对象是FlowRule。Nacos把配置推送给微服务端时微服务端把json字符串转换为实体对象时可能就会出现不匹配的情况 — 微服务规则实体对象没有相应的值 ---- 内存中的规则也就不完善 ---- 出现了dashboard端更新的规则微服务端未生效情况。 当然流控规则都还好如下图所示这两个之间的实体对象成员属性基本上都能对应上 但热点规则这边的实体就不行了他们之间的层级关系就不同了 public class ParamFlowRuleEntity extends AbstractRuleEntityParamFlowRule {public ParamFlowRuleEntity() {}// ParamFlowRule为客户端的规则实体但是这里将一整个实体对象变为了ParamFlowRuleEntity的其中一个属性// 所以这里转json之后的层级关系就发生了改变public ParamFlowRuleEntity(ParamFlowRule rule) {AssertUtil.notNull(rule, Authority rule should not be null);// 父类中的属性this.rule rule;}... }// 父类 public abstract class AbstractRuleEntityT extends AbstractRule implements RuleEntity {protected Long id;protected String app;protected String ip;protected Integer port;// ParamFlowRule为客户端的规则实体成为了ParamFlowRuleEntity实体的一个成员属性protected T rule;private Date gmtCreate;private Date gmtModified;... }为了解决这种情况那么就需要定义一个规范存入Nacos配置中心的数据只能是微服务那边的规则实体对象不能是dashboard这边的规则实体对象 修改源码实现 naocs配置中心保存的是微服务端的规则实体对象 各个规则都先在dashboard端将规则实体转换为微服务能用的规则实体在推送至Nacos配置中心 从Nacos配置中心获取配置后都先将json字符串转换为dashboard端的规则实体对象 项目结构如下 配置类 import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.RuleEntity; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.fastjson.JSON; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.exception.NacosException;import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors;public final class NacosConfigUtil {// 定义配置中心的分组名这里需要和微服务端进行配对不然dashboard推送一个分组微服务结果从另一个分组去读取配置public static final String GROUP_ID SENTINEL_GROUP;// 定义配置文件dataId的一个后缀一般命名就是 serviceName 后缀。当然dataId也要和微服务那边读取配置保存一样// 避免你写一个dataId微服务从另一个dataId去读public static final String FLOW_DATA_ID_POSTFIX -flow-rules;public static final String PARAM_FLOW_DATA_ID_POSTFIX -param-flow-rules;public static final String DEGRADE_DATA_ID_POSTFIX -degrade-rules;public static final String SYSTEM_DATA_ID_POSTFIX -system-rules;public static final String AUTHORITY_DATA_ID_POSTFIX -authority-rules;public static final String GATEWAY_FLOW_DATA_ID_POSTFIX -gateway-flow-rules;public static final String GATEWAY_API_DATA_ID_POSTFIX -gateway-api-rules;public static final String CLUSTER_MAP_DATA_ID_POSTFIX -cluster-map;/*** cc for cluster-client*/public static final String CLIENT_CONFIG_DATA_ID_POSTFIX -cc-config;/*** cs for cluster-server*/public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX -cs-transport-config;public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX -cs-flow-config;public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX -cs-namespace-set;//超时时间public static final int READ_TIMEOUT 3000;private NacosConfigUtil() {}/*** RuleEntity-----Rule* 控制台这边的规则实体都是RuleEntity类型的这里就调用各个规则实体对象中的toRule()方法转换为微服务端的规则实体对象* 例如 FlowRuleEntity#toRule ---- FlowRule ParamFlowRuleEntity#toRule ---- ParamFlowRule* param entities* return*/public static String convertToRule(List? extends RuleEntity entities){return JSON.toJSONString(entities.stream().map(r - r.toRule()).collect(Collectors.toList()));}/*** ApiDefinitionEntity-----ApiDefinition* param entities* return*/public static String convertToApiDefinition(List? extends ApiDefinitionEntity entities){return JSON.toJSONString(entities.stream().map(r - r.toApiDefinition()).collect(Collectors.toList()));}/*** GatewayFlowRuleEntity-----GatewayFlowRule* param entities* return*/public static String convertToGatewayFlowRule(List? extends GatewayFlowRuleEntity entities){return JSON.toJSONString(entities.stream().map(r - r.toGatewayFlowRule()).collect(Collectors.toList()));}}通过Nacos配置中心的地址创建对应的ConfigService对象并存入Spring容器中 Configuration public class NacosConfig {Value(${sentinel.nacos.config.serverAddr})private String serverAddrlocalhost:8848;Beanpublic ConfigService nacosConfigService() throws Exception {return ConfigFactory.createConfigService(serverAddr);} /*对于Nacos开启了认证那么就需要添加Naocs的用户名和密码了Beanpublic ConfigService nacosConfigService() throws Exception {Properties properties new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);properties.put(PropertyKeyConst.USERNAME, nacos);properties.put(PropertyKeyConst.PASSWORD, nacos);return ConfigFactory.createConfigService(properties);}*/ }flow 拉取配置实现DynamicRuleProvider接口 Component(flowRuleNacosProvider) public class FlowRuleNacosProvider implements DynamicRuleProviderListFlowRuleEntity {// 注入我们上面创建的ConfigService对象Autowiredprivate ConfigService configService;Overridepublic ListFlowRuleEntity getRules(String appName,String ip,Integer port) throws NacosException {// 从Nacos配置中心拉取配置String rules configService.getConfig(appName NacosConfigUtil.FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.READ_TIMEOUT);if (StringUtil.isEmpty(rules)) {return new ArrayList();}// 解析json获取到 ListFlowRuleListFlowRule list JSON.parseArray(rules, FlowRule.class);// 通过FlowRuleEntity.fromFlowRule(..) 方法实现 FlowRule-------FlowRuleEntityreturn list.stream().map(rule -FlowRuleEntity.fromFlowRule(appName,ip,port,rule)).collect(Collectors.toList());} }/*FlowRuleEntity.fromFlowRule(..) 方法如下所示Sentinel的dashboard端的规则实体对象内其实都自己写了对应的fromFlowRule()方法public static FlowRuleEntity fromFlowRule(String app, String ip, Integer port, FlowRule rule) {FlowRuleEntity entity new FlowRuleEntity();entity.setApp(app);entity.setIp(ip);entity.setPort(port);entity.setLimitApp(rule.getLimitApp());entity.setResource(rule.getResource());entity.setGrade(rule.getGrade());entity.setCount(rule.getCount());entity.setStrategy(rule.getStrategy());entity.setRefResource(rule.getRefResource());entity.setControlBehavior(rule.getControlBehavior());entity.setWarmUpPeriodSec(rule.getWarmUpPeriodSec());entity.setMaxQueueingTimeMs(rule.getMaxQueueingTimeMs());entity.setClusterMode(rule.isClusterMode());entity.setClusterConfig(rule.getClusterConfig());return entity; }*/推送配置实现DynamicRulePublisher接口 Component(flowRuleNacosPublisher) public class FlowRuleNacosPublisher implements DynamicRulePublisherListFlowRuleEntity {// 注入我们上面创建的ConfigService对象Autowiredprivate ConfigService configService;Overridepublic void publish(String app, ListFlowRuleEntity rules) throws Exception {AssertUtil.notEmpty(app, app name cannot be empty);if (rules null) {return;}//发布配置到Nacos配置中心这里会调用我们工具类中编写的方法NacosConfigUtil.convertToRule(rules)configService.publishConfig(app NacosConfigUtil.FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.convertToRule(rules));} }authority Component(authorityRuleNacosProvider) public class AuthorityRuleNacosProvider implements DynamicRuleProviderListAuthorityRuleEntity {Autowiredprivate ConfigService configService;Overridepublic ListAuthorityRuleEntity getRules(String appName,String ip,Integer port) throws Exception {String rules configService.getConfig(appName NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.READ_TIMEOUT);if (StringUtil.isEmpty(rules)) {return new ArrayList();}ListAuthorityRule list JSON.parseArray(rules, AuthorityRule.class);return list.stream().map(rule -AuthorityRuleEntity.fromAuthorityRule(appName, ip, port, rule)).collect(Collectors.toList());}}Component(authorityRuleNacosPublisher) public class AuthorityRuleNacosPublisher implements DynamicRulePublisherListAuthorityRuleEntity {Autowiredprivate ConfigService configService;Overridepublic void publish(String app, ListAuthorityRuleEntity rules) throws Exception {AssertUtil.notEmpty(app, app name cannot be empty);if (rules null) {return;}configService.publishConfig(app NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.convertToRule(rules));} }degread Component(degradeRuleNacosProvider) public class DegradeRuleNacosProvider implements DynamicRuleProviderListDegradeRuleEntity {Autowiredprivate ConfigService configService;Overridepublic ListDegradeRuleEntity getRules(String appName,String ip,Integer port) throws Exception {String rules configService.getConfig(appName NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.READ_TIMEOUT);if (StringUtil.isEmpty(rules)) {return new ArrayList();}ListDegradeRule list JSON.parseArray(rules, DegradeRule.class);return list.stream().map(rule -DegradeRuleEntity.fromDegradeRule(appName, ip, port, rule)).collect(Collectors.toList());} }Component(degradeRuleNacosPublisher) public class DegradeRuleNacosPublisher implements DynamicRulePublisherListDegradeRuleEntity {Autowiredprivate ConfigService configService;Overridepublic void publish(String app, ListDegradeRuleEntity rules) throws Exception {AssertUtil.notEmpty(app, app name cannot be empty);if (rules null) {return;}configService.publishConfig(app NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.convertToRule(rules));} }param Component(paramFlowRuleNacosProvider) public class ParamFlowRuleNacosProvider implements DynamicRuleProviderListParamFlowRuleEntity {Autowiredprivate ConfigService configService;Overridepublic ListParamFlowRuleEntity getRules(String appName,String ip,Integer port) throws Exception {String rules configService.getConfig(appName NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.READ_TIMEOUT);if (StringUtil.isEmpty(rules)) {return new ArrayList();}ListParamFlowRule list JSON.parseArray(rules, ParamFlowRule.class);return list.stream().map(rule -ParamFlowRuleEntity.fromParamFlowRule(appName, ip, port, rule)).collect(Collectors.toList());} }Component(paramFlowRuleNacosPublisher) public class ParamFlowRuleNacosPublisher implements DynamicRulePublisherListParamFlowRuleEntity {Autowiredprivate ConfigService configService;Overridepublic void publish(String app, ListParamFlowRuleEntity rules) throws Exception {AssertUtil.notEmpty(app, app name cannot be empty);if (rules null) {return;}configService.publishConfig(app NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.convertToRule(rules));} }system Component(systemRuleNacosProvider) public class SystemRuleNacosProvider implements DynamicRuleProviderListSystemRuleEntity {Autowiredprivate ConfigService configService;Overridepublic ListSystemRuleEntity getRules(String appName,String ip,Integer port) throws Exception {String rules configService.getConfig(appName NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.READ_TIMEOUT);if (StringUtil.isEmpty(rules)) {return new ArrayList();}ListSystemRule list JSON.parseArray(rules, SystemRule.class);return list.stream().map(rule -SystemRuleEntity.fromSystemRule(appName, ip, port, rule)).collect(Collectors.toList());}}Component(systemRuleNacosPublisher) public class SystemRuleNacosPublisher implements DynamicRulePublisherListSystemRuleEntity {Autowiredprivate ConfigService configService;Overridepublic void publish(String app, ListSystemRuleEntity rules) throws Exception {AssertUtil.notEmpty(app, app name cannot be empty);if (rules null) {return;}configService.publishConfig(app NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.convertToRule(rules));} }gateway public class ApiDefinition2 {private String apiName;private SetApiPathPredicateItem predicateItems;public ApiDefinition2() {}public String getApiName() {return apiName;}public void setApiName(String apiName) {this.apiName apiName;}public SetApiPathPredicateItem getPredicateItems() {return predicateItems;}public void setPredicateItems(SetApiPathPredicateItem predicateItems) {this.predicateItems predicateItems;}Overridepublic String toString() {return ApiDefinition2{ apiName apiName \ , predicateItems predicateItems };}public ApiDefinition toApiDefinition() {ApiDefinition apiDefinition new ApiDefinition();apiDefinition.setApiName(apiName);SetApiPredicateItem apiPredicateItems new LinkedHashSet();apiDefinition.setPredicateItems(apiPredicateItems);if (predicateItems ! null) {for (ApiPathPredicateItem predicateItem : predicateItems) {apiPredicateItems.add(predicateItem);}}return apiDefinition;}}Component(gatewayApiRuleNacosProvider) public class GatewayApiRuleNacosProvider implements DynamicRuleProviderListApiDefinitionEntity {Autowiredprivate ConfigService configService;Overridepublic ListApiDefinitionEntity getRules(String appName,String ip,Integer port) throws Exception {String rules configService.getConfig(appName NacosConfigUtil.GATEWAY_API_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.READ_TIMEOUT);if (StringUtil.isEmpty(rules)) {return new ArrayList();}// 注意 ApiDefinition的属性SetApiPredicateItem predicateItems中元素 是接口类型JSON解析丢失数据// 重写实体类ApiDefinition2,再转换为ApiDefinitionListApiDefinition2 list JSON.parseArray(rules, ApiDefinition2.class);return list.stream().map(rule -ApiDefinitionEntity.fromApiDefinition(appName, ip, port, rule.toApiDefinition())).collect(Collectors.toList());}public static void main(String[] args) {String rules [{\apiName\:\/pms/productInfo/${id}\,\predicateItems\:[{\matchStrategy\:1,\pattern\:\/pms/productInfo/\}]}];ListApiDefinition list JSON.parseArray(rules, ApiDefinition.class);System.out.println(list);ListApiDefinition2 list2 JSON.parseArray(rules, ApiDefinition2.class);System.out.println(list2);System.out.println(list2.get(0).toApiDefinition());}}Component(gatewayApiRuleNacosPublisher) public class GatewayApiRuleNacosPublisher implements DynamicRulePublisherListApiDefinitionEntity {Autowiredprivate ConfigService configService;Overridepublic void publish(String app, ListApiDefinitionEntity rules) throws Exception {AssertUtil.notEmpty(app, app name cannot be empty);if (rules null) {return;}configService.publishConfig(app NacosConfigUtil.GATEWAY_API_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.convertToApiDefinition(rules));} }Component(gatewayFlowRuleNacosProvider) public class GatewayFlowRuleNacosProvider implements DynamicRuleProviderListGatewayFlowRuleEntity {Autowiredprivate ConfigService configService;Overridepublic ListGatewayFlowRuleEntity getRules(String appName,String ip,Integer port) throws Exception {String rules configService.getConfig(appName NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.READ_TIMEOUT);if (StringUtil.isEmpty(rules)) {return new ArrayList();}ListGatewayFlowRule list JSON.parseArray(rules, GatewayFlowRule.class);return list.stream().map(rule -GatewayFlowRuleEntity.fromGatewayFlowRule(appName, ip, port, rule)).collect(Collectors.toList());} }Component(gatewayFlowRuleNacosPublisher) public class GatewayFlowRuleNacosPublisher implements DynamicRulePublisherListGatewayFlowRuleEntity {Autowiredprivate ConfigService configService;Overridepublic void publish(String app, ListGatewayFlowRuleEntity rules) throws Exception {AssertUtil.notEmpty(app, app name cannot be empty);if (rules null) {return;}configService.publishConfig(app NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, NacosConfigUtil.convertToGatewayFlowRule(rules));} }修改源码 我们现在需要在controller层将原本dashboard从微服务获取规则配置、dashboard更新规则后调用微服务这一过程改为Nacos。 以流控规则举例在FlowControllerV1层中注入我们写的类 /** 从远程配置中心拉取规则*/ Autowired Qualifier(flowRuleNacosProvider) private DynamicRuleProviderListFlowRuleEntity ruleProvider;/** 推送规则到远程配置中心*/ Autowired Qualifier(flowRuleNacosPublisher) private DynamicRulePublisherListFlowRuleEntity rulePublisher;原本dashboard从微服务获取规则配置改为通过flowRuleNacosProvider从Nacos拉取配置 GetMapping(/rules) AuthAction(PrivilegeType.READ_RULE) public ResultListFlowRuleEntity apiQueryMachineRules(RequestParam String app,RequestParam String ip,RequestParam Integer port) {if (StringUtil.isEmpty(app)) {return Result.ofFail(-1, app cant be null or empty);}if (StringUtil.isEmpty(ip)) {return Result.ofFail(-1, ip cant be null or empty);}if (port null) {return Result.ofFail(-1, port cant be null);}try {//从客户端内存获取规则配置//ListFlowRuleEntity rules sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port);//从远程配置中心获取规则配置ListFlowRuleEntity rules ruleProvider.getRules(app,ip,port);if (rules ! null !rules.isEmpty()) {for (FlowRuleEntity entity : rules) {entity.setApp(app);if (entity.getClusterConfig() ! null entity.getClusterConfig().getFlowId() ! null) {entity.setId(entity.getClusterConfig().getFlowId());}}}rules repository.saveAll(rules);return Result.ofSuccess(rules);} catch (Throwable throwable) {logger.error(Error when querying flow rules, throwable);return Result.ofThrowable(-1, throwable);} }规则更改后推送至Nacos PostMapping(/rule) AuthAction(PrivilegeType.WRITE_RULE) public ResultFlowRuleEntity apiAddFlowRule(RequestBody FlowRuleEntity entity) {ResultFlowRuleEntity checkResult checkEntityInternal(entity);if (checkResult ! null) {return checkResult;}entity.setId(null);Date date new Date();entity.setGmtCreate(date);entity.setGmtModified(date);entity.setLimitApp(entity.getLimitApp().trim());entity.setResource(entity.getResource().trim());try {// 规则写入dashboard的内存中会写入三个map中entity repository.save(entity);//发布规则到客户端内存中//publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get(5000, TimeUnit.MILLISECONDS);//发布规则到远程配置中心publishRules(entity.getApp());return Result.ofSuccess(entity);} catch (Throwable t) {Throwable e t instanceof ExecutionException ? t.getCause() : t;logger.error(Failed to add new flow rule, app{}, ip{}, entity.getApp(), entity.getIp(), e);return Result.ofFail(-1, e.getMessage());} }/** * 发布规则到远程配置中心 * param app * throws Exception */ private void publishRules(/*NonNull*/ String app) throws Exception {// 从三个Map中的其中一个获取规则实体集合ListFlowRuleEntity rules repository.findAllByApp(app);// 推送NacosrulePublisher.publish(app, rules); }在配置文件中指定NacosConfig的地址因为在最上方的配置类中使用到了该配置项 #接入nacos配置中心用于规则数据持久化 sentinel.nacos.config.serverAddrlocalhost:8848测试 微服务端引入Nacos的读数据源 还是需要它监听dataId的更改并更新内存中的规则数据 dependencygroupIdcom.alibaba.csp/groupIdartifactIdsentinel-datasource-nacos/artifactId /dependency配置文件中添加相应的配置 server:port: 8806spring:application:name: mall-user-sentinel-rule-push #微服务名称#配置nacos注册中心地址cloud:nacos:discovery:server-addr: 127.0.0.1:8848sentinel:transport:# 添加sentinel的控制台地址dashboard: 127.0.0.1:8080datasource:# 名称自定义可以随便定义字符串flow-rules:nacos:server-addr: 127.0.0.1:8848# dataId取了微服务名字后面再拼接字符串# 注意需要和配置类中常量定义的一致dataId: ${spring.application.name}-flow-rules# 这里的组名需要和配置类中常量定义的一致groupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: flowdegrade-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-degrade-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: degradeparam-flow-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-param-flow-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: param-flowauthority-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-authority-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: authoritysystem-rules:nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-system-rulesgroupId: SENTINEL_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: system在Sentinel中进行了两个限流规则的配置 Naocs的配置中心也有相应的更改 微服务中也会生效 补充 如果在工作中sentinel的持久化这一块已经被其他项目组的人完成了但他们是直接把dashboard端的规则实体转json存入了Nacos配置中心。进而导致了热点参数规则不生效并且不允许我们修改源码。 当出现了上面这种情况那我们应该怎么处理嘞 解决方案 自定义一个解析热点规则配置的解析器FlowParamJsonConverter继承JsonConverter重写convert方法。 利用BeanPostProcessor机制替换beanName为param-flow-rules-sentinel-nacos-datasource的converter属性注入FlowParamJsonConverter。 Configuration public class ConverterConfig {Bean(sentinel-json-param-flow-converter2)Primarypublic JsonConverter jsonParamFlowConverter() {return new FlowParamJsonConverter(new ObjectMapper(), ParamFlowRule.class);} }Component public class FlowParamConverterBeanPostProcessor implements BeanPostProcessor {Autowiredprivate JsonConverter jsonParamFlowConverter;Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals(param-flow-rules-sentinel-nacos-datasource)) {NacosDataSourceFactoryBean nacosDataSourceFactoryBean (NacosDataSourceFactoryBean) bean;nacosDataSourceFactoryBean.setConverter(jsonParamFlowConverter);return bean;}return bean;} }public class FlowParamJsonConverter extends JsonConverter {Class ruleClass;public FlowParamJsonConverter(ObjectMapper objectMapper, Class ruleClass) {super(objectMapper, ruleClass);this.ruleClass ruleClass;}Overridepublic CollectionObject convert(String source) {ListObject list new ArrayList();JSONArray jsonArray JSON.parseArray(source);for (int i 0; i jsonArray.size(); i) {//解析rule属性JSONObject jsonObject (JSONObject) jsonArray.getJSONObject(i).get(rule);Object object JSON.toJavaObject(jsonObject, ruleClass);list.add(object);}return list;} }
http://www.w-s-a.com/news/223482/

相关文章:

  • 企业网站建设选题的依据及意义校园网站建设的论文
  • 网站版面设计方案水电维修在哪个网站上做推广好些
  • 邹平建设局官方网站企业宣传片广告公司
  • 南京建设集团网站建站极速通
  • 网站建设与推广员岗位职责网站开发应如何入账
  • 企业网站的作用和目的手机回收站
  • 大连零基础网站建设培训电话郎溪做网站
  • 成都科技网站建设注册公司最少需要多少注册资金
  • 找公司做网站注意事项麻城建设局网站停办
  • 沧州企业做网站wordpress 消息通知
  • 网站开发外包计入什么科目怎样申请网站空间
  • 西安建设局网站小孩把巴塘网站建设
  • 做网站 客户一直要求改郑州做优惠券网站的公司
  • 专门做特卖的网站是什么东北石油大学秦皇岛吧
  • 网站建设需要云主机吗wordpress 下载数据表插件
  • 集团网站建设哪个好石龙镇仿做网站
  • 网站建设费税率是多少项目备案信息查询
  • 网站开发php有哪些权威发布型舆情回应
  • 凡科建站有哪些弊端百度手机怎么刷排名多少钱
  • 南山网站公司在招聘网站做销售工资高吗
  • 百度联盟怎么加入赚钱合肥seo按天收费
  • 网站建设与用户需求分析加盟店排行榜加盟项目排行榜
  • 柳州市诚信体系建设网站wordpress建手机网站吗
  • 网站策划书是什么水产公司网站源码
  • 温州做网站多少钱网站服务器机房
  • 网站公司设计 网站首页什么网站专门做图片
  • 书店网站怎么做网站点击快速排名
  • 太阳镜商城网站建设公司做网站
  • 如何制作个人作品网站宣传片拍摄合同
  • 关于微网站策划ppt怎么做做插画的网站