你們好,今天開始給你們分享 — Dubbo 專題之 Dubbo 令牌驗證和優雅停機。在前面的章節中咱們介紹了 Dubbo 延遲和粘滯鏈接,瞭解了什麼是延遲和粘滯鏈接以及平常的使用場景和實現原理,同時咱們知道延遲鏈接是在使用實例對象的時候才建立通信鏈接,粘滯鏈接是儘量的使用已經建立的鏈接,它們都有相似減小鏈接建立的做用。那本章節討論一些輕鬆的話題就是令牌驗證和優雅停機,那什麼是令牌呢?以及它的做用是什麼呢?。那就讓咱們快速開始吧!java
首先介紹什麼是令牌,咱們經過一個生活中的小例子討論什麼是令牌。例如:咱們小夥伴常常坐火車出去玩那得首先購買火車票吧,而後咱們拿着火車票到安檢口進行檢票,檢票成功咱們就能夠乘坐火車,若是檢票失敗則不能乘坐。這裏的火車票就是咱們所說的令牌,只有拿到有效的令牌咱們纔有權限或資格作後續的事情。git
那什麼是優雅停機呢?簡單的理解就是在應用正常處理完成事後才退出應用,可是若是咱們經過kill -9 PID
等強制關閉指令,是不會執行優雅停機的,只有經過 kill PID
時,纔會執行。在個人 Dubbo 是經過 JDK 的 ShutdownHook 來完成優雅停機。spring
Dubbo 主要經過 XML 、註解、配置文件的方式配置:shell
XML 配置方式:apache
<!--隨機token令牌,使用UUID生成--> <dubbo:provider token="true" />
或者編程
<!--固定token令牌,至關於密碼--> <dubbo:provider token="123456" />
<!--隨機token令牌,使用UUID生成--> <dubbo:service interface="com.muke.dubbocourse.common.api.BookFacade" token="true" />
或者api
<!--固定token令牌,至關於密碼--> <dubbo:service interface="com.muke.dubbocourse.common.api.BookFacade" token="123456" />
註解方式:服務級別設置緩存
@DubboService(token = "true") //@Service(token = "true")
配置文件:全局配置tomcat
dubbo.provider.token=true
Dubbo 中主要經過屬性配置和編碼方式:微信
屬性配置:
# dubbo.properties dubbo.service.shutdown.wait=15000
編碼方式:
DubboShutdownHook.destroyAll();
Tips:使用 tomcat 等容器部署的場景,建議經過擴展 ContextListener 等自行調用如下代碼實現優雅停機
下面咱們看看 Dubbo 中令牌驗證和優雅停機的使用場景。首先 Dubbo 中的場景描述是令牌驗證在註冊中心控制權限,以決定要不要下發令牌給消費者,能夠防止消費者繞過註冊中心訪問提供者,另外經過註冊中心可靈活改變受權方式,而不需修改或升級提供者。優雅停機在 Dubbo 中注意也是用於資源的回收處理等。下面咱們討論經常使用的使用場景:
下面咱們以獲取圖書列表爲例進行實例演示主要演示令牌驗證。項目結構以下:
下面咱們看看服務消費端的配置dubbo-provider-xml.xml
:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <dubbo:application name="demo-provider" metadata-type="remote"/> <dubbo:registry address="zookeeper://127.0.0.1:2181"/> <bean id="bookFacade" class="com.muke.dubbocourse.tokenverify.provider.BookFacadeImpl"/> <!--暴露本地服務爲Dubbo服務--> <dubbo:service interface="com.muke.dubbocourse.async.api.BookFacade" ref="bookFacade" token="12345"/> </beans>
上面咱們開啓服務級別的 token
配置 token="12345"
設置 token
固定值。下面咱們看看服務消費端配置文件dubbo-consumer-xml.xml
:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <dubbo:application name="demo-consumer" logger="log4j"/> <dubbo:registry address="zookeeper://127.0.0.1:2181"/> <!--1.經過註冊中心獲取服務引用--> <!-- <dubbo:reference id="bookFacade" interface="com.muke.dubbocourse.common.api.BookFacade">--> <!-- </dubbo:reference>--> <!--2.url直接指定服務提供者所作機器以及端口--> <dubbo:reference id="bookFacade" interface="com.muke.dubbocourse.common.api.BookFacade" url="dubbo://localhost:20890"> </dubbo:reference> </beans>
上面的 XML 中若是使用第一種方式能夠正常訪問咱們的bookFacade
服務,若是使用第二種直連的方式繞開註冊中心則會獲得如下錯誤:
Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /192.168.101.8:20890Caused by: java.net.ConnectException: Connection refused at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
由於咱們的服務開啓 token
驗證若是繞開註冊中心直接調用則 token
會驗證不經過。
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
style="display:block; text-align:center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-4279907681900931" data-ad-slot="6812672741"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
下面咱們主要分析 Dubbo 中的令牌驗證源碼。
token 的解析過程:
當咱們的服務服務端的服務暴露時會調用方法`org.apache.dubbo.config.ServiceConfig
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) { //... //獲取在服務提供端配置的 token 值 ,例如:token="123456" if(ConfigUtils.isEmpty(token) && provider != null) { token = provider.getToken(); } if (!ConfigUtils.isEmpty(token)) { //若是配置值爲:true 或 default 則產生一個隨機的token值 if (ConfigUtils.isDefault(token)) { map.put(TOKEN_KEY, UUID.randomUUID().toString()); } else { //設置爲配置的token值 map.put(TOKEN_KEY, token); } } //init serviceMetadata attachments serviceMetadata.getAttachments().putAll(map); //... }
在上面的代碼中咱們能夠看到從咱們的配置中獲取token
值並註冊到註冊中心,若是配置值爲:true
或 default
則產生一個隨機的token
值,不然使用配置的token
值。
token使用過程:
在服務消費端調用請求到達服務提供端前會通過一些了的過濾器,其中就包括了對token
的校驗過濾器。核心代碼以下:
public class TokenFilter implements Filter { @Override public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException { //獲取token參數值 String token = invoker.getUrl().getParameter(TOKEN_KEY); if (ConfigUtils.isNotEmpty(token)) { Class<?> serviceType = invoker.getInterface(); Map<String, String> attachments = inv.getAttachments(); String remoteToken = (attachments == null ? null : attachments.get(TOKEN_KEY)); //驗證消費者攜帶的token與服務提供端的token是否相等 if (!token.equals(remoteToken)) { throw new RpcException("Invalid token! Forbid invoke remote service " + serviceType + " method " + inv.getMethodName() + "() from consumer " + RpcContext.getContext().getRemoteHost() + " to provider " + RpcContext.getContext().getLocalHost()); } } return invoker.invoke(inv); } }
經過上面的過濾器對token
進行驗證,若是驗證經過則調用後面的執行器,若是驗證失敗則拋出異常。
在本小節中咱們主要學習了 Dubbo 中的令牌驗證和優雅停機,以及常見的使用場景和使用方式。同時咱們也經過示例演示和源碼分析對 Dubbo 的令牌驗證原理進行解析。其中令牌驗證核心思想就是經過服務提供端提供的token
或者隨機產生的token
放入註冊中心進行管理,而後服務消費端獲取token
令牌而且在調用服務提供端時攜帶 token
,服務提供端根據消費端攜帶的token
進行驗證。在優雅停機方面 Dubbo 是經過 JDK 的 ShutdownHook 來完成優雅停機。
本節課程的重點以下:
我的從事金融行業,就任過易極付、思建科技、某網約車平臺等重慶一流技術團隊,目前就任於某銀行負責統一支付系統建設。自身對金融行業有強烈的愛好。同時也實踐大數據、數據存儲、自動化集成和部署、分佈式微服務、響應式編程、人工智能等領域。同時也熱衷於技術分享創立公衆號和博客站點對知識體系進行分享。關注公衆號: 青年IT男 獲取最新技術文章推送!
博客地址: http://youngitman.tech
微信公衆號: