dubbo高階配置學習(上)

FrankYou發表於2018-02-05

啟動時檢查

Dubbo預設會在啟動時檢查依賴的服務是否可用,不可用時會丟擲異常,阻止Spring初始化完成,以便上線時,能及早發現問題,預設check=true

如果你的Spring容器是懶載入的,或者通過API程式設計延遲引用服務,請關閉check,否則服務臨時不可用時,會丟擲異常,拿到null引用,如果check=false,總是會返回引用,當服務恢復時,能自動連上。

可以通過check="false"關閉檢查,比如,測試時,有些服務不關心,或者出現了迴圈依賴,必須有一方先啟動。

關閉某個服務的啟動時檢查:(沒有提供者時報錯)

<dubbo:reference

interface="com.foo.BarService"

check="false"

/>

關閉所有服務的啟動時檢查:(沒有提供者時報錯)


<dubbo:consumer

check="false"

/>

關閉註冊中心啟動時檢查:(註冊訂閱失敗時報錯)

<dubbo:registry

check="false"

/>

也可以用dubbo.properties配置:

dubbo.reference.com.foo.BarService.check=false


dubbo.reference.check=false
dubbo.consumer.check=false
dubbo.registry.check=false

也可以用-D引數:

java
 -Ddubbo.reference.com.foo.BarService.check=false
java
 -Ddubbo.reference.check=false
java
 -Ddubbo.consumer.check=false 
java
 -Ddubbo.registry.check=false

注意區別

dubbo.reference.check=false,強制改變所有reference的check值,就算配置中有宣告,也會被覆蓋。

dubbo.consumer.check=false,是設定check的預設值,如果配置中有顯式的宣告,如:<dubbo:reference check="true"/>,不會受影響。

dubbo.registry.check=false,前面兩個都是指訂閱成功,但提供者列表是否為空是否報錯,如果註冊訂閱失敗時,也允許啟動,需使用此選項,將在後臺定時重試。

引用預設是延遲初始化的,只有引用被注入到其它Bean,或被getBean()獲取,才會初始化。

如果需要飢餓載入,即沒有人引用也立即生成動態代理,可以配置:

<dubbo:reference

interface="com.foo.BarService"

init="true"

/>

叢集容錯

在叢集呼叫失敗時,Dubbo提供了多種容錯方案,預設為failover重試。

各節點關係:

這裡的Invoker是Provider的一個可呼叫Service的抽象,Invoker封裝了Provider地址及Service介面資訊。

Directory代表多個Invoker,可以把它看成List<Invoker>,但與List不同的是,它的值可能是動態變化的,比如註冊中心推送變更。

Cluster將Directory中的多個Invoker偽裝成一個Invoker,對上層透明,偽裝過程包含了容錯邏輯,呼叫失敗後,重試另一個。

Router負責從多個Invoker中按路由規則選出子集,比如讀寫分離,應用隔離等。

LoadBalance負責從多個Invoker中選出具體的一個用於本次呼叫,選的過程包含了負載均衡演算法,呼叫失敗後,需要重選。

叢集容錯模式:

Failover Cluster

失敗自動切換,當出現失敗,重試其它伺服器。(預設)

通常用於讀操作,但重試會帶來更長延遲。

可通過retries="2"來設定重試次數(不含第一次)。

Failfast Cluster

快速失敗,只發起一次呼叫,失敗立即報錯。

通常用於非冪等性的寫操作,比如新增記錄。

Failsafe Cluster

失敗安全,出現異常時,直接忽略。

通常用於寫入審計日誌等操作。

Failback Cluster

失敗自動恢復,後臺記錄失敗請求,定時重發。

通常用於訊息通知操作。

Forking Cluster

並行呼叫多個伺服器,只要一個成功即返回。

通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。

可通過forks="2"來設定最大並行數。

Broadcast Cluster

廣播呼叫所有提供者,逐個呼叫,任意一臺報錯則報錯。(2.1.0開始支援)

通常用於通知所有提供者更新快取或日誌等本地資源資訊。

重試次數配置如:(failover叢集模式生效)


<dubbo:service

retries="2"

/>

或:

<dubbo:reference

retries="2"

/>

或:


<dubbo:reference>


<dubbo:method

name="findFoo"

retries="2"

/>
</dubbo:reference>

叢集模式配置如:

<dubbo:service

cluster="failsafe"

/>

或:

<dubbo:reference

cluster="failsafe"

/>

負載均衡

在叢集負載均衡時,Dubbo提供了多種均衡策略,預設為random隨機呼叫。

Random LoadBalance

隨機,按權重設定隨機概率。

在一個截面上碰撞的概率高,但呼叫量越大分佈越均勻,而且按概率使用權重後也比較均勻,有利於動態調整提供者權重。

RoundRobin LoadBalance

輪循,按公約後的權重設定輪循比率。

存在慢的提供者累積請求問題,比如:第二臺機器很慢,但沒掛,當請求調到第二臺時就卡在那,久而久之,所有請求都卡在調到第二臺上。

LeastActive LoadBalance

最少活躍呼叫數,相同活躍數的隨機,活躍數指呼叫前後計數差。

使慢的提供者收到更少請求,因為越慢的提供者的呼叫前後計數差會越大。

ConsistentHash LoadBalance

一致性Hash,相同引數的請求總是發到同一提供者。

當某一臺提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其它提供者,不會引起劇烈變動。

演算法參見:http://en.wikipedia.org/wiki/Consistent_hashing。

預設只對第一個引數Hash,如果要修改,請配置<dubbo:parameter key="hash.arguments" value="0,1" />

預設用160份虛擬節點,如果要修改,請配置<dubbo:parameter key="hash.nodes" value="320" />

配置如:

<dubbo:service

interface="..."

loadbalance="roundrobin"

/>

或:

<dubbo:reference

interface="..."

loadbalance="roundrobin"

/>

或:

<dubbo:service

interface="...">


<dubbo:method

name="..."

loadbalance="roundrobin"/>


</dubbo:service>

或:

<dubbo:reference

interface="...">


<dubbo:method

name="..."

loadbalance="roundrobin"/>


</dubbo:reference>

執行緒模型

件處理執行緒說明

如果事件處理的邏輯能迅速完成,並且不會發起新的IO請求,比如只是在記憶體中記個標識,則直接在IO執行緒上處理更快,因為減少了執行緒池排程。

但如果事件處理邏輯較慢,或者需要發起新的IO請求,比如需要查詢資料庫,則必須派發到執行緒池,否則IO執行緒阻塞,將導致不能接收其它請求。

如果用IO執行緒處理事件,又在事件處理過程中發起新的IO請求,比如在連線事件中發起登入請求,會報“可能引發死鎖”異常,但不會真死鎖。

Dispatcher

all 所有訊息都派發到執行緒池,包括請求,響應,連線事件,斷開事件,心跳等。

direct 所有訊息都不派發到執行緒池,全部在IO執行緒上直接執行。

message 只有請求響應訊息派發到執行緒池,其它連線斷開事件,心跳等訊息,直接在IO執行緒上執行。

execution 只請求訊息派發到執行緒池,不含響應,響應和其它連線斷開事件,心跳等訊息,直接在IO執行緒上執行。

connection 在IO執行緒上,將連線斷開事件放入佇列,有序逐個執行,其它訊息派發到執行緒池。

ThreadPool

fixed 固定大小執行緒池,啟動時建立執行緒,不關閉,一直持有。(預設)

cached 快取執行緒池,空閒一分鐘自動刪除,需要時重建。

limited 可伸縮執行緒池,但池中的執行緒數只會增長不會收縮。(為避免收縮時突然來了大流量引起的效能問題)。

配置如:

<dubbo:protocol

name="dubbo"

dispatcher="all"

threadpool="fixed"

threads="100"

/>

直連提供者

在開發及測試環境下,經常需要繞過註冊中心,只測試指定服務提供者,這時候可能需要點對點直連,點對點直聯方式,將以服務介面為單位,忽略註冊中心的提供者列表,A介面配置點對點,不影響B介面從註冊中心獲取列表。

(1) 如果是線上需求需要點對點,可在<dubbo:reference>中配置url指向提供者,將繞過註冊中心,多個地址用分號隔開,配置如下:(1.0.6及以上版本支援)

<dubbo:reference
id="xxxService"

interface="com.alibaba.xxx.XxxService"

url="dubbo://localhost:20890"

/>

(2) 在JVM啟動引數中加入-D引數對映服務地址,如:

(key為服務名,value為服務提供者url,此配置優先順序最高,1.0.15及以上版本支援)

java
-Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890

注意

為了避免複雜化線上環境,不要線上上使用這個功能,只應在測試階段使用。

(3) 如果服務比較多,也可以用檔案對映,如:

(用-Ddubbo.resolve.file指定對映檔案路徑,此配置優先順序高於<dubbo:reference>中的配置,1.0.15及以上版本支援)

(2.0以上版本自動載入${user.home}/dubbo-resolve.properties檔案,不需要配置)

java
-Ddubbo.resolve.file=xxx.properties

然後在對映檔案xxx.properties中加入:(key為服務名,value為服務提供者url)

com.alibaba.xxx.XxxService=dubbo://localhost:20890

注意

為了避免複雜化線上環境,不要線上上使用這個功能,只應在測試階段使用。

只訂閱

問題

為方便開發測試,經常會線上下共用一個所有服務可用的註冊中心,這時,如果一個正在開發中的服務提供者註冊,可能會影響消費者不能正常執行。

解決方案

可以讓服務提供者開發方,只訂閱服務(開發的服務可能依賴其它服務),而不註冊正在開發的服務,通過直連測試正在開發的服務。

禁用註冊配置:

<dubbo:registry

address="10.20.153.10:9090"

register="false"

/>

或者:

<dubbo:registry

address="10.20.153.10:9090?register=false"

/>

只註冊

問題

如果有兩個映象環境,兩個註冊中心,有一個服務只在其中一個註冊中心有部署,另一個註冊中心還沒來得及部署,而兩個註冊中心的其它應用都需要依賴此服務,所以需要將服務同時註冊到兩個註冊中心,但卻不能讓此服務同時依賴兩個註冊中心的其它服務。

解決方案

可以讓服務提供者方,只註冊服務到另一註冊中心,而不從另一註冊中心訂閱服務。

禁用訂閱配置:

<dubbo:registry

id="hzRegistry"

address="10.20.153.10:9090"

/>
<dubbo:registry

id="qdRegistry"

address="10.20.141.150:9090"

subscribe="false"

/>

或者:

<dubbo:registry

id="hzRegistry"

address="10.20.153.10:9090"

/>
<dubbo:registry

id="qdRegistry"

address="10.20.141.150:9090?subscribe=false"

/>

靜態服務

有時候希望人工管理服務提供者的上線和下線,此時需將註冊中心標識為非動態管理模式。

<dubbo:registry

address="10.20.141.150:9090"

dynamic="false"

/>

或者:

<dubbo:registry

address="10.20.141.150:9090?dynamic=false"

/>

服務提供者初次註冊時為禁用狀態,需人工啟用,斷線時,將不會被自動刪除,需人工禁用。

如果是一個第三方獨立提供者,比如memcached等,可以直接向註冊中心寫入提供者地址資訊,消費者正常使用:(通常由指令碼監控中心頁面等呼叫)

RegistryFactory
registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry
registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf

("memcached://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo"));

多協議

(1) 不同服務不同協議

比如:不同服務在效能上適用不同協議進行傳輸,比如大資料用短連線協議,小資料大併發用長連線協議。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">

<dubbo:application name="world" />
<dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />

<!-- 多協議配置 -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="rmi" port="1099" />

<!-- 使用dubbo協議暴露服務 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" protocol="dubbo" />
<!-- 使用rmi協議暴露服務 -->
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" protocol="rmi" />

</beans>

(2) 多協議暴露服務

比如:需要與http客戶端互操作

consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <dubbo:application name="world" />
<dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />

<!-- 多協議配置 -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="hessian" port="8080" />

<!-- 使用多個協議暴露服務 -->
<dubbo:service id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" protocol="dubbo,hessian" />

</beans>

多註冊中心

(1) 多註冊中心註冊

比如:中文站有些服務來不及在青島部署,只在杭州部署,而青島的其它應用需要引用此服務,就可以將服務同時註冊到兩個註冊中心。

consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <dubbo:application name="world" />

<!-- 多註冊中心配置 -->
<dubbo:registry id="hangzhouRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="qingdaoRegistry" address="10.20.141.151:9010" default="false" />

<!-- 向多個註冊中心註冊 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="hangzhouRegistry,qingdaoRegistry" />

</beans>

(2) 不同服務使用不同註冊中心

比如:CRM有些服務是專門為國際站設計的,有些服務是專門為中文站設計的。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <dubbo:application name="world" />

<!-- 多註冊中心配置 -->
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />

<!-- 向中文站註冊中心註冊 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="chinaRegistry" />

<!-- 向國際站註冊中心註冊 -->
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" registry="intlRegistry" />

</beans>

(3) 多註冊中心引用

比如:CRM需同時呼叫中文站和國際站的PC2服務,PC2在中文站和國際站均有部署,介面及版本號都一樣,但連的資料庫不一樣。

consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <dubbo:application name="world" />

<!-- 多註冊中心配置 -->
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />

<!-- 引用中文站服務 -->
<dubbo:reference id="chinaHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="chinaRegistry" />

<!-- 引用國際站站服務 -->
<dubbo:reference id="intlHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="intlRegistry" />

</beans>

如果只是測試環境臨時需要連線兩個不同註冊中心,使用豎號分隔多個不同註冊中心地址:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">

<dubbo:application name="world" />

<!-- 多註冊中心配置,豎號分隔表示同時連線多個不同註冊中心, 同一註冊中心的多個叢集地址用逗號分隔 -->
<dubbo:registry address="10.20.141.150:9090|10.20.154.177:9010" />

<!-- 引用服務 -->
<dubbo:reference id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" />

</beans>

服務分組

當一個介面有多種實現時,可以用group區分。

<dubbo:service

group="feedback"

interface="com.xxx.IndexService"

/>
<dubbo:service

group="member"

interface="com.xxx.IndexService"

/>

任意組:(2.2.0以上版本支援,總是隻調一個可用組的實現)

<dubbo:reference

id="feedbackIndexService"

group="feedback"

interface="com.xxx.IndexService"

/>
<dubbo:reference

id="memberIndexService"

group="member"

interface="com.xxx.IndexService"

/>

 

多版本

當一個介面實現,出現不相容升級時,可以用版本號過渡,版本號不同的服務相互間不引用。

在低壓力時間段,先升級一半提供者為新版本

再將所有消費者升級為新版本

然後將剩下的一半提供者升級為新版本

<dubbo:service

interface="com.foo.BarService"

version="1.0.0"

/>

 

<dubbo:service

interface="com.foo.BarService"

version="2.0.0"

/>

 

<dubbo:reference

id="barService"

interface="com.foo.BarService"

version="1.0.0"

/>

 

<dubbo:reference

id="barService"

interface="com.foo.BarService"

version="2.0.0"

/>

不區分版本:(2.2.0以上版本支援)

<dubbo:reference

id="barService"

interface="com.foo.BarService"

version="*"

/>

分組聚合

按組合並返回結果,比如選單服務,介面一樣,但有多種實現,用group區分,現在消費方需從每種group中呼叫一次返回結果,合併結果返回,這樣就可以實現聚合選單項。

從2.1.0版本開始支援

程式碼參見:https://github.com/alibaba/dubbo/tree/master/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/merge

配置如:(搜尋所有分組)

<dubbo:reference

interface="com.xxx.MenuService"

group="*"

merger="true"

/>

或:(合併指定分組)

<dubbo:reference

interface="com.xxx.MenuService"

group="aaa,bbb"

merger="true"

/>

或:(指定方法合併結果,其它未指定的方法,將只呼叫一個Group)

<dubbo:reference

interface="com.xxx.MenuService"

group="*">
<dubbo:method

name="getMenuItems"

merger="true"

/>
</dubbo:service>

或:(某個方法不合並結果,其它都合併結果)

<dubbo:reference

interface="com.xxx.MenuService"

group="*"

merger="true">
<dubbo:method

name="getMenuItems"

merger="false"

/>
</dubbo:service>

或:(指定合併策略,預設根據返回值型別自動匹配,如果同一型別有兩個合併器時,需指定合併器的名稱)

參見:[合併結果擴充套件]

<dubbo:reference

interface="com.xxx.MenuService"

group="*">
<dubbo:method

name="getMenuItems"

merger="mymerge"

/>
</dubbo:service>

或:(指定合併方法,將呼叫返回結果的指定方法進行合併,合併方法的引數型別必須是返回結果型別本身)

<dubbo:reference

interface="com.xxx.MenuService"

group="*">
<dubbo:method

name="getMenuItems"

merger=".addAll"

/>
</dubbo:service>

引數驗證

引數驗證功能是基於JSR303實現的,使用者只需標識JSR303標準的驗證Annotation,並通過宣告filter來實現驗證。

2.1.0以上版本支援

完整示例程式碼參見:https://github.com/alibaba/dubbo/tree/master/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/validation

驗證方式可擴充套件,參見:Validation擴充套件點

引數標註示例:

import

java.io.Serializable;
import

java.util.Date;
import

javax.validation.constraints.Future;
import

javax.validation.constraints.Max;
import

javax.validation.constraints.Min;
import

javax.validation.constraints.NotNull;
import

javax.validation.constraints.Past;
import

javax.validation.constraints.Pattern;
import

javax.validation.constraints.Size;
public

class 
ValidationParameter implements

Serializable {
private

static 
final 
long 
serialVersionUID = 7158911668568000392L;
@NotNull

// 不允許為空
@Size(min
= 1,
max = 20)
//
長度或大小範圍
private

String name;
@NotNull(groups
= ValidationService.Save.class)
//
儲存時不允許為空,更新時允許為空 ,表示不更新該欄位
@Pattern(regexp
= "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$")
private

String email;
@Min(18)
//
最小值
@Max(100)
//
最大值
private

int 
age;
@Past

// 必須為一個過去的時間
private

Date loginDate;
@Future

// 必須為一個未來的時間
private

Date expiryDate;
public

String getName() {
return

name;
}
public

void 
setName(String name) {
this.name
= name;
}
public

String getEmail() {
return

email;
}
public

void 
setEmail(String email) {
this.email
= email;


}
public

int 
getAge() {
return

age;
}
public

void 
setAge(int

age) {
this.age
= age;
}
public

Date getLoginDate() {
return

loginDate;
}
public

void 
setLoginDate(Date loginDate) {
this.loginDate
= loginDate;
}
public

Date getExpiryDate() {
return

expiryDate;
}
public

void 
setExpiryDate(Date expiryDate) {
this.expiryDate
= expiryDate;
}
}

分組驗證示例:

public

interface 
ValidationService { //
預設可按服務介面區分驗證場景,如:@NotNull(groups = ValidationService.class)
@interface

Save{} //
與方法同名介面,首字母大寫,用於區分驗證場景,如:@NotNull(groups = ValidationService.Save.class),可選
void

save(ValidationParameter parameter);
void

update(ValidationParameter parameter);
}

分組驗證示例:

import

javax.validation.GroupSequence;

public

interface 
ValidationService {

@GroupSequence(Update.class)
//
同時驗證Update組規則

@interface

Save{}


void

save(ValidationParameter parameter);

@interface

Update{}


void

update(ValidationParameter parameter);

}

引數驗證示例:

import

javax.validation.constraints.Min;
import

javax.validation.constraints.NotNull;
public

interface 
ValidationService {
void

save(@NotNull

ValidationParameter parameter); //
驗證引數不為空
void

delete(@Min(1)
int

id); //
直接對基本型別引數驗證
}

在客戶端驗證引數:

<dubbo:reference

id="validationService"

interface="com.alibaba.dubbo.examples.validation.api.ValidationService"

validation="true"

/>

在伺服器端驗證引數:

<dubbo:service

interface="com.alibaba.dubbo.examples.validation.api.ValidationService"

ref="validationService"

validation="true"

/>

驗證異常資訊:

import

javax.validation.ConstraintViolationException;
import

javax.validation.ConstraintViolationException;
import

org.springframework.context.support.ClassPathXmlApplicationContext;
import

com.alibaba.dubbo.examples.validation.api.ValidationParameter;
import

com.alibaba.dubbo.examples.validation.api.ValidationService;
import

com.alibaba.dubbo.rpc.RpcException;
public

class 
ValidationConsumer {
public

static 
void 
main(String[] args) throws

Exception {
String
config = ValidationConsumer.class.getPackage().getName().replace('.',
'/')
+ "/validation-consumer.xml";


ClassPathXmlApplicationContext
context = new

ClassPathXmlApplicationContext(config);
context.start();
ValidationService
validationService = (ValidationService)context.getBean("validationService");


//
Error
try

{
parameter
= new

ValidationParameter();
validationService.save(parameter);
System.out.println("Validation
ERROR");
}
catch

(RpcException e) { //
丟擲的是RpcException
ConstraintViolationException
ve = (ConstraintViolationException) e.getCause(); //
裡面嵌了一個ConstraintViolationException
Set<ConstraintViolation<?>>
violations = ve.getConstraintViolations(); //
可以拿到一個驗證錯誤詳細資訊的集合
System.out.println(violations);
}
}
}

需要加入依賴:

 

<dependency>

<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
</dependency>

相關文章