游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

天穹gateway网关系列3用户自定义动态filter

  开源地址
  https:github。comXiaoMimone一、为什么需要用户自定义动态filter
  在系列文章《如何设计filter链》里我们介绍了filter的设计思路以及它们是如何被加载串联为一条链路的。这些filter目前都是网关里内置的filter,比如我们默认支持日志filter,mockfilter等。但在实际的使用中,很多情景用户是需要可以自定义过滤器以满足一些自己的功能要求。所以自定义过滤器就非常有必要了。
  更进一步,动态加载这些自定义filter也是必须的,如果新增一个自定义filter就需要重启我们的网关集群来更新filter链路,很显然是不被接受的。二、核心设计与实现1、总体设计
  添加自定义filter:在网关控制台上传自定义filter,后台解析代码,分析出FilterDef(能唯一定义一个filter)。生成一条filter的记录。编译自定义filter:将上传的代码进行编译,并存储到文件服务器,方便gateway集群拉取到jar包。审核自定义filter:filter是用户自定义的,并且会被加载到网关集群,所以一定要review一下代码进行审核。启用自定义filter:在上述步骤完成之后,就可以启用filter使其生效了。2、编写自定义filter
  所有用户自定义filter都需要实现抽象类CustomRequestFilter,CustomRequestFilter实现了RequestFilter。用户filter只需要实现CustomRequestFilter里的execute方法即可。publicabstractclassCustomRequestFilterextendsRequestFilter{OverridepublicfinalFullHttpResponsedoFilter(FilterContextcontext,Invokerinvoker,ApiInfoapiInfo,FullHttpRequestrequest){if(this。allow(apiInfo)){try{context。setNext(false);returnexecute(context,invoker,apiInfo,request);}catch(Throwableex){log。error(invokecustomfilter:{}error:{},this。getDef()。getName(),ex。getMessage());filterchain已经执行过了,不再第二次执行了if(!context。isNext()){returninvoker。doInvoker(context,apiInfo,request);}returnHttpResponseUtils。create(Result。fromException(ex));}}else{returninvoker。doInvoker(context,apiInfo,request);}}publicFullHttpResponsenext(FilterContextcontext,Invokerinvoker,ApiInfoapiInfo,FullHttpRequestrequest){context。setNext(true);returninvoker。doInvoker(context,apiInfo,request);}publicabstractFullHttpResponseexecute(FilterContextcontext,Invokerinvoker,ApiInfoapiInfo,FullHttpRequestrequest);}复制代码
  下图是一个实际的filter例子,可以看到处理逻辑都写到了execute方法里面。resources里面的FilterDef唯一定义该filter。
  在实际编写自定义filter时,用户可能会用到更加丰富的能力,比如使用调用一个rpc接口,获取一个动态配置等,为此我们在RequestFilter里提供了getBean方法以获取这些能力。在filter中引入dubbo
  Dubbodubbothis。getBean(Dubbo。class);
  举例:MethodInfomethodInfonewMethodInfo();methodInfo。setServiceName(com。xiaomi。planet。user。module。api。service。SpecialUserService);methodInfo。setMethodName(testMethod);methodInfo。setGroup(staging);methodInfo。setVersion(1。0);methodInfo。setParameterTypes(newString〔〕{java。lang。Integer,java。lang。Integer});methodInfo。setArgs(newObject〔〕{1,1});Objectresultdubbo。call(methodInfo);复制代码在filter中引入nacos
  Nacosnacosthis。getBean(Nacos。class);
  举例:NacosConfignacosConfignewNacosConfig();nacosConfig。setDataId(configKey);nacosConfig。setGroupId(DEFAULTGROUP);Stringconfignacos。getConfig(nacosConfig);复制代码在filter中获取请求参数和header处理getMapString,StringqueryParamsHttpRequestUtils。getQueryParams(request。uri());处理postStringpostStrnewString(HttpRequestUtils。getRequestBody(request));处理表单HttpPostRequestDecoderdecodernewHttpPostRequestDecoder(newDefaultHttpDataFactory(false),request);ListInterfaceHttpDatapostDatadecoder。getBodyHttpDatas();for(InterfaceHttpDatadata:postData){if(data。getHttpDataType()InterfaceHttpData。HttpDataType。Attribute){MemoryAttributeattribute(MemoryAttribute)data;kv。put(attribute。getName(),attribute。getValue());}}处理headerFullHttpRequestrequest。headers()复制代码在filter里返回自定义结果返回HttpResponseUtils。create(),举例returnHttpResponseUtils。create(Result。fail(GeneralCodes。Forbidden,HttpResponseStatus。FORBIDDEN。reasonPhrase()));复制代码在filter里区分环境envGroup值有3种:staging,online(线上外网),intranet(线上内网)StringenvfilterContext。getAttachment(envGroup,staging);复制代码其他filter里的一些处理获取filter传递进来的参数filterParamsthis。getFilterParams(apiInfo);在实际调用下游之前的一些代码。。。省略代码。。。实际调用下游next(context,invoker,apiInfo,request)在实际调用下游之后的一些代码。。。省略代码。。。复制代码3、动态加载自定义filter
  在编写好自定义filter并上传审核完成后,控制台会广播通知gateway集群里的每个节点,有新的filter加入,是时候reloadfilterchain了。
  在第一节RequestFilterChain的reload方法基础上,我们加入加载自定义filter的逻辑吧。入口还是reload方法,它在获取用户定义的filter列表时,调用了FilterManager的getUserFilterList方法。热加载filter的逻辑我们都写到了FilterManager里面。Slf4jComponentpublicclassRequestFilterChainimplementsIRequestFilterChain{AutowiredprivateApplicationContextac;AutowiredprivateFilterManagerfilterManager;privatefinalCopyOnWriteArrayListRequestFilterfilterListnewCopyOnWriteArrayList();加载filterpublicvoidreload(Stringtype,ListStringnames){log。info(reloadfilter);获取系统定义的filterMapString,RequestFiltermapac。getBeansOfType(RequestFilter。class);ListRequestFilterlistnewArrayList(map。values());log。info(systemfiltersize:{},list。size());获取用户定义的filterListRequestFilteruserFilterListfilterManager。getUserFilterList(type,names)。stream()。filter(itfilterUserFilterWithGroup(it))。collect(Collectors。toList());log。info(userfiltersize:{}type:{}names:{},userFilterList。size(),type,names);list。addAll(userFilterList);listsortFilterList(list);。。。省略部分代码。。。}}复制代码
  FilterManager的getUserFilterList方法
  (getUserFilterListloadRequestFilterloadFilter)省略一部分代码,可前往https:github。comXiaoMimonetreemastergatewayall查看publicclassFilterManager{publicListRequestFiltergetUserFilterList(Stringtype,ListStringnames){try{if(!configService。isAllowUserFilter()){log。info(skipuserfilter);returnLists。newArrayList();}将老的filterjar包删除deleteOldFilter(type,names);从文件中心将编译好的filterjar包下载到本地downloadFilter(type,names);ListStringjarListgetJarPathList();log。info(jarList:{},jarList);热加载filterreturnloadRequestFilter(jarList);}catch(Throwableex){log。error(getUserFilterListex:{},ex。getMessage());returnLists。newArrayList();}}publicListRequestFilterloadRequestFilter(ListStringpathNameList){if(pathNameList。size()0){returnLists。newArrayList();}try{URL〔〕urlspathNameList。stream()。map(p{try{returnnewURL(file:p);}catch(MalformedURLExceptione){log。error(e。getMessage());}returnnull;})。filter(itnull!it)。toArray(URL〔〕::new);returnArrays。stream(urls)。map(url{try{log。info(loadrequestfilterurl:{},url);URLClassLoaderclassLoadernewURLClassLoader(newURL〔〕{url});returnloadFilter(url。getFile(),classLoader);}catch(Throwablee){log。error(loadfiltererror,url:{},msg:{},url,e。getMessage(),e);}returnnull;})。filter(itnull!it)。collect(Collectors。toList());}catch(Throwableex){log。error(ex。getMessage(),ex);}returnLists。newArrayList();}publicRequestFilterloadFilter(Stringurl,URLClassLoaderclassLoader)throwsIOException,ClassNotFoundException,IllegalAccessException,InstantiationException{StringcontentZipUtils。readFile(url,FilterDef);PropertiespropertiesnewProperties();properties。load(newStringInputStream(content));StringfilterClassproperties。getProperty(filter);Classlt;?clazzclassLoader。loadClass(filterClass);RequestFilterins(RequestFilter)clazz。newInstance();Stringnameproperties。getProperty(name);Stringauthorproperties。getProperty(author);Stringgroupsproperties。getProperty(groups);log。info(loadFilter,name:{},author:{},groups:{},name,author,groups);classLoaderMap。put(name,classLoader);ins。setDef(newFilterDef(0,name,author,groups));ins。setGetBeanFunction(getBean());returnins;}}复制代码
  至此,用户可以随时增加一个新的gatewayfilter,或者更新那些已经存在的filter,而不用进行任何重启。4、使用业务自定义filter
  在添加实际的apiinfo接口时,选择适合你接口的filter启用吧。

三月最该吃的菜你可知,益肝明目还防感冒,炒一盘,还不用五块钱三月最该吃的菜你可知,益肝明目还防感冒,炒一盘,还不用五块钱三月的春分天气宜人舒适,让人非常想出门踏青看看那春风吹绿的大地。呼吸一下新鲜的空气感受一下春的迷人景色,但是在……女儿最爱的早餐,一周吃3次都不腻,一次一个就管饱,特香特好吃女儿最爱的早餐,一周吃3次都不腻,一次一个就管饱,特香特好吃。孩子上学了,作为家长肯定要在早餐上花费不少心思,不可能说每天早餐都一个样,不然孩子也都吃腻了。我家也是这样,早餐包……你有啥好吃的地方特产推荐?谢谢邀请!要说好吃的地方特产,使我最魂牵梦绕的还是家乡单县的羊肉汤。老家山东省单县的羊肉汤也被誉为天下第一汤。这是因为在众多、甚至是数不胜数的各地名汤中,只有单县羊肉汤是……你觉得家里厨房里,最没用的厨具是什么?当初为什么购买?首先,我家是最普通的中国式厨房,不是很大,封闭式的。在看看我家的电器:1。电高压锅式电饭煲。优点是每天使用蒸饭功能,快还好吃,只需20分钟就可以。缺点,功能太多有点鸡肋,……黄晓明妈妈爆料杨颖真实性格,家里外面两张面孔,出乎意料黄晓明妈妈透露杨颖真实性格,节目里是女汉子,在家里却是乖乖女。对于现在的这个娱乐圈来说,明星们的离婚其实早就见怪不怪了,黄晓明、杨颖夫妇于2022年1月18日正式宣布离婚消息,……黄皮饮品火爆出圈!再次刷新北方人的水果认知来源:海报新闻继初夏的油柑之后,小众水果黄皮也在今年盛夏成功出圈,成了新式茶饮品牌的宠儿。百度指数显示,六月份以来,黄皮网络搜索指数呈拉升趋势,在6月26日至6月2……广东人喜欢的蒜蓉粉丝蒸花蛤,好吃到起飞,邻居家的孩子都馋哭了每个人的记忆深处都会有一道菜。就像我们长大了,在外拼搏的你,每当吃饭时,总会怀念儿时妈妈做的菜。有时候人们吃的不仅仅是味道,而是岁月里的一种记忆,更是记忆深处的那种……意外!火箭刺头无人认领,伊巴卡或被交易,莫兰特太尴尬了近日,NBA有大量的球员触发联盟健康与安全协议,在这样的情况下,球队为了考虑到应急不会轻易裁掉球员,但是不追求战绩的火箭是一个例外,管理层就裁掉了豪斯。怎么说呢,豪斯曾经也是火……天气炎热孩子没食欲隔三差五吃这12道菜,美味营养孩子喜欢吃大家好,欢迎大家来到我的美食自媒体,我是美食领域创作者锦绣V山东:专注美食,让生活更有味。今天为大家带来了几道家常美食的做法,这几道美食也是深受大家的喜欢,而且是很常见的几道美……晒黄瓜干,要不要焯水?70岁的妈妈这样做,1天晒干,又脆又香大家好,我是一名宝妈美食达人!生活中唯有爱和美食不可辜负,即使粗茶淡饭,也要过得活色生香!晒黄瓜皮,焯水就错了,教你正确做法,1天就晒干,好吃!炎热的夏天,温度真高……适合小朋友的酱香牛肉焖土豆,简简单单,味道好营养高,下饭一绝适合小朋友的酱香牛肉焖土豆,简简单单,味道好营养高,下饭一绝如果觉得还不错不要忘了关注我哦,每一个关注都是一份鼓励。我会更加努力更新优质实用的内容的。牛肉,是三大肉……输不起!韩媒再次质疑冬奥裁判,为崔敏静喊冤拉人也能拿金牌?北京时间2月11日晚间,女子短道速滑1000米的决赛,在这次的决赛中并没有中国选手参加,因此大家都将目光放在了韩国选手崔敏静身上,与韩国粉丝不同,中国观众基本上都不太希望崔敏静……
去了成都,被一碗10块钱的面彻底征服不睡到自然醒,就对不起天府之国。自然醒是不现实的,毕竟和公司小伙伴拍着胸脯说自己是来糖酒会找好酒的。不想吃油条包子,又没太多时间,吃面就是一个绝好的选择。前一天老赵……魅力江西,风景独好(中英文版)女士们、先生们,朋友们:大家下午好!Ladiesandgentlemen,dearfriends,Goodafternoon!从地图上看,江西就像一位带……梅苏特厄齐尔将因外科手术缺席三个月左右土耳其伊斯坦布尔巴沙克谢尔中场球员梅苏特厄齐尔将因外科手术而缺席三个月左右。俱乐部主席戈克塞尔居姆达格(GkselGmdag)说。对我们来说,能有厄齐尔这样的球员是一件非……比脸大2倍的面包羊腿,里边满满都是肉!北京第一新疆菜够豪横今儿个老白要去探的这家准噶尔餐厅是石河子驻北京办事处,就在龙潭公园边上,附近很多地铁站,地理位置着实很优越啊!鲁迅大大曾经说过这驻京办的菜能有多难吃呢?〔看〕咱们一……测评了几十款百元级别的葡萄酒,最后挑出这3瓶过几天就是国际妇女节啦专属于女生的节日当然要来点特别的给大家推荐几瓶女生都爱喝的葡萄酒在家做几个菜喝点酒,太有情调啦一、低起泡酒:一束花莫斯卡托产……HarmonyOS3即将上线卡片可堆叠互联更高效隐私更安全再过两天(7月27日),华为就将正式举行HarmonyOS3及华为全场景新品发布会。而预热许久的HarmonyOS3也将会在本次发布会上正式亮相,大家对于此次新版本的更新还是相……酒店为什么都要设置钟点房,3个小时可以做什么?对于人们来说,交通运输业的发展为生活带来了极大的便利,人们经常去各地旅游。去一个陌生的地方,首先就会找一个环境舒适的酒店,寻找当地的美食去品尝一下,玩够了再回到自己的家乡……秋天遇到此菜别错过,蒸包子最香,营养高味道棒,再不吃就过季了千万不要错过这道秋季佳肴,包子是最香,营养丰富的高味棒,而且不宜反季食用。秋天的天气凉爽舒适,有很多种蔬菜。我婆婆在楼下的小院子里种了很多蔬菜,茄子,黄瓜,西红柿,豆子,垃圾等……这道菜家家都会做,但是家家口味不同,网友评论还是不地道。这道菜色彩光亮,齿留余香,让人不仅想到原来它才是精品。最主要特色是酸辣可下饭。大家可能第一时间想到~酸辣土豆丝。有这么一句话不知道大家听说过没家家吃土豆丝,家家不会吃。今……饭店最火爆菜品,在家也能做出地道的口味,只需我们加入它几个朋友出去喝酒,必点菜之一,也是我的最爱~正宗川菜水煮鱼。我每次在家总做不出饭店的那种爽的味道,有时候非常接近,但是总是感觉缺少了什么。一个四川的同学告诉我,放错了调味品,应……橘子买回来这些都别扔,可以止咳化痰疏肝理气改善乳腺问题现在正是橘子大量上市的时候,圆滚滚、金灿灿的橘子,看着就喜庆,闻着就开心。买回家剥开吃了,香甜多汁,是很多人的心头好。可是你知道吗?橘子浑身都是宝,只吃橘肉就太可惜了!橘……成都世乒赛团体赛小组赛首局连下7分打出气势,樊振东30取胜10月3日,成都世乒赛团体赛男团第一小组的比赛继续进行,中国队迎战斯洛文尼亚队。樊振东、王楚钦和马龙三名选手出战本场比赛。首先登场的是樊振东,而他的对手是丹尼科组尔。首局……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网