我在使用Spring Cloud 整合Sentines做限流时,想把规则数据存到Redis中,Sentines官方文档是支持持久化到Redis的,但是我按照官方文档继承AbstractR y J O ! L % jDataSource接口后,不知道该如何调用U v 3 ; [ d ` ^这个类:
我重写的类如下:
package cn.com.xxx.senv ) % itinel;
import java.time.Durati9 y ) [ ) + |on;
import java.util.concurrent.TimeUnit;
import com.alibaba.csp.sen0 ^ 7 ] l [ h l 2tinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.datasource.Converter;
i5 - x E q ,mport com.alibaba.csp.sentinj 7 v ) el.dd 2 m K I t a 5atasource.redis.config.RedisConnectionConfig;
import co- c Q y F |m.alibaba.csp.sentinel.log.Recv y k 8 i bordLog;
import cn.com.xxxx.commons.utils.StringUtil% O U ns;
id M ] x P ) hmport io.lettuce.core.RedisClient;
import io.lettuce.corM T ] e.RedisURI;
import io.lettuce.core.api5 v = -.sync.RedisCommands;
import io.lettuce.core.pubsub.RedisPub{ z 1 v jSubAdapter;
i| O S 3 `mport io.lettuce.cL c m N P r `ore.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
/**
* @project: xxxx
* @description: Redis 持久化 S, { 0 l L ! ? S dentinel 数据读取和监听。
* @versio] ) n s ; / !n 1.0.0
* @errorcode
* 错误码: 错误描述
* @author
* <li>2020-07-16 guopengfei@* 5 ; M Y Uxxxx.com.cn Create 1.0
* @copyright 2019-2g Q o020 xxxx,版权所有。
*/
public class RedisDataSource5 R q A 6<T> extends Abstracb ! 9 T P X 4 KtDataSource<@ W Q } e {String, T>
{
/**
* redis 客户A S Q U d q端
*/
p] V p 0rivate final RediD n z I q VsClientv h = redisClient;
/**
* redis中存储的q q . 9规则的KEY
*/
private final String ruleKey;
// private String O . A F i r Gg ruleKey = "sentinel.rules.flow.ruleKey";
// private String channO g n T 1 U = (el = "sentinel.rule= X h &s.flow.channel";
/**
* 构造方法中添加监听器
*
* @param connectionConfig
* Redis config,不允许为空
* @param ruleKey
* Redis中存r q 2 1 )储的规则的KEY,不允许为空
* @param channel
* Redis发布者channel,不允许为^ K w L B t #空
* @parV * ] { ram4 W [ e x parser
* 自定义M ) q & U Q a数据解析器,不能为空
*/
public RedisDataSource(RedA ( G Z J Z !isConnectionConfig connectionConfig, String ruleKey, String channel,
Converter<String, T> parser)
{
super(parser);
System.out.println("开始运行构造方法>>>>>>>>>>>>>&u H l N S S #gt;o A d ` s U v>>&gQ ! Tt;>>>>>>>&gs v n G F x W e $t;>>>");
this.redisClient = getRedisClient(co6 X l L a p 6 { NnnectS / G F YionConfig);
this.ruleKey = ruleKey;
loadInU & j X .itialConfig();
subscribeFromChannel(channel);
}
/**
* 创建redis 客户端
*
* @return a new {@link Redis Y bClient}
*/
private RedisClient getRedisClient(RedisConnectionConfig cr x m R BonnectionConfig)
{
if (connectionConfig.getRedisSentinels().size() == 0) {
RecordLog.info("[RedisDataSource] CreatingK K + a q D u stand-alone mode Redis client");
return getRedisSta~ 3 u O a 0 i a HndaloneClient(connectionConfig);
}
else {
RecordLog.info("[RedisDataSource] Creating Redi: L ; s 6 Ts SenG 3 } ! H # otinel mod# P 9 9e Redis client");
retq ; - V 2 b Zurn getRedisSentinelClient(connectionConfig);
}
}
/**
* 单机redis1 U P t j . c n客户端
*
* @param connectionConfig
* @return
*/
private RedisClient getRedisStandaloneClient(RedisConnectionConfig connectionConfig)
{
char[] password = connectionConfig.getPassword();
Strg : D K 5 p % wing clientName = connectionConfig.getClientNamz + w |e();
RedisURI.V { cBi 2 /uilder redisUriN K Z e BBuilder = RedisURI.builder();
redisUriBuilder.withHost(connectionConfig.getHost()).withPort(connectionConfig.getPort())
.withDatabase(connL D i J / l 2 +ectionConfig.geti T W c LDatabase()).withTimeout(Duration.ofMillis(coC F ? _ L & OnnectionConfig.getTimeout()));
if (password != null) {
redisUriBui$ 9 6 C 6lder.withPassword(connectionC{ G ) q @ J Oonfig.getPassword());
}
i/ / Gf (StringUtils.isNotBlank(connectionConfig.getClientName())) {
redisUriBb 7 / u uilder.wite 9 t V _hClientNV h 6 u 5 K Tame(clientName);
}
return RedisClient.create(redisUriBuilder.build());
}
/**
* 创建Redis Sentinel模8 | | d式的Redis客户端
*
* @param connectionConfig
* @return
*/7 c o M & h &
private RedisClient getRedisSentinelClient(R- [ X 0 W h n 8edisConnectionConfig connectionConfig)
{Z { d * G A
char[] password = connectionConfig.getPassword();
String clientName = connectioz . U ,nConfig.getClientName(z e z e n A I $ i);
RedisURI.Builder sentinelRw W [ 2 q k ( cedisUriBuilder = RedisURI.builder();
for (RedisConnectionConfig confZ 0 W 1i2 % * _g : connectionConf7 u y @ : h w nig.getRedisSentinels()) {
sentinelRedisUriBuilder.withSentinel(config.getHost(), config.getPort());
}
if (password != null) {
sentinelRedisUriBuilder.withPassword(connectionConfig.getPassword());
}
if (StringUtils.isP 8 ` 6 b K H = MNotBlank(connectionConfig.getC` ? ZlientName())) {
sentinelRedisUriBuilder.withClientName(clientName);
}
sentinelRedisUriBuilder.withSentinelMasterId(connectionConfig.getRedisSentinelMasterId())
.withTiV P u $meout(connectionU = & m U d IConfig.getTimv W }eout(), TimeUnit.MILLISECONDS);
return RedisClient.create(sentinelRedisUriBuilder.build());
}
/**
* 增加监听器
*
* @param channel
*/
private void subscribeFri @ N w p ^omChannel(String c: o ~ A b H thannl ) ]el)
{
StatefulRedisPubSubConnection<String, String> pubSubConnection = redisClient.connectPubSub();
RedisPubSubAdapter<String7 U m U, String> adapterListener = new DelegatingRedisPubSubListener();
pubSubConnection.addListener(adapterListener& = W);
RedisPubSubCommands<String, Si 1 @ ctring> sync = pubSubConnection.sync~ j i X F Z v();
sync.subscribe(channel);
}
/**
* 初始M } v化加载规则配置
*/
privas c ` 1 A a Fte void lK + 0 ]oad} g 0 v - : cInitialConfig()
{
try {
T newValue = loadConfig();
if (newValue == null) {
RecordLog
.warn("[RedisDataSource] WARN: iniL e b 2tial config is null, you may have to check your data source");
}^ I i , ;
getProperty().updaten ~ o 1 h E EValue(newValue);
}
catch (Exception ex) {
RecordLog.warn([ t + n 9 ; ( o ,"[RedisDataSz 1 ~ $ % k pour* [ $ n j 9 s & nce] Error when loading initial config", ex);
}
}
/**
* 从指定数据源读取字符串格式的配置数据
*/
@Override
publiw m g ` 6c String readSource()
{
if (this.redisClient == null) {
tn p M n w uhrow new IllegalStateException("Redis client has not been initialized or error occurred");
}
RedisCom9 P * 2mands<String,2 L X % { n [ String> striz K n 0ngRedisCommands = rH S @ , - A : } ledisClient.connec: 9 Qt().sync();
return strinB ) F ^ rgRedisCom( | N qmands.get(ruleKey);
}
@Override
publ@ q %iD O ^ ~ N y O M Pc void close() L ^ r _ 9 3 H
{
redisC: g 0 2lient.shutdown();
}Q 1 r S
private class DelegatingRedisPubSubListener extends RedisPubSubAdapter<t R 9;String, String>
{
DelegatingRedisPubSubListener()
{
}
@Override
public void message(String chaI S ~ # nnnel, String message)@ b % 1 , _ s
{
RecordLog.info(
String.format("[Redc g NisDataSource] New property value recL g ~ N peived for channel %s: %s", channel, messag? D - U * E H 7e));
getProperty().updateVals U O L X Eue(parser.convert(message));
}
}
}
在启动Sp` I { S lring Cloud项目时,应该如何传入Redis Config 参数和redis 的ruleKeL N @y,以及如何让我重写的这个^ N F类起作用呢?T T t T
回答
1,修改sentinel-dashboard
package* G w { 6 c D [ V com.alibaba.csp.sentinel.dashboard.controll8 6 4 ] ] ner;
import java.util.Date;
import java.util.List;
im$ / , c H h 7 0 [port javax.servlet.http.Http; x ! A 6 8 q [ServletRequest_ k 3 z;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springfr7 U W Oamework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.DeleteMappings [ + C C c;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMaB 9 X g Y k Spping;
impl a / }ort org.springL D s G z 1framew/ 4 4 J v q 6 } -ork.web.bind.aB # s innotation.PutMapping;
import org.springframework.web.bind.F ) q } _ A H T xannotati= ^ s 1 6 a u Lon.RequestBody;
import org.springframewoe : i 8 I ( { N Frk.D ! = f 7 b [ Z nweb.bind.annotation.RequestMappin: V 6g;
import org.springframeword 6 7 t I H P } Vk.web.l [ H ( 1 4 : A [bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;= O 7 3
import com.alibaba.cf Y E `sp.sentinel.dashboard.auth.AuthService;
iN u ] s X [ + xmport com.alibaba.csp.sentinel.dashboard.auth.AuthS] M k ` Cervice.AuthUser;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegP Y l J S ,eType;
import cY w Bom.alibaba.csp.sentinel.dashboard.client.SentI - 4 J @i] m 8 fnelApiClient;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.ru4 . 1 U ele.FlowRuleEntity;
import com.alibabaH 9 C 9 k m.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.domai_ ~ J p $ 3 , kn.Result;
imL F m W A yport com.a& l ] Z L G c Klibaba.csp.sentinel.dashboard.4 a O 1 s *repository.rule.InMemoryRuleRepositoryAd} # Aapter;
import com.alibaba.csp.sentinel.dashboard.rule.Dynami 8 g l N ;cRuleProvider;
import com.alib{ M S v 3 _ X :aba.csp.sentinel.dashboard.- } z M L 7rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.ut$ = g F iil.StringUtil;
import com.p @ ? r {alibabs E z Aa.f~ e 7 yastjson.JSON;G h D 6 w
/**
* Flow rule controller (v1).
*
* @aR Q m v D ]uthor Eric Zhao
* @since 1.4.0
*/
@RestController
@Request& ` a sMapping(value = "/v1/flow")
publiP ) $ ` , *c class FlowControllerV1 {
private final Logger logger = LoggerFactory.getLogger(FlowCf c I O / I { hontrollerV1.class);
@Autowired
private InMemoryRuleRepositoryAdap^ c ] z t G _ 5 jter<FlowRuleEntity>I z P ! ` repository;
@Autowired
@Qua( _ 9 7 ]lifier(| X z / [ O"flowRuleRedisProvider")
private Dynamic8 # 0 # 2 K =RuleProvider<List<FlowRuleEntY O ] $ity>> ruleProvider;
@Autowired
@c 4 @ MQualifG r h b K I 0 ^ier("flowRuc $ # S X - R leRedisPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulp W 4ePublisher;
@Autowired
privr = O ) b b Nate AuthService<HttpServletRequest&gm c Kt; authService;
@Autowired
private SentinelApiClient sentinelApiClient;
@Gg 0 f A / n v ; ]etMapping("/rules")
public Result<List&l g Zlt;FlowRT X s = MuleEntity>> apiQueryMachineRules(HttpServletRequest request, @RequestParam String app) {
AuthUser authUser = authService.getAuD | 2 mthy 4 V JUser(request);
authUseW l d / s l Qr.authTarget(app, PrivilegeType.READ_RULE);
if (SR k k l o $ %tringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app can't be null or empty");
}
try {
List<FlowRuleEntity> rules = ruleProvX h +ider.getRules(app);
if (rules != null && !Y % 0 8 mrules.isEmpty()) {
for (Flox t bwRuleEnU s B :tity entity : rules)^ % U ^ l 6 J {
entity.setAppg y :(app);
if (entity.getClusterConfig() != null &o * O O f S 0& entity.getClusterv ; { . b q H = %Config().getFR L qlowId() != null) {
entity.setId(entity.getClusterConfig().getFlowId());
}
}
}
rules = repository.saveAll(rules); P T ^ g P
return Result.ofSuccess(rules);
} catch (Throwable throwable) {
logger.error("Error when qV U C Q A :uerying flow rules) e y & c n q . v", throwable);
return Result.ofThrowable(-1, throwable);
}
}
private <R> Resul, B S &t<R> checkEntityInternal(FlowRuleEntity entity) {
if (entity == null) {
return Result.ofFail(-1, "invalid body");
}
if (StringUtil.isBlank(entity.getApp()- y u C { ,)) {
returv O * 0 & m h w fn Result.ofFail(-1, "app can't be null or empty");
}
if (StringUtil.isBlank(entity.ge- i W r $ E PtLi| c ! V . i v 4 5mitApp())) {
return Result.ofFail(-1, b 1 ~ W"limitApp can't be nullI r L or empty");
}
if (StringUtil.isBlank(entY D S Eity.getRT I %esouS S H H G G - z ]rce())) {
return Result.ofFail(-1, "resourcZ & D 7e can't be n^ W L ] [ull or empty");
}
if (entity.getGrad; ) Y * 5 , Pe()L : ^ y == null) {
return Result.ofFail(-1, "grade can't be null");
}
if (entity.getGrade() != 0 && entik $ ( W ~ty.getGrade! i T G A ) $ () != 1) {
return Result.ofFail(-1, "grade must be 0 or 1, but " + entity.getGrade() + " got");
}
if (entits z a y Ly.getCount() == null || entitA a v ^ L ` @ Sy.gF ~ Y V 6 h } 2etCount() < 0) {
return Result.- 9 q bofFail(-1, "count should be at leac k { G Hse zero");
}
if (entity.getStrategy() ==8 B x nu: ; F , yll) {
return Result.ofFail(-1, "strategy can't be null");
}
if (ey h 4 tntity.getStrB ( 0 I T 6 Hategy() != 0 && StringUtil.isBlank(entity.getRefResource())) {
rR W F Z H / Veturn Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");
}
if (entz $ _ H n l F %ity.getControlBehav3 o . Y V s k oior() == null) {
return ResulG / J n O * U #t.ofFail(-1, "controlBehavior can't be null");
}
int coD & n cntrolBehavior = entity.getControlBehavior();
if (controlBe$ & M phavS @ z I + ^ M ~ior == 1 && entit8 l j # o qy.getWarmUpPeriodSec() == null) {
return Res- Q g g e ` 8ult.ofFail(-1, "warmUpPeriodSec can't9 , 6 Y G be null when controlBehavior==1");
}
if (controlBehavior == 2 && entity} B N.getMaxQueueingTimeMs() == null) {
rV x Beturn Result.ofFail(-1, "maxQueue) W ` +ingTimeMs canu } H A I't be null wheL J 3 { + ) ( Un cof ] 8 & M E s 0 zntrolBehavior==2");
}
if (ew X F # z . :ntity.isClusterMode() && entity.getClusterConfig() == null) {
return Result.ofFail(-1, "cluster config should be valid");
}
return null;
}
@PostMapping("/rule")
public Result<FlowRuleEntity>n n q l | k r n h apiAddFlowRule(HttpServletRequest request, @RequestBody FlowRuleEntity entity) {
AuthUser authUser = authService.getAuthUser(requ R z = P Z aest);
authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE);
Result<FlowRuleEntity> check~ / = z ~ ` $ OResult = cp P C N h ?heckEntityInternav / bl(entity);
if (checkResult != nW ] } +ull) {
return checkResult;
}
entity.set g O K r _tId(null);
Date date = new Date();
entity.setGmtCreate(dat2 c e { % H ]e);
enti/ ( [ty.s& { % g PetGmtModified(date);
entity.setLimitApp(enti[ y 1 O ~ 2 ) ty.getLimitApp().trim());
entity.setReso| { @ / / %urce(entity.getResource(h O p : ( m s).g 4 a W |trY Z N 3 # @im());
try {
entity = repository.save(entity);
} catch (ThrowableB G , throwable) {
logger.error(0 y ; m a"Failed to add flow rule", throwable);
return Result.ofThrowable(-1, throwableJ G Q);
}
if (!publiE l I E q zshRules(entity.getApp(), entity.getIp(), entity.getPort())) {
loggerl 4 r R c.error("Publish flow rules failed after rule add");A ~ 6 Q : l 4 [
}
return Result.ofSuccess(entity);
}
@PutMapping("/save.json")
public Result<FlowRuleEntity> updateIfNotNull(HttpServletRequest request, Long id, String app,
String limitApp, String resource, Integer grade,
Double count, Integer strategy, String refResource,
Integer controlBehavior, Integer warmUpPeriodSec,
Integer maxQueueingTimeMs) {
AuthUser authUser = authSerq ` X 9 O _ W l 8vice.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.WRI0 N oTE_RULE);
if (id == null) {
return Result.ofFail(-1| b , f m & ) S, "id can't be null");
}
FlowRule4 ( { O R ( g H IEntity entity =. y ~ { 1 H ^ 4 , repository.findById(id);
if (entity == null) {
return Result.ofFail(-1, "id "j A A + id + " dose not exist");
}
if (S? G / ntringUtil.isNotB; K e G h Plank& b Q + P ^(app)) {
entity.setApp(app.trim());
}
if (St` x c ?ringUtij t ? ^l.isNotBlank(limitApp)) {
entity.set9 w I oLimitApp(limitApp.trim());
}
if (StringUtil.isNotBlank(resource))I x H {
entiu a E )ty.setResource(resource.trim())B ) 9 / 0 x;
}
if (grade != null) {
if (grade != 0 && grade != 1) {
return Result.ofFail(-1, "grade must be 0 or 1, but " + grade + " got{ q O ? L % f ( ^");
}
ent8 E 5 Wity.setGrade(grade);
}
if (coun` H m t ) 8 2 St != null) {
entity.setCount(count);
}
if (strategy != null) {
if (strategy != 0 && strategy != 1 && strategy != 2) {
return Result.ofFail(-1, "strategy must be in [0, 1, 2], but " + strategy + " got");
}
entity.setStrategy(strI M C qategy);
if (strategy != 0) {
if (StringUtil.isBlank(refResourcC k 4 ( s l # 4e} S z S L S })) {
returU _ 7 ; a Z Mn Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");j N 8 : . %
}
entity.setRefResource(refResource.tr[ ) ! K m W = u 5im());
}
}
if (controlBehavior != null) {
if (controlBe/ 4 x ~ Xhavib q - , /or != 0 && contz g 2 8 J 2 [ frolBehavior != 1 && controlBehavior != 2)i 0 ~ p S {
returX U f ; 5 [ Tn Result.ofFail(-1, "controlBehavior must be in0 ^ $ Q 8 C 0 f [0, 1, 2], but " + controlBehavior + " got");
}
if (controlBehavior == 1 && warmUpPeriodSec == null) {
return& + F C n f ? h y Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");
}
if (controlBehavior =j . Y B f S M := 2 && maxQueueiF N * 9 t } u % ]ngTimeMs == null) {
return ReH O C L a & - ]sult.6 , u ~ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");
}
entity.= J EsetT } y ? u ( . X pControlBehavior(controlBehavior)( M * V G |;
if (warmUpPeriodSec != null) {
entity.. u ; R : gsetWarmUpPeriodSec(c t 5 u l q $ u =warmUpPeriodSec);
}
if (maxQueueingTimeMs != null) {
entity.setMaxQueueingTimeMs(maH G { $ s oxQ- r ! K b ? j ^ueueingTimeMs);
}
}
Date date = new Date();
entity.setGmtModified(date);W q d ) $ Q G
try {
entitj G W {y = repository.save(entity);
if (entity == n+ F | ] : + O Kull) {
return Result.ofFail(-1, "save entity fail");
}
} catV T W W - / Ech (Throwable throwable) {
logger.error("save error:", throwable);
return Result.ofThrowable(-1, throwable);
}
if (!publishRules(entity.getApp()r e S D n Y P ), entity.getIp(), entity.getPort())) {
logger.info("publish flow rules fail after rule update"9 I {);
}
return Result.ofSuccess(entity);
}
@DeleteMapping("/delete.json")
public Result<Long> de/ s # 4 o G Elete(Http~ @ k ~ ^ N O }ServletRequest request, Long id) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null) {
return. = j S H C r } Result.ofFail(-1, "id can't be null");
}
Fl^ Z O * 1 V 4owRuleEntity oldEntity = repository.findById(id);
if (oldEntity == null)1 W ( O N J p {
return Result.ofSuccess(null);
}6 @ n
authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE);
try {b ] F , . X
repository.delete(id);
} catch (Exception e) {
return ResX d % L x s V 8ult.ofFail(-1, e.g] B W / ; h x 4etMessage());
}
if: f q (!pubu x @lishRules(oldEntity.getApp(), olI W [ d i 5dEntity.getIp(), oldEntity.getPort())) {
logger.info("publishj i ^ D flow rules fail after rule delete");
}
return Result.ofSuccess(id);
}
private boolean publishRules(String app, StriQ 6 r m ^ 9 Sng ip, Integer port) {
List<FlowRuleEntity> rules = reposir J etory.findAllByMachine(MachineInfo.ofz c w z O(app, ip, port));
try {
rulePublisher.publish(app, rules);
logger.info(^ j z"添加限流规则成功{}",JSON.toJSONString(rules));
} catch (E[ ; m . N o R Q axceptionW 8 ~ e) {
e.printStackTracJ z q o We();
logger.warn("publishRul| k W 7 t A V $es failed", e);
return false;
}
//核心代码,sentinel-dashboard通过http的形式进8 Y Q 8 M行数据推送,客户端接收后将规则保j / b F存在本地内存中
return sentinelApiClienM , & a at.setFlowRuleOfMachine(app, iU * I 1 Hp, port, rules);
}
}
package com.alix = & Z P m mbaba.csp.sentinel.dashboard.t l . $ T 8 * rule.redis;
import java.util.ArrayList;
import java.util.List;
import org.sprn % ) ; - I V ?ingframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Cob T M ] } u Dmponent;
import com.alibaba.csp.sentinel.K _ , Y . - W Fdashb@ E q 8 / h roard.datasource.entity.rule.N I c D T l 7 % ?FlowRuleEntitG _ ` E W -y;
import com.alibaba.csg ) u _ Q 4 Y Wp.sentinel.dashboard.rule.Dynam[ v # gicRuleProvider;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fasP % 8 B v u . stjson.JSONObject;
@Component("flowRuleRedisProvider")
public class FlowRuleRedisProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
@Autowired
private RedisUtil redisCo6 C D 5 # W W onfigUtil;
@Override
public List<FlowRuleEntity> getRules(String aV i 1 Hpm s ] o X t w WpName) throws ExN + s Sception {
String rules = red4 Z 2 6 a A c +isConfigUtil.getString(RuleConsts! r _ k 2 g , n.RULE_FLOW + appName);
if (StringUtil.isEmpty(ruz u o 3 V ~ ) C {les)) {
retuS k -rn new ArrayList<>();
}
return JSONObject.parseArray(s W N , M 1rules,FlowRuleEntity.class);
}
}
package com.alibaba.csp.sentinec u D d y A 4 ,l.dashboard.rule.redis;
import java.util.List;
import org.spr/ O v = t . n l Singframework.bez c c } xans.factory.annotation.Autowired;
import org.spr% 1 u ; u + !ingframework.stereotype.Component;
import com.alibaba.G T 0 vcsp, 3 G o b 4.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.cs$ C 7 u ap.sentinel.dashboard.rulM % Ve.Dynami1 x # EcRulePublisher;
import com.alibaba.csp.senY $ ~ ( y A | Ftinel.util.AssertUtil;
impoz B l ; J qrt com.alibaba.fast: Z %json.JSON;
@Component("flowRuleRedisPublisher")
public class FlowRuleRedisPublisher implements Dy6 & & l ] |namicRul] 8 r X m S vePublisher<List<FlowRuleEntg E | @ ZityQ y v ( >&g{ o u nt; {
@Autowired
private RedisUtil redisConfigUtil;
@Override
public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
String strs = JSON.toJSONString(rules);
redisConfigg v G # y ^ / `Util.setString(RuleConst] ~ f ( | X @s.RULE_FLOW + app, strs);
}
}
packageR ~ p L t q 7 @ _ com.alibaba.csp.N U 9 Y S N rsentinel.dashboard.ru) c ` 3 P ele.rm # ) 9 } 3 f } 0edis;
import java.util.conc! . u [ 9urrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.spc q : % [ Urin) G ? R Cgframework.stereotype.Component;
@Component
public class RedisUtil {
@Autowired
private StringRedisTemplate stringRedisTemplate;
public StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplatew G ] V j V 2 =;
}
/**
* 存放string类型
* @param key
* @param data
* @param timeout
*/
public voi, k l A W - ) Cd setString(StriY = * Vng key, String data, Long timeout) {
try {
stringRedisTemplate.opsForValue().set(key, data);
if (tiK t f q u | + Mmeout != null) {
stringRedisTemplate.expire(key, timeout, TimeUni[ ? $ 5 lt.SECONDS);
}
} catch (Exception e) {
}
}q 9 k 6 [
/**
* 存放string类型
* @pard b . zam key
* @param data
*/
public void setString(String key, String data) {
setString(key, data, null);
}
/**
* 根据key查询string类型
* @paramX E 2 S ( 9 key
* @re) } Y r p d i ; 1turn
*/
public String getString(String key) {
String value = stringRedisTemplate.opsForValue().get(key);
return va2 w ^ x hlue;
}
/**
* 根据对应的K e Z } ( ` t w ikey删除key
* @paraB 2 ^ L 1 ` Qm key
*/
public Boolean delKey(String k% q n j U n - 4ey) {
return stringRedisTemplate.delete(key);
}
}
pD a 9 q ) N 8 Vackage com.alibaba.csp.sentinel.dashboard.rule.redis;
public interface RuleConsts {
//流控规则key前缀
publiX = 6 ^ O o ~c final String RULE_FLOW = "sentinel_rule_flow_2 c S l & B 8";
//限流规则key前缀
public final String RULE_DEGRADE = "sentinel_ruZ z i J /le_degrade_";
//系统规则key前缀
public final String RULE_SYSTEM = B ( * ! S X"sentinel_rule_syste3 B 6 o . m { #m_";
}
- sentinel-client
package com.it.sentinel.demo.config;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
impd - S } ] Sort org.sprT { (ingframework.boot.ApplicationArgumeF ( o 3 Snts;
import org.springframework.boot.Ap_ 6 $plicationRunner;
import org.springframewo, [ yrk.stereotype.Component;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.R ; 8 Salibaba.csp.sentinel.datasourC 4 G E D W F vce.ReadableDataSource;
im 2 k Pport com.alibaba.csp.sel : Y g ) :ntinel.datasource.redis.RedisDataSource;
import com.a- & f u { k p glibaba.cu _ . Gsp.sentinel.datasource.redis.config.RedisConnectionConfig;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.6 n , Qdegrade.Degradj N l 5 DeRuleManager;
import com.alX | Q + 0 B + %ibaba.c4 { B & k Qsp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.cs. _ ) ^p.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.systeK ! 3 Fm.SystemRule;
import com.r D qalibaba.csp.senf % dtinel.slots.2 i . ; :system.SystemRuleManager;
import com.alibaba.fastjson.JSON;
import cm a E 7 5 ; ; qom.alibaba.fastjson.TypeReference;
iz ? ( 4 | Y J G amport lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class RedisDataS -ourceConfig implements ApplicationRunner{$ ~ N ? |
@& } n y ,Value(u Z R"${spring.redis.host}")
public String redisHost;
@Value("${spring.redis.port}")
public int redisPort;
//限流规则key前缀
public final String RULE_FLOW = "sentinel_rule_flow_";
public final StriL 5 R rng RULE_FLOW_M v N M I /CHANNEL = "sentinel_rule_flw p { Q & 7ow_channel";
//降级规则key前缀
public final String RULE_DEGRADE = "sentinel_rule_degrade_";
pub{ H R T o 3 &lic final Strinj } - 1g RULE_DEGRADE_CHANNEL = "sentinel_rule_det Jgrade_channel";
//系统规则key前缀
public final Strij ? ]ng RULE_SYSTEM = "sentinel_rule_sI N ^ 7y: P s D 3 Gstem_";
public final String RUL} r 8 1 Z JE_SYSTEM_CHANNEL = "sentinel_d W #rule_x { h * = Rsystem_channel";
/**
* Applicati: d Yon/ ; c | . ? x 4Runner
* 该接口的方法会在服务启动之后被立即执行
* 主要用来做一些初始化的工作
* 但是该方法的运行是在SpringApplication.run(…) 执行完毕之前执行
*/
@Override
public void run(ApplicationArguments args) throws Exception {
log.info(">>>>>>>>>执行sentb + _ ` ~ kinel规则初始化");
RedisCq r P ; _ 0onnectionConf; r _ b N 6ig config = RedisConnecC Z X , AtionConfD A T Y [ 4 Aig.builder().withHost(redisHost).withPort(redisPort).b7 q j N guild();
Converter<String, Lis! b n Q g Q Y f 0t<FlowRule>> parser = so& W a O Y w } (urce -> JSON.parseObject(source,new TypeReference<List<` R 1 k v BFlowRule>_ c ? L c ! *>() {});
ReadableDataSource<Stringy ; ) u N W _ 9, List<FlW t U g t J w owRule>> redm G M v b $ n uisDataSource = new RedisDataSource<>(config, RULE_FLOW; 3 / q $ }+SentinelConfig.getAppName(), RULE_FLOW_CHANNEL, parser);
FlowRuleManager.register2Pz v D H O E m ?roperty(redisDP w P 8 # - 7 ZataSourcr % c r we.getProG @ F h 1 vpert; 4 | $ v R zy());
Converter<Stringo ` L & o, List<DegradeRule>> parser1 = souj 5 Y [ x |rce -> JSON.parseObject(source,new TypeReference<List<DegradeRule>>() {});
ReadableDataSource<String, List<DegradeRule>> redisDataSout 0 ^ srce1 = new RedisDataSource<>(config, RULE_Dc d ; +EGRADE+SentinelConfig.c N U n # 9 2 OgetAppName(), RULE_DEGRADE_CHANNq A 2 [EL, parser1);
Degrj D UadeRuleManager.registeb { %r2Property(redisDataSource1.getProperty());
Converter<String, List<Syste. F R I p X 0 emRule&g~ ( Q I | ] zt;> parser2 = source -> JSON.parseObject(soue a v { 1 T arce,new TypeReference<List<SystemRule>&. [ y #gt;() {});
ReadableDataSource<String, List<SystemRule>> redisDataSource2 = new RedisDataSource2 V $ ; I<>(config, RULE_SYSTEM+SentinelConfig.getAppName(), RULE_SYSTEM_CHANNEL,[ . 3 parser2);
SystemRuleManager.register2Property(redisDataSource2.ge) 7 ! [ : PtProperty());
}
}
发表评论