diff --git a/.gitignore b/.gitignore
index f369c2833aeacbff3aa85a6cd1cdc25520928209..e5ba291004ab0d89c1ef1db6f353361232fddcc8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,4 @@ coverage.txt
 remoting/zookeeper/zookeeper-4unittest/
 config_center/zookeeper/zookeeper-4unittest/
 registry/zookeeper/zookeeper-4unittest/
+registry/consul/agent*
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index ea6b2035584ba07ae7caa709f83be59cf20c730e..707e64481416b2c090bad05cddce2b3ccebf4535 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,3 +18,6 @@ script:
 
 after_success:
   - bash <(curl -s https://codecov.io/bash)
+
+notifications:
+  webhooks: https://oapi.dingtalk.com/robot/send?access_token=f5d6237f2c79db584e75604f7f88db1ce1673c8c0e98451217b28fde791e1d4f
\ No newline at end of file
diff --git a/CHANGE.md b/CHANGE.md
index cdfca4fb6d5d7106ed0c56e40cf40647607c3015..947a695ca854fe8c3d91d8ea989b52dcddbe1523 100644
--- a/CHANGE.md
+++ b/CHANGE.md
@@ -1,5 +1,43 @@
 # Release Notes
 
+## 1.2.0
+
+### New Features
+
+- Add etcdv3 registry support<https://github.com/apache/dubbo-go/pull/148>
+- Add nacos registry support<https://github.com/apache/dubbo-go/pull/151>
+- Add fail fast cluster support<https://github.com/apache/dubbo-go/pull/140>
+- Add available cluster support<https://github.com/apache/dubbo-go/pull/155>
+- Add broadcast cluster support<https://github.com/apache/dubbo-go/pull/158>
+- Add forking cluster support<https://github.com/apache/dubbo-go/pull/161>
+- Add service token authorization support<https://github.com/apache/dubbo-go/pull/202>
+- Add accessLog filter support<https://github.com/apache/dubbo-go/pull/214>
+- Add tps limit support<https://github.com/apache/dubbo-go/pull/237>
+- Add execute limit support<https://github.com/apache/dubbo-go/pull/246>
+- Move callService to invoker & support attachments<https://github.com/apache/dubbo-go/pull/193>
+- Move example in dubbo-go project away<https://github.com/apache/dubbo-go/pull/228>
+- Support dynamic config center which compatible with dubbo 2.6.x & 2.7.x and commit the zookeeper impl<https://github.com/apache/dubbo-go/pull/194>
+
+### Enhancement
+
+- Split gettyRPCClient.close and gettyRPCClientPool.remove in protocol/dubbo/pool.go<https://github.com/apache/dubbo-go/pull/186>
+- Remove client from pool before closing it<https://github.com/apache/dubbo-go/pull/190>
+- Enhance the logic for fetching the local address<https://github.com/apache/dubbo-go/pull/209>
+- Add protocol_conf default values<https://github.com/apache/dubbo-go/pull/221>
+- Add task pool for getty<https://github.com/apache/dubbo-go/pull/141>
+- Update getty: remove read queue<https://github.com/apache/dubbo-go/pull/137>
+- Clean heartbeat from PendingResponse<https://github.com/apache/dubbo-go/pull/166>
+
+### Bugfixes
+
+- GettyRPCClientPool remove deadlock<https://github.com/apache/dubbo-go/pull/183/files>
+- Fix failover cluster bug and url parameter retries change int to string type<https://github.com/apache/dubbo-go/pull/195>
+- Fix url params unsafe map<https://github.com/apache/dubbo-go/pull/201>
+- Read protocol config by map key in config yaml instead of protocol name<https://github.com/apache/dubbo-go/pull/218>
+- Fix dubbo group issues #238<https://github.com/apache/dubbo-go/pull/243>/<https://github.com/apache/dubbo-go/pull/244>
+- Fix bug in reference_config<https://github.com/apache/dubbo-go/pull/157>
+- Fix high memory bug in zookeeper listener<https://github.com/apache/dubbo-go/pull/168>
+
 ## 1.1.0
 
 ### New Features
diff --git a/LICENSE b/LICENSE
index e76f9d9dd705daad997776153b1060f5bf8c2a1d..75b52484ea471f882c29e02693b4f02dba175b5e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -176,6 +176,19 @@
 
    END OF TERMS AND CONDITIONS
 
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
diff --git a/NOTICE b/NOTICE
index a9bd809c5c43a9d88a773b5f0c421b252abf38de..d7aa899d1cef0fba67826bebd0d587e9cc17ba5d 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
 Apache Dubbo Go
-Copyright 2018-2019 The Apache Software Foundation
+Copyright 2018-2020 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.md b/README.md
index fdc3062d6f086be14ad19b1f718f713c54fb48ed..f387b934e25e0b19c6d4c6cb9b23548344c3d543 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,11 @@ Finished List:
     * JsonRPC V2
     * Hessian V2
     
+- Protocol
+    * Dubbo
+    * Jsonrpc2.0
+    * [gRPC](https://github.com/apache/dubbo-go/pull/311)
+    
 - Registry
     * ZooKeeper
     * [etcd v3](https://github.com/apache/dubbo-go/pull/148)
@@ -73,6 +78,7 @@ Finished List:
     * [AccessLogFilter](https://github.com/apache/dubbo-go/pull/214)
     * [TpsLimitFilter](https://github.com/apache/dubbo-go/pull/237)
     * [ExecuteLimitFilter](https://github.com/apache/dubbo-go/pull/246)
+    * [GenericServiceFilter](https://github.com/apache/dubbo-go/pull/291)
     
 - Invoke
     * [generic invoke](https://github.com/apache/dubbo-go/pull/122)
@@ -98,11 +104,11 @@ You can know more about dubbo-go by its [roadmap](https://github.com/apache/dubb
 
 ## Document
 
-TODO
+https://dubbogo.github.io/dubbo-go-website (**Improving**)
 
 ## Quick Start
 
-[dubbogo-samples](https://github.com/dubbogo/dubbogo-samples) shows how to use dubbo-go. Please read the [dubbogo-samples/README.md](https://github.com/dubbogo/dubbogo-samples/blob/master/README.md) carefully to learn how to dispose the configuration and compile the program.
+[dubbo-samples/golang](https://github.com/dubbogo/dubbo-samples) shows how to use dubbo-go. Please read the [dubbo-samples/golang/README.md](https://github.com/dubbogo/dubbo-samples/blob/master/golang/README.md) carefully to learn how to dispose the configuration and compile the program.
 
 ## Running unit tests
 
diff --git a/README_CN.md b/README_CN.md
index edabe64d376cd4d49f6ab4251db9387aca48bbf0..22af253416017403eaad2579ff977c6925936d7a 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -41,6 +41,11 @@ Apache License, Version 2.0
 - 序列化协议
     * JsonRPC V2
     * Hessian V2
+
+- 协议
+    * Dubbo
+    * Jsonrpc2.0
+    * [gRPC](https://github.com/apache/dubbo-go/pull/311)
     
 - 注册中心
     * ZooKeeper
@@ -97,11 +102,11 @@ Apache License, Version 2.0
 
 ## 文档
 
-TODO
+https://dubbogo.github.io/dubbo-go-website (**完善中**)
 
 ## 快速开始 ##
 
-[dubbogo-samples](https://github.com/dubbogo/dubbogo-samples)这个项目的事例展示了如何使用 dubbo-go 。请仔细阅读 [dubbogo-samples/README.md](https://github.com/dubbogo/dubbogo-samples/blob/master/README.md) 学习如何处理配置并编译程序。
+[dubbo-samples/golang](https://github.com/dubbogo/dubbo-samples)这个项目的事例展示了如何使用 dubbo-go 。请仔细阅读 [dubbo-samples/golang/README.md](https://github.com/dubbogo/dubbo-samples/blob/master/golang/README.md) 学习如何处理配置并编译程序。
 
 ## 运行单测
 
diff --git a/cluster/cluster.go b/cluster/cluster.go
index d89df5a21954d63552b857d988fa9a9e7d1fcfb5..617ce5ebf0fa7b5dc7f6047caacec9865aa6960f 100644
--- a/cluster/cluster.go
+++ b/cluster/cluster.go
@@ -21,6 +21,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// Cluster ...
 type Cluster interface {
 	Join(Directory) protocol.Invoker
 }
diff --git a/cluster/cluster_impl/available_cluster.go b/cluster/cluster_impl/available_cluster.go
index 7e748cd938319ff437bb3fb6c7945b857d316069..2ad140b93e15b97d1517119b07b1080a68a0503f 100644
--- a/cluster/cluster_impl/available_cluster.go
+++ b/cluster/cluster_impl/available_cluster.go
@@ -31,6 +31,7 @@ func init() {
 	extension.SetCluster(available, NewAvailableCluster)
 }
 
+// NewAvailableCluster ...
 func NewAvailableCluster() cluster.Cluster {
 	return &availableCluster{}
 }
diff --git a/cluster/cluster_impl/available_cluster_invoker.go b/cluster/cluster_impl/available_cluster_invoker.go
index c59c0702c216fe5c58d190a023322aaa00ac9c17..6f6d2dffbbbf2f6c758097b11713ae0c1b6bd387 100644
--- a/cluster/cluster_impl/available_cluster_invoker.go
+++ b/cluster/cluster_impl/available_cluster_invoker.go
@@ -18,6 +18,7 @@ limitations under the License.
 package cluster_impl
 
 import (
+	"context"
 	"fmt"
 )
 
@@ -34,13 +35,14 @@ type availableClusterInvoker struct {
 	baseClusterInvoker
 }
 
+// NewAvailableClusterInvoker ...
 func NewAvailableClusterInvoker(directory cluster.Directory) protocol.Invoker {
 	return &availableClusterInvoker{
 		baseClusterInvoker: newBaseClusterInvoker(directory),
 	}
 }
 
-func (invoker *availableClusterInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (invoker *availableClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	invokers := invoker.directory.List(invocation)
 	err := invoker.checkInvokers(invokers, invocation)
 	if err != nil {
@@ -54,7 +56,7 @@ func (invoker *availableClusterInvoker) Invoke(invocation protocol.Invocation) p
 
 	for _, ivk := range invokers {
 		if ivk.IsAvailable() {
-			return ivk.Invoke(invocation)
+			return ivk.Invoke(ctx, invocation)
 		}
 	}
 	return &protocol.RPCResult{Err: errors.New(fmt.Sprintf("no provider available in %v", invokers))}
diff --git a/cluster/cluster_impl/available_cluster_invoker_test.go b/cluster/cluster_impl/available_cluster_invoker_test.go
index 04032a7f24dec0e73acb15921f753921391f1515..dc0666d5afa633c86fdfaa48b93a334c19bb0248 100644
--- a/cluster/cluster_impl/available_cluster_invoker_test.go
+++ b/cluster/cluster_impl/available_cluster_invoker_test.go
@@ -39,7 +39,7 @@ import (
 )
 
 var (
-	availableUrl, _ = common.NewURL(context.Background(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	availableUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
 )
 
 func registerAvailable(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker {
@@ -66,7 +66,7 @@ func TestAvailableClusterInvokerSuccess(t *testing.T) {
 	invoker.EXPECT().IsAvailable().Return(true)
 	invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
 
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 
 	assert.Equal(t, mockResult, result)
 }
@@ -80,7 +80,7 @@ func TestAvailableClusterInvokerNoAvail(t *testing.T) {
 
 	invoker.EXPECT().IsAvailable().Return(false)
 
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.TODO(), &invocation.RPCInvocation{})
 
 	assert.NotNil(t, result.Error())
 	assert.True(t, strings.Contains(result.Error().Error(), "no provider available"))
diff --git a/cluster/cluster_impl/base_cluster_invoker_test.go b/cluster/cluster_impl/base_cluster_invoker_test.go
index d06d3cc23e75cf2227fa22894475f141ffe09a96..49df78c41b3c3cc7dacf92153fc7e4515a0caec0 100644
--- a/cluster/cluster_impl/base_cluster_invoker_test.go
+++ b/cluster/cluster_impl/base_cluster_invoker_test.go
@@ -18,7 +18,6 @@
 package cluster_impl
 
 import (
-	"context"
 	"fmt"
 	"testing"
 )
@@ -37,7 +36,7 @@ import (
 func Test_StickyNormal(t *testing.T) {
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
 		url.SetParam("sticky", "true")
 		invokers = append(invokers, NewMockInvoker(url, 1))
 	}
@@ -51,7 +50,7 @@ func Test_StickyNormal(t *testing.T) {
 func Test_StickyNormalWhenError(t *testing.T) {
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
 		url.SetParam("sticky", "true")
 		invokers = append(invokers, NewMockInvoker(url, 1))
 	}
diff --git a/cluster/cluster_impl/broadcast_cluster.go b/cluster/cluster_impl/broadcast_cluster.go
index 50aae3cfab8d67570b50dcab4e53bbfad29d6d30..9b27a4ce37bc73e42b55e4e20deb9593fd837444 100644
--- a/cluster/cluster_impl/broadcast_cluster.go
+++ b/cluster/cluster_impl/broadcast_cluster.go
@@ -31,6 +31,7 @@ func init() {
 	extension.SetCluster(broadcast, NewBroadcastCluster)
 }
 
+// NewBroadcastCluster ...
 func NewBroadcastCluster() cluster.Cluster {
 	return &broadcastCluster{}
 }
diff --git a/cluster/cluster_impl/broadcast_cluster_invoker.go b/cluster/cluster_impl/broadcast_cluster_invoker.go
index 238df0acfa7fb946e38bfbfd490bce7c0bb34e60..1b49e9a115252d4eca94bedd557ebcc21fee4cc7 100644
--- a/cluster/cluster_impl/broadcast_cluster_invoker.go
+++ b/cluster/cluster_impl/broadcast_cluster_invoker.go
@@ -17,6 +17,9 @@ limitations under the License.
 
 package cluster_impl
 
+import (
+	"context"
+)
 import (
 	"github.com/apache/dubbo-go/cluster"
 	"github.com/apache/dubbo-go/common/logger"
@@ -33,7 +36,7 @@ func newBroadcastClusterInvoker(directory cluster.Directory) protocol.Invoker {
 	}
 }
 
-func (invoker *broadcastClusterInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (invoker *broadcastClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	invokers := invoker.directory.List(invocation)
 	err := invoker.checkInvokers(invokers, invocation)
 	if err != nil {
@@ -46,7 +49,7 @@ func (invoker *broadcastClusterInvoker) Invoke(invocation protocol.Invocation) p
 
 	var result protocol.Result
 	for _, ivk := range invokers {
-		result = ivk.Invoke(invocation)
+		result = ivk.Invoke(ctx, invocation)
 		if result.Error() != nil {
 			logger.Warnf("broadcast invoker invoke err: %v when use invoker: %v\n", result.Error(), ivk)
 			err = result.Error()
diff --git a/cluster/cluster_impl/broadcast_cluster_invoker_test.go b/cluster/cluster_impl/broadcast_cluster_invoker_test.go
index 565684a8ae25c648ff77aef71d2ced0665202fe7..1de5270265a79b4d1d62317730bd06927d939acd 100644
--- a/cluster/cluster_impl/broadcast_cluster_invoker_test.go
+++ b/cluster/cluster_impl/broadcast_cluster_invoker_test.go
@@ -39,7 +39,7 @@ import (
 )
 
 var (
-	broadcastUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	broadcastUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
 )
 
 func registerBroadcast(t *testing.T, mockInvokers ...*mock.MockInvoker) protocol.Invoker {
@@ -74,7 +74,7 @@ func Test_BroadcastInvokeSuccess(t *testing.T) {
 
 	clusterInvoker := registerBroadcast(t, invokers...)
 
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Equal(t, mockResult, result)
 }
 
@@ -104,6 +104,6 @@ func Test_BroadcastInvokeFailed(t *testing.T) {
 
 	clusterInvoker := registerBroadcast(t, invokers...)
 
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Equal(t, mockFailedResult.Err, result.Error())
 }
diff --git a/cluster/cluster_impl/failback_cluster.go b/cluster/cluster_impl/failback_cluster.go
index de22c78e947d0b8124add721ab7ff42efebcdbe4..76573571684c07f63609009f59ab0ac881ae1b50 100644
--- a/cluster/cluster_impl/failback_cluster.go
+++ b/cluster/cluster_impl/failback_cluster.go
@@ -31,6 +31,7 @@ func init() {
 	extension.SetCluster(failback, NewFailbackCluster)
 }
 
+// NewFailbackCluster ...
 func NewFailbackCluster() cluster.Cluster {
 	return &failbackCluster{}
 }
diff --git a/cluster/cluster_impl/failback_cluster_invoker.go b/cluster/cluster_impl/failback_cluster_invoker.go
index c8dbeda09f62e88b51dd4ad2b6b09d5715f0b224..46b0ff634e56c45223a5aeb5566b9b1401518960 100644
--- a/cluster/cluster_impl/failback_cluster_invoker.go
+++ b/cluster/cluster_impl/failback_cluster_invoker.go
@@ -18,6 +18,7 @@
 package cluster_impl
 
 import (
+	"context"
 	"strconv"
 	"sync"
 	"time"
@@ -71,7 +72,7 @@ func newFailbackClusterInvoker(directory cluster.Directory) protocol.Invoker {
 	return invoker
 }
 
-func (invoker *failbackClusterInvoker) process() {
+func (invoker *failbackClusterInvoker) process(ctx context.Context) {
 	invoker.ticker = time.NewTicker(time.Second * 1)
 	for range invoker.ticker.C {
 		// check each timeout task and re-run
@@ -102,7 +103,7 @@ func (invoker *failbackClusterInvoker) process() {
 
 				retryInvoker := invoker.doSelect(retryTask.loadbalance, retryTask.invocation, retryTask.invokers, invoked)
 				var result protocol.Result
-				result = retryInvoker.Invoke(retryTask.invocation)
+				result = retryInvoker.Invoke(ctx, retryTask.invocation)
 				if result.Error() != nil {
 					retryTask.lastInvoker = retryInvoker
 					invoker.checkRetry(retryTask, result.Error())
@@ -126,7 +127,7 @@ func (invoker *failbackClusterInvoker) checkRetry(retryTask *retryTimerTask, err
 	}
 }
 
-func (invoker *failbackClusterInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (invoker *failbackClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	invokers := invoker.directory.List(invocation)
 	err := invoker.checkInvokers(invokers, invocation)
 	if err != nil {
@@ -150,11 +151,11 @@ func (invoker *failbackClusterInvoker) Invoke(invocation protocol.Invocation) pr
 
 	ivk := invoker.doSelect(loadbalance, invocation, invokers, invoked)
 	//DO INVOKE
-	result = ivk.Invoke(invocation)
+	result = ivk.Invoke(ctx, invocation)
 	if result.Error() != nil {
 		invoker.once.Do(func() {
 			invoker.taskList = queue.New(invoker.failbackTasks)
-			go invoker.process()
+			go invoker.process(ctx)
 		})
 
 		taskLen := invoker.taskList.Len()
diff --git a/cluster/cluster_impl/failback_cluster_test.go b/cluster/cluster_impl/failback_cluster_test.go
index 1d2266cabebf591b09188fb723f02126a3f1e0ec..4571fccec59a2f995009f57c35b56ec5e1cb3ea6 100644
--- a/cluster/cluster_impl/failback_cluster_test.go
+++ b/cluster/cluster_impl/failback_cluster_test.go
@@ -41,7 +41,7 @@ import (
 )
 
 var (
-	failbackUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	failbackUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
 )
 
 // registerFailback register failbackCluster to cluster extension.
@@ -72,7 +72,7 @@ func Test_FailbackSuceess(t *testing.T) {
 	mockResult := &protocol.RPCResult{Rest: rest{tried: 0, success: true}}
 	invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
 
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Equal(t, mockResult, result)
 }
 
@@ -102,7 +102,7 @@ func Test_FailbackRetryOneSuccess(t *testing.T) {
 		return mockSuccResult
 	})
 
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 	assert.Equal(t, 0, len(result.Attachments()))
@@ -150,7 +150,7 @@ func Test_FailbackRetryFailed(t *testing.T) {
 	}
 
 	// first call should failed.
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 	assert.Equal(t, 0, len(result.Attachments()))
@@ -192,7 +192,7 @@ func Test_FailbackRetryFailed10Times(t *testing.T) {
 	}).Times(10)
 
 	for i := 0; i < 10; i++ {
-		result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+		result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 		assert.Nil(t, result.Error())
 		assert.Nil(t, result.Result())
 		assert.Equal(t, 0, len(result.Attachments()))
@@ -222,14 +222,14 @@ func Test_FailbackOutOfLimit(t *testing.T) {
 	invoker.EXPECT().Invoke(gomock.Any()).Return(mockFailedResult).Times(11)
 
 	// reached limit
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 	assert.Equal(t, 0, len(result.Attachments()))
 
 	// all will be out of limit
 	for i := 0; i < 10; i++ {
-		result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+		result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 		assert.Nil(t, result.Error())
 		assert.Nil(t, result.Result())
 		assert.Equal(t, 0, len(result.Attachments()))
diff --git a/cluster/cluster_impl/failfast_cluster.go b/cluster/cluster_impl/failfast_cluster.go
index 6301d945626103226132b433dd21e8647f53a38b..e0b80ded041cd30b379857ff00d307811e53765d 100644
--- a/cluster/cluster_impl/failfast_cluster.go
+++ b/cluster/cluster_impl/failfast_cluster.go
@@ -31,6 +31,7 @@ func init() {
 	extension.SetCluster(failfast, NewFailFastCluster)
 }
 
+// NewFailFastCluster ...
 func NewFailFastCluster() cluster.Cluster {
 	return &failfastCluster{}
 }
diff --git a/cluster/cluster_impl/failfast_cluster_invoker.go b/cluster/cluster_impl/failfast_cluster_invoker.go
index 734ea2c6cb19bf54a338a76a10c9cfcc59d3954b..49e7c7689f5a19a36154e092a6a83cc39da604ba 100644
--- a/cluster/cluster_impl/failfast_cluster_invoker.go
+++ b/cluster/cluster_impl/failfast_cluster_invoker.go
@@ -17,6 +17,9 @@ limitations under the License.
 
 package cluster_impl
 
+import (
+	"context"
+)
 import (
 	"github.com/apache/dubbo-go/cluster"
 	"github.com/apache/dubbo-go/protocol"
@@ -32,7 +35,7 @@ func newFailFastClusterInvoker(directory cluster.Directory) protocol.Invoker {
 	}
 }
 
-func (invoker *failfastClusterInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (invoker *failfastClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	invokers := invoker.directory.List(invocation)
 	err := invoker.checkInvokers(invokers, invocation)
 	if err != nil {
@@ -47,5 +50,5 @@ func (invoker *failfastClusterInvoker) Invoke(invocation protocol.Invocation) pr
 	}
 
 	ivk := invoker.doSelect(loadbalance, invocation, invokers, nil)
-	return ivk.Invoke(invocation)
+	return ivk.Invoke(ctx, invocation)
 }
diff --git a/cluster/cluster_impl/failfast_cluster_test.go b/cluster/cluster_impl/failfast_cluster_test.go
index 1a4342e6c2b74fd6b1359646eeb463bb6dc17d0a..38e258199e05c396e22118337bbdb3ae2b955bd0 100644
--- a/cluster/cluster_impl/failfast_cluster_test.go
+++ b/cluster/cluster_impl/failfast_cluster_test.go
@@ -39,7 +39,7 @@ import (
 )
 
 var (
-	failfastUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	failfastUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
 )
 
 // registerFailfast register failfastCluster to cluster extension.
@@ -69,7 +69,7 @@ func Test_FailfastInvokeSuccess(t *testing.T) {
 	mockResult := &protocol.RPCResult{Rest: rest{tried: 0, success: true}}
 
 	invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 
 	assert.NoError(t, result.Error())
 	res := result.Result().(rest)
@@ -89,7 +89,7 @@ func Test_FailfastInvokeFail(t *testing.T) {
 	mockResult := &protocol.RPCResult{Err: perrors.New("error")}
 
 	invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 
 	assert.NotNil(t, result.Error())
 	assert.Equal(t, "error", result.Error().Error())
diff --git a/cluster/cluster_impl/failover_cluster.go b/cluster/cluster_impl/failover_cluster.go
index 0f1aa0371f57df5414a04a59e2a6772a4cd382b3..b16be3bafd43c7de8e2fadd109a73a3ea710e225 100644
--- a/cluster/cluster_impl/failover_cluster.go
+++ b/cluster/cluster_impl/failover_cluster.go
@@ -31,6 +31,7 @@ func init() {
 	extension.SetCluster(name, NewFailoverCluster)
 }
 
+// NewFailoverCluster ...
 func NewFailoverCluster() cluster.Cluster {
 	return &failoverCluster{}
 }
diff --git a/cluster/cluster_impl/failover_cluster_invoker.go b/cluster/cluster_impl/failover_cluster_invoker.go
index dcce7369931a11f31fb6b9e4e1a6c0aa0ec7cdf6..6178a05a1226ba629d2456ad6886b02a26288e45 100644
--- a/cluster/cluster_impl/failover_cluster_invoker.go
+++ b/cluster/cluster_impl/failover_cluster_invoker.go
@@ -18,6 +18,7 @@
 package cluster_impl
 
 import (
+	"context"
 	"strconv"
 )
 
@@ -43,7 +44,7 @@ func newFailoverClusterInvoker(directory cluster.Directory) protocol.Invoker {
 	}
 }
 
-func (invoker *failoverClusterInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (invoker *failoverClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 
 	invokers := invoker.directory.List(invocation)
 	err := invoker.checkInvokers(invokers, invocation)
@@ -95,7 +96,7 @@ func (invoker *failoverClusterInvoker) Invoke(invocation protocol.Invocation) pr
 		}
 		invoked = append(invoked, ivk)
 		//DO INVOKE
-		result = ivk.Invoke(invocation)
+		result = ivk.Invoke(ctx, invocation)
 		if result.Error() != nil {
 			providers = append(providers, ivk.GetUrl().Key())
 			continue
diff --git a/cluster/cluster_impl/failover_cluster_test.go b/cluster/cluster_impl/failover_cluster_test.go
index 78b799320dfa58d55e531c658ec5eb0e69306cff..99c584bb583c1d59ece505feafd74ad6e11f6b9a 100644
--- a/cluster/cluster_impl/failover_cluster_test.go
+++ b/cluster/cluster_impl/failover_cluster_test.go
@@ -39,9 +39,9 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-/////////////////////////////
+// ///////////////////////////
 // mock invoker
-/////////////////////////////
+// ///////////////////////////
 
 type MockInvoker struct {
 	url       common.URL
@@ -77,10 +77,12 @@ type rest struct {
 	success bool
 }
 
-func (bi *MockInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (bi *MockInvoker) Invoke(c context.Context, invocation protocol.Invocation) protocol.Result {
 	count++
-	var success bool
-	var err error = nil
+	var (
+		success bool
+		err     error
+	)
 	if count >= bi.successCount {
 		success = true
 	} else {
@@ -105,16 +107,16 @@ func normalInvoke(t *testing.T, successCount int, urlParam url.Values, invocatio
 
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i), common.WithParams(urlParam))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i), common.WithParams(urlParam))
 		invokers = append(invokers, NewMockInvoker(url, successCount))
 	}
 
 	staticDir := directory.NewStaticDirectory(invokers)
 	clusterInvoker := failoverCluster.Join(staticDir)
 	if len(invocations) > 0 {
-		return clusterInvoker.Invoke(invocations[0])
+		return clusterInvoker.Invoke(context.Background(), invocations[0])
 	}
-	return clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	return clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 }
 func Test_FailoverInvokeSuccess(t *testing.T) {
 	urlParams := url.Values{}
@@ -155,14 +157,14 @@ func Test_FailoverDestroy(t *testing.T) {
 
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
 		invokers = append(invokers, NewMockInvoker(url, 1))
 	}
 
 	staticDir := directory.NewStaticDirectory(invokers)
 	clusterInvoker := failoverCluster.Join(staticDir)
 	assert.Equal(t, true, clusterInvoker.IsAvailable())
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.NoError(t, result.Error())
 	count = 0
 	clusterInvoker.Destroy()
diff --git a/cluster/cluster_impl/failsafe_cluster.go b/cluster/cluster_impl/failsafe_cluster.go
index 3ff97d25eae80980a90a03e71865bb8f9a63defe..177d24a585b5f72fb0667215beb8d11147cc2922 100644
--- a/cluster/cluster_impl/failsafe_cluster.go
+++ b/cluster/cluster_impl/failsafe_cluster.go
@@ -31,6 +31,7 @@ func init() {
 	extension.SetCluster(failsafe, NewFailsafeCluster)
 }
 
+// NewFailsafeCluster ...
 func NewFailsafeCluster() cluster.Cluster {
 	return &failsafeCluster{}
 }
diff --git a/cluster/cluster_impl/failsafe_cluster_invoker.go b/cluster/cluster_impl/failsafe_cluster_invoker.go
index b95f997fef87cf466f07c4e506e41758e7998e52..4d8fe27719eb71fa287fe4142d8e92ca17acfba4 100644
--- a/cluster/cluster_impl/failsafe_cluster_invoker.go
+++ b/cluster/cluster_impl/failsafe_cluster_invoker.go
@@ -17,6 +17,9 @@
 
 package cluster_impl
 
+import (
+	"context"
+)
 import (
 	"github.com/apache/dubbo-go/cluster"
 	"github.com/apache/dubbo-go/common/constant"
@@ -42,7 +45,7 @@ func newFailsafeClusterInvoker(directory cluster.Directory) protocol.Invoker {
 	}
 }
 
-func (invoker *failsafeClusterInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (invoker *failsafeClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	invokers := invoker.directory.List(invocation)
 
 	err := invoker.checkInvokers(invokers, invocation)
@@ -65,7 +68,7 @@ func (invoker *failsafeClusterInvoker) Invoke(invocation protocol.Invocation) pr
 
 	ivk := invoker.doSelect(loadbalance, invocation, invokers, invoked)
 	//DO INVOKE
-	result = ivk.Invoke(invocation)
+	result = ivk.Invoke(ctx, invocation)
 	if result.Error() != nil {
 		// ignore
 		logger.Errorf("Failsafe ignore exception: %v.\n", result.Error().Error())
diff --git a/cluster/cluster_impl/failsafe_cluster_test.go b/cluster/cluster_impl/failsafe_cluster_test.go
index 7888b97c3a02bd4679f8ec5267637b8d2a7c12e4..2e35de8da91cc78730b6380bf039f0626ca75ec0 100644
--- a/cluster/cluster_impl/failsafe_cluster_test.go
+++ b/cluster/cluster_impl/failsafe_cluster_test.go
@@ -39,11 +39,11 @@ import (
 )
 
 var (
-	failsafeUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	failsafeUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
 )
 
-// register_failsafe register failsafeCluster to cluster extension.
-func register_failsafe(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker {
+// registerFailsafe register failsafeCluster to cluster extension.
+func registerFailsafe(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker {
 	extension.SetLoadbalance("random", loadbalance.NewRandomLoadBalance)
 	failsafeCluster := NewFailsafeCluster()
 
@@ -62,14 +62,14 @@ func Test_FailSafeInvokeSuccess(t *testing.T) {
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := register_failsafe(t, invoker)
+	clusterInvoker := registerFailsafe(t, invoker)
 
 	invoker.EXPECT().GetUrl().Return(failsafeUrl).AnyTimes()
 
 	mockResult := &protocol.RPCResult{Rest: rest{tried: 0, success: true}}
 
 	invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 
 	assert.NoError(t, result.Error())
 	res := result.Result().(rest)
@@ -81,14 +81,14 @@ func Test_FailSafeInvokeFail(t *testing.T) {
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := register_failsafe(t, invoker)
+	clusterInvoker := registerFailsafe(t, invoker)
 
 	invoker.EXPECT().GetUrl().Return(failsafeUrl).AnyTimes()
 
 	mockResult := &protocol.RPCResult{Err: perrors.New("error")}
 
 	invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 
 	assert.NoError(t, result.Error())
 	assert.Nil(t, result.Result())
diff --git a/cluster/cluster_impl/forking_cluster.go b/cluster/cluster_impl/forking_cluster.go
index 0a3c2b313ff3c4e89e592af9256fc42713419914..6b0572b15088e86870b3d9fd911a1d0b022378be 100644
--- a/cluster/cluster_impl/forking_cluster.go
+++ b/cluster/cluster_impl/forking_cluster.go
@@ -31,6 +31,7 @@ func init() {
 	extension.SetCluster(forking, NewForkingCluster)
 }
 
+// NewForkingCluster ...
 func NewForkingCluster() cluster.Cluster {
 	return &forkingCluster{}
 }
diff --git a/cluster/cluster_impl/forking_cluster_invoker.go b/cluster/cluster_impl/forking_cluster_invoker.go
index d6cf2f4b89ab4f322fa758deecae90c60742ef49..058d7fefd6edf6c43e5eda4b8f2f6a9c161189e2 100644
--- a/cluster/cluster_impl/forking_cluster_invoker.go
+++ b/cluster/cluster_impl/forking_cluster_invoker.go
@@ -18,7 +18,7 @@ limitations under the License.
 package cluster_impl
 
 import (
-	"errors"
+	"context"
 	"fmt"
 	"time"
 )
@@ -44,7 +44,8 @@ func newForkingClusterInvoker(directory cluster.Directory) protocol.Invoker {
 	}
 }
 
-func (invoker *forkingClusterInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+// Invoke ...
+func (invoker *forkingClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	err := invoker.checkWhetherDestroyed()
 	if err != nil {
 		return &protocol.RPCResult{Err: err}
@@ -75,7 +76,7 @@ func (invoker *forkingClusterInvoker) Invoke(invocation protocol.Invocation) pro
 	resultQ := queue.New(1)
 	for _, ivk := range selected {
 		go func(k protocol.Invoker) {
-			result := k.Invoke(invocation)
+			result := k.Invoke(ctx, invocation)
 			err := resultQ.Put(result)
 			if err != nil {
 				logger.Errorf("resultQ put failed with exception: %v.\n", err)
@@ -86,14 +87,18 @@ func (invoker *forkingClusterInvoker) Invoke(invocation protocol.Invocation) pro
 	rsps, err := resultQ.Poll(1, time.Millisecond*time.Duration(timeouts))
 	if err != nil {
 		return &protocol.RPCResult{
-			Err: errors.New(fmt.Sprintf("failed to forking invoke provider %v, but no luck to perform the invocation. Last error is: %s", selected, err.Error()))}
+			Err: fmt.Errorf("failed to forking invoke provider %v, "+
+				"but no luck to perform the invocation. Last error is: %v", selected, err),
+		}
 	}
 	if len(rsps) == 0 {
-		return &protocol.RPCResult{Err: errors.New(fmt.Sprintf("failed to forking invoke provider %v, but no resp", selected))}
+		return &protocol.RPCResult{Err: fmt.Errorf("failed to forking invoke provider %v, but no resp", selected)}
 	}
+
 	result, ok := rsps[0].(protocol.Result)
 	if !ok {
-		return &protocol.RPCResult{Err: errors.New(fmt.Sprintf("failed to forking invoke provider %v, but not legal resp", selected))}
+		return &protocol.RPCResult{Err: fmt.Errorf("failed to forking invoke provider %v, but not legal resp", selected)}
 	}
+
 	return result
 }
diff --git a/cluster/cluster_impl/forking_cluster_test.go b/cluster/cluster_impl/forking_cluster_test.go
index 8603f8aedc4e28a3a4ca2f115355debc1a5ecc62..9797ecbd041ae2e09c3d0566f88d08b7246b900f 100644
--- a/cluster/cluster_impl/forking_cluster_test.go
+++ b/cluster/cluster_impl/forking_cluster_test.go
@@ -42,7 +42,7 @@ import (
 )
 
 var (
-	forkingUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	forkingUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
 )
 
 func registerForking(t *testing.T, mockInvokers ...*mock.MockInvoker) protocol.Invoker {
@@ -87,7 +87,7 @@ func Test_ForkingInvokeSuccess(t *testing.T) {
 
 	clusterInvoker := registerForking(t, invokers...)
 
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Equal(t, mockResult, result)
 	wg.Wait()
 }
@@ -117,7 +117,7 @@ func Test_ForkingInvokeTimeout(t *testing.T) {
 
 	clusterInvoker := registerForking(t, invokers...)
 
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.NotNil(t, result)
 	assert.NotNil(t, result.Error())
 	wg.Wait()
@@ -156,7 +156,7 @@ func Test_ForkingInvokeHalfTimeout(t *testing.T) {
 
 	clusterInvoker := registerForking(t, invokers...)
 
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Equal(t, mockResult, result)
 	wg.Wait()
 }
diff --git a/cluster/cluster_impl/mock_cluster.go b/cluster/cluster_impl/mock_cluster.go
index 50b2735554b61600fb090f382f3d2920b3d445e3..943c2add68281d01e320252d07b7d58e27b51283 100644
--- a/cluster/cluster_impl/mock_cluster.go
+++ b/cluster/cluster_impl/mock_cluster.go
@@ -24,6 +24,7 @@ import (
 
 type mockCluster struct{}
 
+// NewMockCluster ...
 func NewMockCluster() cluster.Cluster {
 	return &mockCluster{}
 }
diff --git a/cluster/cluster_impl/registry_aware_cluster.go b/cluster/cluster_impl/registry_aware_cluster.go
index f4a28d6dcd5fbab8c62ee1f79bdd8576d8774a4c..079b688da65b3e6f6595212ad6e93c3b6ecc6504 100644
--- a/cluster/cluster_impl/registry_aware_cluster.go
+++ b/cluster/cluster_impl/registry_aware_cluster.go
@@ -29,6 +29,7 @@ func init() {
 	extension.SetCluster("registryAware", NewRegistryAwareCluster)
 }
 
+// NewRegistryAwareCluster ...
 func NewRegistryAwareCluster() cluster.Cluster {
 	return &registryAwareCluster{}
 }
diff --git a/cluster/cluster_impl/registry_aware_cluster_invoker.go b/cluster/cluster_impl/registry_aware_cluster_invoker.go
index 5785c02489f95168d5419f0087f38b07c851a4a3..cded5bf16432e6b0c590e15b81c28369889a5f88 100644
--- a/cluster/cluster_impl/registry_aware_cluster_invoker.go
+++ b/cluster/cluster_impl/registry_aware_cluster_invoker.go
@@ -17,6 +17,9 @@
 
 package cluster_impl
 
+import (
+	"context"
+)
 import (
 	"github.com/apache/dubbo-go/cluster"
 	"github.com/apache/dubbo-go/common/constant"
@@ -33,19 +36,19 @@ func newRegistryAwareClusterInvoker(directory cluster.Directory) protocol.Invoke
 	}
 }
 
-func (invoker *registryAwareClusterInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (invoker *registryAwareClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	invokers := invoker.directory.List(invocation)
 	//First, pick the invoker (XXXClusterInvoker) that comes from the local registry, distinguish by a 'default' key.
 	for _, invoker := range invokers {
 		if invoker.IsAvailable() && invoker.GetUrl().GetParam(constant.REGISTRY_DEFAULT_KEY, "false") == "true" {
-			return invoker.Invoke(invocation)
+			return invoker.Invoke(ctx, invocation)
 		}
 	}
 
 	//If none of the invokers has a local signal, pick the first one available.
 	for _, invoker := range invokers {
 		if invoker.IsAvailable() {
-			return invoker.Invoke(invocation)
+			return invoker.Invoke(ctx, invocation)
 		}
 	}
 	return nil
diff --git a/cluster/cluster_impl/registry_aware_cluster_test.go b/cluster/cluster_impl/registry_aware_cluster_test.go
index 4ae15cc5066c70646dee66cf4ef601202653cb07..3d0dcc0159839eb0a08aed842ee084449458c645 100644
--- a/cluster/cluster_impl/registry_aware_cluster_test.go
+++ b/cluster/cluster_impl/registry_aware_cluster_test.go
@@ -39,13 +39,13 @@ func Test_RegAwareInvokeSuccess(t *testing.T) {
 
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
 		invokers = append(invokers, NewMockInvoker(url, 1))
 	}
 
 	staticDir := directory.NewStaticDirectory(invokers)
 	clusterInvoker := regAwareCluster.Join(staticDir)
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.NoError(t, result.Error())
 	count = 0
 }
@@ -55,14 +55,14 @@ func TestDestroy(t *testing.T) {
 
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
 		invokers = append(invokers, NewMockInvoker(url, 1))
 	}
 
 	staticDir := directory.NewStaticDirectory(invokers)
 	clusterInvoker := regAwareCluster.Join(staticDir)
 	assert.Equal(t, true, clusterInvoker.IsAvailable())
-	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.NoError(t, result.Error())
 	count = 0
 	clusterInvoker.Destroy()
diff --git a/cluster/directory.go b/cluster/directory.go
index 045296ce549b13c327b6f479ca0bd75d0b6ce131..5a03b3a4490ce0b3aadece8a9ef43395f845dd12 100644
--- a/cluster/directory.go
+++ b/cluster/directory.go
@@ -22,7 +22,8 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// Extension - Directory
+// Directory
+//Extension - Directory
 type Directory interface {
 	common.Node
 	List(invocation protocol.Invocation) []protocol.Invoker
diff --git a/cluster/directory/base_directory.go b/cluster/directory/base_directory.go
index 1d59b51cc36858b80fb43c1d76e368e89e26ae36..e1a38c4c82cbac61fdfd96cd284c4eea44c97ccc 100644
--- a/cluster/directory/base_directory.go
+++ b/cluster/directory/base_directory.go
@@ -27,25 +27,32 @@ import (
 	"github.com/apache/dubbo-go/common"
 )
 
+// BaseDirectory ...
 type BaseDirectory struct {
 	url       *common.URL
 	destroyed *atomic.Bool
 	mutex     sync.Mutex
 }
 
+// NewBaseDirectory ...
 func NewBaseDirectory(url *common.URL) BaseDirectory {
 	return BaseDirectory{
 		url:       url,
 		destroyed: atomic.NewBool(false),
 	}
 }
+
+// GetUrl ...
 func (dir *BaseDirectory) GetUrl() common.URL {
 	return *dir.url
 }
+
+// GetDirectoryUrl ...
 func (dir *BaseDirectory) GetDirectoryUrl() *common.URL {
 	return dir.url
 }
 
+// Destroy ...
 func (dir *BaseDirectory) Destroy(doDestroy func()) {
 	if dir.destroyed.CAS(false, true) {
 		dir.mutex.Lock()
@@ -54,6 +61,7 @@ func (dir *BaseDirectory) Destroy(doDestroy func()) {
 	}
 }
 
+// IsAvailable ...
 func (dir *BaseDirectory) IsAvailable() bool {
 	return !dir.destroyed.Load()
 }
diff --git a/cluster/directory/static_directory.go b/cluster/directory/static_directory.go
index e7a0e6e569db620ee83521505c9568199d45fe1e..7d2d5490b02d22b12d55385458715fa8b31f2cac 100644
--- a/cluster/directory/static_directory.go
+++ b/cluster/directory/static_directory.go
@@ -27,6 +27,7 @@ type staticDirectory struct {
 	invokers []protocol.Invoker
 }
 
+// NewStaticDirectory ...
 func NewStaticDirectory(invokers []protocol.Invoker) *staticDirectory {
 	var url common.URL
 
diff --git a/cluster/directory/static_directory_test.go b/cluster/directory/static_directory_test.go
index 3ce772e8a6287aebef3fdad039e2b12be421c4e3..42ef1bcd0b51ce94040b3cbfac37a1f6de686fbb 100644
--- a/cluster/directory/static_directory_test.go
+++ b/cluster/directory/static_directory_test.go
@@ -18,7 +18,6 @@
 package directory
 
 import (
-	"context"
 	"fmt"
 	"testing"
 )
@@ -36,7 +35,7 @@ import (
 func Test_StaticDirList(t *testing.T) {
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 
@@ -47,7 +46,7 @@ func Test_StaticDirList(t *testing.T) {
 func Test_StaticDirDestroy(t *testing.T) {
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 
diff --git a/cluster/loadbalance.go b/cluster/loadbalance.go
index 9ae4e4eb808b28581d12b72829c921c4f0cc9ac8..fb3641a77377eabbd692729a32e2c0c096282f18 100644
--- a/cluster/loadbalance.go
+++ b/cluster/loadbalance.go
@@ -21,7 +21,8 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// Extension - LoadBalance
+// LoadBalance
+//Extension - LoadBalance
 type LoadBalance interface {
 	Select([]protocol.Invoker, protocol.Invocation) protocol.Invoker
 }
diff --git a/cluster/loadbalance/consistent_hash.go b/cluster/loadbalance/consistent_hash.go
index 365e6a66242e4a4618ab922f80b4b4247076484d..957c110663d6c56ada15543d372e210fa83bf74b 100644
--- a/cluster/loadbalance/consistent_hash.go
+++ b/cluster/loadbalance/consistent_hash.go
@@ -36,9 +36,12 @@ import (
 )
 
 const (
+	// ConsistentHash ...
 	ConsistentHash = "consistenthash"
-	HashNodes      = "hash.nodes"
-	HashArguments  = "hash.arguments"
+	// HashNodes ...
+	HashNodes = "hash.nodes"
+	// HashArguments ...
+	HashArguments = "hash.arguments"
 )
 
 var (
@@ -50,13 +53,16 @@ func init() {
 	extension.SetLoadbalance(ConsistentHash, NewConsistentHashLoadBalance)
 }
 
+// ConsistentHashLoadBalance ...
 type ConsistentHashLoadBalance struct {
 }
 
+// NewConsistentHashLoadBalance ...
 func NewConsistentHashLoadBalance() cluster.LoadBalance {
 	return &ConsistentHashLoadBalance{}
 }
 
+// Select ...
 func (lb *ConsistentHashLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker {
 	methodName := invocation.MethodName()
 	key := invokers[0].GetUrl().ServiceKey() + "." + methodName
@@ -79,6 +85,7 @@ func (lb *ConsistentHashLoadBalance) Select(invokers []protocol.Invoker, invocat
 	return selector.Select(invocation)
 }
 
+// Uint32Slice ...
 type Uint32Slice []uint32
 
 func (s Uint32Slice) Len() int {
@@ -93,6 +100,7 @@ func (s Uint32Slice) Swap(i, j int) {
 	s[i], s[j] = s[j], s[i]
 }
 
+// ConsistentHashSelector ...
 type ConsistentHashSelector struct {
 	hashCode        uint32
 	replicaNum      int
@@ -133,6 +141,7 @@ func newConsistentHashSelector(invokers []protocol.Invoker, methodName string,
 	return selector
 }
 
+// Select ...
 func (c *ConsistentHashSelector) Select(invocation protocol.Invocation) protocol.Invoker {
 	key := c.toKey(invocation.Arguments())
 	digest := md5.Sum([]byte(key))
diff --git a/cluster/loadbalance/consistent_hash_test.go b/cluster/loadbalance/consistent_hash_test.go
index 174d5715dd1258d329f40251e76ca47d98791ea9..a44293172c6e2c96bd098a19306f69260b713689 100644
--- a/cluster/loadbalance/consistent_hash_test.go
+++ b/cluster/loadbalance/consistent_hash_test.go
@@ -18,7 +18,6 @@
 package loadbalance
 
 import (
-	"context"
 	"testing"
 )
 
@@ -44,7 +43,7 @@ type consistentHashSelectorSuite struct {
 
 func (s *consistentHashSelectorSuite) SetupTest() {
 	var invokers []protocol.Invoker
-	url, _ := common.NewURL(context.TODO(),
+	url, _ := common.NewURL(
 		"dubbo://192.168.1.0:20000/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
 	invokers = append(invokers, protocol.NewBaseInvoker(url))
 	s.selector = newConsistentHashSelector(invokers, "echo", 999944)
@@ -56,8 +55,8 @@ func (s *consistentHashSelectorSuite) TestToKey() {
 }
 
 func (s *consistentHashSelectorSuite) TestSelectForKey() {
-	url1, _ := common.NewURL(context.TODO(), "dubbo://192.168.1.0:8080")
-	url2, _ := common.NewURL(context.TODO(), "dubbo://192.168.1.0:8081")
+	url1, _ := common.NewURL("dubbo://192.168.1.0:8080")
+	url2, _ := common.NewURL("dubbo://192.168.1.0:8081")
 	s.selector.virtualInvokers = make(map[uint32]protocol.Invoker)
 	s.selector.virtualInvokers[99874] = protocol.NewBaseInvoker(url1)
 	s.selector.virtualInvokers[9999945] = protocol.NewBaseInvoker(url2)
@@ -84,11 +83,11 @@ type consistentHashLoadBalanceSuite struct {
 
 func (s *consistentHashLoadBalanceSuite) SetupTest() {
 	var err error
-	s.url1, err = common.NewURL(context.TODO(), "dubbo://192.168.1.0:8080/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	s.url1, err = common.NewURL("dubbo://192.168.1.0:8080/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
 	s.NoError(err)
-	s.url2, err = common.NewURL(context.TODO(), "dubbo://192.168.1.0:8081/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	s.url2, err = common.NewURL("dubbo://192.168.1.0:8081/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
 	s.NoError(err)
-	s.url3, err = common.NewURL(context.TODO(), "dubbo://192.168.1.0:8082/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	s.url3, err = common.NewURL("dubbo://192.168.1.0:8082/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
 	s.NoError(err)
 
 	s.invoker1 = protocol.NewBaseInvoker(s.url1)
diff --git a/cluster/loadbalance/least_active.go b/cluster/loadbalance/least_active.go
index aa69f3cc207ae7465bc6d5472bc075d0902c8978..e7c41aac93e8d3dfcef5d49fa486483bd045f569 100644
--- a/cluster/loadbalance/least_active.go
+++ b/cluster/loadbalance/least_active.go
@@ -28,6 +28,7 @@ import (
 )
 
 const (
+	// LeastActive ...
 	LeastActive = "leastactive"
 )
 
@@ -38,6 +39,7 @@ func init() {
 type leastActiveLoadBalance struct {
 }
 
+// NewLeastActiveLoadBalance ...
 func NewLeastActiveLoadBalance() cluster.LoadBalance {
 	return &leastActiveLoadBalance{}
 }
@@ -52,18 +54,18 @@ func (lb *leastActiveLoadBalance) Select(invokers []protocol.Invoker, invocation
 	}
 
 	var (
-		leastActive  int32 = -1                 // The least active value of all invokers
-		totalWeight  int64 = 0                  // The number of invokers having the same least active value (LEAST_ACTIVE)
-		firstWeight  int64 = 0                  // Initial value, used for comparison
-		leastIndexes       = make([]int, count) // The index of invokers having the same least active value (LEAST_ACTIVE)
-		leastCount         = 0                  // The number of invokers having the same least active value (LEAST_ACTIVE)
-		sameWeight         = true               // Every invoker has the same weight value?
+		leastActive  int32                = -1 // The least active value of all invokers
+		totalWeight  int64                     // The number of invokers having the same least active value (LEAST_ACTIVE)
+		firstWeight  int64                     // Initial value, used for comparison
+		leastCount   int                       // The number of invokers having the same least active value (LEAST_ACTIVE)
+		leastIndexes = make([]int, count)      // The index of invokers having the same least active value (LEAST_ACTIVE)
+		sameWeight   = true                    // Every invoker has the same weight value?
 	)
 
 	for i := 0; i < count; i++ {
 		invoker := invokers[i]
 		// Active number
-		active := protocol.GetStatus(invoker.GetUrl(), invocation.MethodName()).GetActive()
+		active := protocol.GetMethodStatus(invoker.GetUrl(), invocation.MethodName()).GetActive()
 		// current weight (maybe in warmUp)
 		weight := GetWeight(invoker, invocation)
 		// There are smaller active services
diff --git a/cluster/loadbalance/least_active_test.go b/cluster/loadbalance/least_active_test.go
index 6bc6985678d7c392ad21b49ec341c3550265f622..54e57e930f17008cf6d767ef47c0e754ac85d8f7 100644
--- a/cluster/loadbalance/least_active_test.go
+++ b/cluster/loadbalance/least_active_test.go
@@ -18,7 +18,6 @@
 package loadbalance
 
 import (
-	"context"
 	"fmt"
 	"testing"
 )
@@ -38,13 +37,13 @@ func TestLeastActiveSelect(t *testing.T) {
 
 	var invokers []protocol.Invoker
 
-	url, _ := common.NewURL(context.TODO(), "dubbo://192.168.1.0:20000/org.apache.demo.HelloService")
+	url, _ := common.NewURL("dubbo://192.168.1.0:20000/org.apache.demo.HelloService")
 	invokers = append(invokers, protocol.NewBaseInvoker(url))
 	i := loadBalance.Select(invokers, &invocation.RPCInvocation{})
 	assert.True(t, i.GetUrl().URLEqual(url))
 
 	for i := 1; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 	loadBalance.Select(invokers, &invocation.RPCInvocation{})
@@ -56,7 +55,7 @@ func TestLeastActiveByWeight(t *testing.T) {
 	var invokers []protocol.Invoker
 	loop := 3
 	for i := 1; i <= loop; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("test%v://192.168.1.%v:20000/org.apache.demo.HelloService?weight=%v", i, i, i))
+		url, _ := common.NewURL(fmt.Sprintf("test%v://192.168.1.%v:20000/org.apache.demo.HelloService?weight=%v", i, i, i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 
diff --git a/cluster/loadbalance/random.go b/cluster/loadbalance/random.go
index 919792162dc527fa8c1e5cf2911f2933fa8232ef..56f13631b653ed070dae7def5bea97d924141209 100644
--- a/cluster/loadbalance/random.go
+++ b/cluster/loadbalance/random.go
@@ -38,6 +38,7 @@ func init() {
 type randomLoadBalance struct {
 }
 
+// NewRandomLoadBalance ...
 func NewRandomLoadBalance() cluster.LoadBalance {
 	return &randomLoadBalance{}
 }
diff --git a/cluster/loadbalance/random_test.go b/cluster/loadbalance/random_test.go
index ffe65d78ac61e5210d23e44c7f802597fed78f96..ff876f4aef8d229e8041594aaaa096f3ad5b1834 100644
--- a/cluster/loadbalance/random_test.go
+++ b/cluster/loadbalance/random_test.go
@@ -18,7 +18,6 @@
 package loadbalance
 
 import (
-	"context"
 	"fmt"
 	"net/url"
 	"strconv"
@@ -42,13 +41,13 @@ func Test_RandomlbSelect(t *testing.T) {
 
 	invokers := []protocol.Invoker{}
 
-	url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", 0))
+	url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", 0))
 	invokers = append(invokers, protocol.NewBaseInvoker(url))
 	i := randomlb.Select(invokers, &invocation.RPCInvocation{})
 	assert.True(t, i.GetUrl().URLEqual(url))
 
 	for i := 1; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 	randomlb.Select(invokers, &invocation.RPCInvocation{})
@@ -59,13 +58,13 @@ func Test_RandomlbSelectWeight(t *testing.T) {
 
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 
 	urlParams := url.Values{}
 	urlParams.Set("methods.test."+constant.WEIGHT_KEY, "10000000000000")
-	urll, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"), common.WithParams(urlParams))
+	urll, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"), common.WithParams(urlParams))
 	invokers = append(invokers, protocol.NewBaseInvoker(urll))
 	ivc := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("test"))
 
@@ -80,7 +79,7 @@ func Test_RandomlbSelectWeight(t *testing.T) {
 	}
 
 	assert.Condition(t, func() bool {
-		//really is 0.9999999999999
+		// really is 0.9999999999999
 		return selected/10000 > 0.9
 	})
 }
@@ -90,13 +89,13 @@ func Test_RandomlbSelectWarmup(t *testing.T) {
 
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 
 	urlParams := url.Values{}
 	urlParams.Set(constant.REMOTE_TIMESTAMP_KEY, strconv.FormatInt(time.Now().Add(time.Minute*(-9)).Unix(), 10))
-	urll, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"), common.WithParams(urlParams))
+	urll, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"), common.WithParams(urlParams))
 	invokers = append(invokers, protocol.NewBaseInvoker(urll))
 	ivc := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("test"))
 
diff --git a/cluster/loadbalance/round_robin.go b/cluster/loadbalance/round_robin.go
index 075acac7cdc60086ececb7b655dee86ec5198369..4d039999677aefb1093071666a845279dc357ce9 100644
--- a/cluster/loadbalance/round_robin.go
+++ b/cluster/loadbalance/round_robin.go
@@ -31,16 +31,19 @@ import (
 )
 
 const (
+	// RoundRobin ...
 	RoundRobin = "roundrobin"
 
+	// COMPLETE ...
 	COMPLETE = 0
+	// UPDATING ...
 	UPDATING = 1
 )
 
 var (
-	methodWeightMap sync.Map            // [string]invokers
-	state           int32    = COMPLETE // update lock acquired ?
-	recyclePeriod   int64    = 60 * time.Second.Nanoseconds()
+	methodWeightMap sync.Map          // [string]invokers
+	state           = int32(COMPLETE) // update lock acquired ?
+	recyclePeriod   = 60 * time.Second.Nanoseconds()
 )
 
 func init() {
@@ -49,6 +52,7 @@ func init() {
 
 type roundRobinLoadBalance struct{}
 
+// NewRoundRobinLoadBalance ...
 func NewRoundRobinLoadBalance() cluster.LoadBalance {
 	return &roundRobinLoadBalance{}
 }
diff --git a/cluster/loadbalance/round_robin_test.go b/cluster/loadbalance/round_robin_test.go
index 0b8e89c7349afb056309b5a70d91aa5cce309aa0..1517f2a20b473af57cc23e61b988aa5a6a04de31 100644
--- a/cluster/loadbalance/round_robin_test.go
+++ b/cluster/loadbalance/round_robin_test.go
@@ -18,7 +18,6 @@
 package loadbalance
 
 import (
-	"context"
 	"fmt"
 	"strconv"
 	"testing"
@@ -39,13 +38,13 @@ func TestRoundRobinSelect(t *testing.T) {
 
 	var invokers []protocol.Invoker
 
-	url, _ := common.NewURL(context.TODO(), "dubbo://192.168.1.0:20000/org.apache.demo.HelloService")
+	url, _ := common.NewURL("dubbo://192.168.1.0:20000/org.apache.demo.HelloService")
 	invokers = append(invokers, protocol.NewBaseInvoker(url))
 	i := loadBalance.Select(invokers, &invocation.RPCInvocation{})
 	assert.True(t, i.GetUrl().URLEqual(url))
 
 	for i := 1; i < 10; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 	loadBalance.Select(invokers, &invocation.RPCInvocation{})
@@ -57,7 +56,7 @@ func TestRoundRobinByWeight(t *testing.T) {
 	var invokers []protocol.Invoker
 	loop := 10
 	for i := 1; i <= loop; i++ {
-		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService?weight=%v", i, i))
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService?weight=%v", i, i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 
diff --git a/cluster/loadbalance/util.go b/cluster/loadbalance/util.go
index 7e0c2e265073c0a96032a6dd3294a6d73c1a4001..9f36ad9379a3a09a4a058f6179e3e537b9e105bc 100644
--- a/cluster/loadbalance/util.go
+++ b/cluster/loadbalance/util.go
@@ -26,6 +26,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// GetWeight ...
 func GetWeight(invoker protocol.Invoker, invocation protocol.Invocation) int64 {
 	url := invoker.GetUrl()
 	weight := url.GetMethodParamInt64(invocation.MethodName(), constant.WEIGHT_KEY, constant.DEFAULT_WEIGHT)
diff --git a/cluster/router.go b/cluster/router.go
index 54a19695574f245fcac236e9308a2469f306a4f8..589eb9a2696e5772070a94e8c764c78c8e0ca8a2 100644
--- a/cluster/router.go
+++ b/cluster/router.go
@@ -24,18 +24,22 @@ import (
 
 // Extension - Router
 
+// RouterFactory ...
 type RouterFactory interface {
 	Router(*common.URL) (Router, error)
 }
 
+// Router ...
 type Router interface {
 	Route([]protocol.Invoker, common.URL, protocol.Invocation) []protocol.Invoker
 }
 
+// RouterChain ...
 type RouterChain struct {
 	routers []Router
 }
 
+// NewRouterChain ...
 func NewRouterChain(url common.URL) {
 
 }
diff --git a/cluster/router/condition_router.go b/cluster/router/condition_router.go
index efae65ccb34eb8a78e281cfaf7b1fcec79b3d163..c38e9718cca6d5e67a874a61225bac7d27d5d352 100644
--- a/cluster/router/condition_router.go
+++ b/cluster/router/condition_router.go
@@ -24,7 +24,7 @@ import (
 )
 
 import (
-	"github.com/dubbogo/gost/container/gxset"
+	gxset "github.com/dubbogo/gost/container/set"
 	gxnet "github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
 )
@@ -37,9 +37,12 @@ import (
 )
 
 const (
+	//ROUTE_PATTERN route pattern regex
 	ROUTE_PATTERN = `([&!=,]*)\\s*([^&!=,\\s]+)`
-	FORCE         = "force"
-	PRIORITY      = "priority"
+	// FORCE ...
+	FORCE = "force"
+	// PRIORITY ...
+	PRIORITY = "priority"
 )
 
 //ConditionRouter condition router struct
@@ -104,7 +107,8 @@ func newConditionRouter(url *common.URL) (*ConditionRouter, error) {
 	}, nil
 }
 
-//Router determine the target server list.
+// Route
+// Router determine the target server list.
 func (c *ConditionRouter) Route(invokers []protocol.Invoker, url common.URL, invocation protocol.Invocation) []protocol.Invoker {
 	if len(invokers) == 0 {
 		return invokers
@@ -212,7 +216,7 @@ func parseRule(rule string) (map[string]MatchPair, error) {
 	return condition, nil
 }
 
-//
+//MatchWhen  MatchWhen
 func (c *ConditionRouter) MatchWhen(url common.URL, invocation protocol.Invocation) (bool, error) {
 	condition, err := MatchCondition(c.WhenCondition, &url, nil, invocation)
 	return len(c.WhenCondition) == 0 || condition, err
@@ -245,20 +249,21 @@ func MatchCondition(pairs map[string]MatchPair, url *common.URL, param *common.U
 		if len(sampleValue) > 0 {
 			if !matchPair.isMatch(sampleValue, param) {
 				return false, nil
-			} else {
-				result = true
 			}
+
+			result = true
 		} else {
 			if !(matchPair.Matches.Empty()) {
 				return false, nil
-			} else {
-				result = true
 			}
+
+			result = true
 		}
 	}
 	return result, nil
 }
 
+// MatchPair ...
 type MatchPair struct {
 	Matches    *gxset.HashSet
 	Mismatches *gxset.HashSet
diff --git a/cluster/router/condition_router_test.go b/cluster/router/condition_router_test.go
index 7d8b0d88cab688e6ea10d1562a27de4609d51f58..fc639b9fc77b3b83d01c663fa02a7185a2d03756 100644
--- a/cluster/router/condition_router_test.go
+++ b/cluster/router/condition_router_test.go
@@ -59,21 +59,21 @@ func (bi *MockInvoker) GetUrl() common.URL {
 }
 
 func getRouteUrl(rule string) *common.URL {
-	url, _ := common.NewURL(context.TODO(), "condition://0.0.0.0/com.foo.BarService")
+	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
 	url.AddParam("rule", rule)
 	url.AddParam("force", "true")
 	return &url
 }
 
 func getRouteUrlWithForce(rule, force string) *common.URL {
-	url, _ := common.NewURL(context.TODO(), "condition://0.0.0.0/com.foo.BarService")
+	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
 	url.AddParam("rule", rule)
 	url.AddParam("force", force)
 	return &url
 }
 
 func getRouteUrlWithNoForce(rule string) *common.URL {
-	url, _ := common.NewURL(context.TODO(), "condition://0.0.0.0/com.foo.BarService")
+	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
 	url.AddParam("rule", rule)
 	return &url
 }
@@ -93,15 +93,19 @@ type rest struct {
 
 var count int
 
-func (bi *MockInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (bi *MockInvoker) Invoke(_ context.Context, _ protocol.Invocation) protocol.Result {
 	count++
-	var success bool
-	var err error = nil
+
+	var (
+		success bool
+		err     error
+	)
 	if count >= bi.successCount {
 		success = true
 	} else {
 		err = perrors.New("error")
 	}
+
 	result := &protocol.RPCResult{Err: err, Rest: rest{tried: count, success: success}}
 	return result
 }
@@ -116,7 +120,7 @@ func TestRoute_matchWhen(t *testing.T) {
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("=> host = 1.2.3.4"))
 	router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule))
-	cUrl, _ := common.NewURL(context.TODO(), "consumer://1.1.1.1/com.foo.BarService")
+	cUrl, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService")
 	matchWhen, _ := router.(*ConditionRouter).MatchWhen(cUrl, inv)
 	assert.Equal(t, true, matchWhen)
 	rule1 := base64.URLEncoding.EncodeToString([]byte("host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"))
@@ -148,9 +152,9 @@ func TestRoute_matchWhen(t *testing.T) {
 func TestRoute_matchFilter(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
 	t.Logf("The local ip is %s", localIP)
-	url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService?default.serialization=fastjson")
-	url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
-	url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService?default.serialization=fastjson")
+	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
 	invokers := []protocol.Invoker{NewMockInvoker(url1, 1), NewMockInvoker(url2, 2), NewMockInvoker(url3, 3)}
 	rule1 := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 10.20.3.3"))
 	rule2 := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 10.20.3.* & host != 10.20.3.3"))
@@ -164,7 +168,7 @@ func TestRoute_matchFilter(t *testing.T) {
 	router4, _ := NewConditionRouterFactory().Router(getRouteUrl(rule4))
 	router5, _ := NewConditionRouterFactory().Router(getRouteUrl(rule5))
 	router6, _ := NewConditionRouterFactory().Router(getRouteUrl(rule6))
-	cUrl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService")
+	cUrl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
 	fileredInvokers1 := router1.Route(invokers, cUrl, &invocation.RPCInvocation{})
 	fileredInvokers2 := router2.Route(invokers, cUrl, &invocation.RPCInvocation{})
 	fileredInvokers3 := router3.Route(invokers, cUrl, &invocation.RPCInvocation{})
@@ -184,18 +188,18 @@ func TestRoute_methodRoute(t *testing.T) {
 	inv := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("getFoo"), invocation.WithParameterTypes([]reflect.Type{}), invocation.WithArguments([]interface{}{}))
 	rule := base64.URLEncoding.EncodeToString([]byte("host !=4.4.4.* & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"))
 	router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule))
-	url, _ := common.NewURL(context.TODO(), "consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo")
+	url, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo")
 	matchWhen, _ := router.(*ConditionRouter).MatchWhen(url, inv)
 	assert.Equal(t, true, matchWhen)
-	url1, _ := common.NewURL(context.TODO(), "consumer://1.1.1.1/com.foo.BarService?methods=getFoo")
+	url1, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=getFoo")
 	matchWhen, _ = router.(*ConditionRouter).MatchWhen(url1, inv)
 	assert.Equal(t, true, matchWhen)
-	url2, _ := common.NewURL(context.TODO(), "consumer://1.1.1.1/com.foo.BarService?methods=getFoo")
+	url2, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=getFoo")
 	rule2 := base64.URLEncoding.EncodeToString([]byte("methods=getFoo & host!=1.1.1.1 => host = 1.2.3.4"))
 	router2, _ := NewConditionRouterFactory().Router(getRouteUrl(rule2))
 	matchWhen, _ = router2.(*ConditionRouter).MatchWhen(url2, inv)
 	assert.Equal(t, false, matchWhen)
-	url3, _ := common.NewURL(context.TODO(), "consumer://1.1.1.1/com.foo.BarService?methods=getFoo")
+	url3, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=getFoo")
 	rule3 := base64.URLEncoding.EncodeToString([]byte("methods=getFoo & host=1.1.1.1 => host = 1.2.3.4"))
 	router3, _ := NewConditionRouterFactory().Router(getRouteUrl(rule3))
 	matchWhen, _ = router3.(*ConditionRouter).MatchWhen(url3, inv)
@@ -204,12 +208,12 @@ func TestRoute_methodRoute(t *testing.T) {
 }
 
 func TestRoute_ReturnFalse(t *testing.T) {
-	url, _ := common.NewURL(context.TODO(), "")
+	url, _ := common.NewURL("")
 	localIP, _ := gxnet.GetLocalIP()
 	invokers := []protocol.Invoker{NewMockInvoker(url, 1), NewMockInvoker(url, 2), NewMockInvoker(url, 3)}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => false"))
-	curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService")
+	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
 	router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv)
 	assert.Equal(t, 0, len(fileredInvokers))
@@ -217,11 +221,11 @@ func TestRoute_ReturnFalse(t *testing.T) {
 
 func TestRoute_ReturnEmpty(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
-	url, _ := common.NewURL(context.TODO(), "")
+	url, _ := common.NewURL("")
 	invokers := []protocol.Invoker{NewMockInvoker(url, 1), NewMockInvoker(url, 2), NewMockInvoker(url, 3)}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => "))
-	curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService")
+	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
 	router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv)
 	assert.Equal(t, 0, len(fileredInvokers))
@@ -232,7 +236,7 @@ func TestRoute_ReturnAll(t *testing.T) {
 	invokers := []protocol.Invoker{&MockInvoker{}, &MockInvoker{}, &MockInvoker{}}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = " + localIP))
-	curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService")
+	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
 	router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv)
 	assert.Equal(t, invokers, fileredInvokers)
@@ -240,16 +244,16 @@ func TestRoute_ReturnAll(t *testing.T) {
 
 func TestRoute_HostFilter(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
-	url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService")
-	url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
-	url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
+	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = " + localIP))
-	curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService")
+	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
 	router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv)
 	assert.Equal(t, 2, len(fileredInvokers))
@@ -259,16 +263,16 @@ func TestRoute_HostFilter(t *testing.T) {
 
 func TestRoute_Empty_HostFilter(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
-	url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService")
-	url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
-	url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
+	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte(" => " + " host = " + localIP))
-	curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService")
+	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
 	router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv)
 	assert.Equal(t, 2, len(fileredInvokers))
@@ -278,16 +282,16 @@ func TestRoute_Empty_HostFilter(t *testing.T) {
 
 func TestRoute_False_HostFilter(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
-	url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService")
-	url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
-	url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
+	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("true => " + " host = " + localIP))
-	curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService")
+	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
 	router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv)
 	assert.Equal(t, 2, len(fileredInvokers))
@@ -297,16 +301,16 @@ func TestRoute_False_HostFilter(t *testing.T) {
 
 func TestRoute_Placeholder(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
-	url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService")
-	url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
-	url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
+	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = $host"))
-	curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService")
+	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
 	router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv)
 	assert.Equal(t, 2, len(fileredInvokers))
@@ -316,16 +320,16 @@ func TestRoute_Placeholder(t *testing.T) {
 
 func TestRoute_NoForce(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
-	url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService")
-	url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
-	url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
+	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 1.2.3.4"))
-	curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService")
+	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
 	router, _ := NewConditionRouterFactory().Router(getRouteUrlWithNoForce(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv)
 	assert.Equal(t, invokers, fileredInvokers)
@@ -333,16 +337,16 @@ func TestRoute_NoForce(t *testing.T) {
 
 func TestRoute_Force(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
-	url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService")
-	url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
-	url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
+	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 1.2.3.4"))
-	curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService")
+	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
 	router, _ := NewConditionRouterFactory().Router(getRouteUrlWithForce(rule, "true"))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv)
 	assert.Equal(t, 0, len(fileredInvokers))
diff --git a/cluster/router/router_factory.go b/cluster/router/router_factory.go
index a9794cb885badae98445ef4d7c0bbc2230d25d5f..723050939e5080f1fefd230986dc679dfbdc06ed 100644
--- a/cluster/router/router_factory.go
+++ b/cluster/router/router_factory.go
@@ -27,11 +27,15 @@ func init() {
 	extension.SetRouterFactory("condition", NewConditionRouterFactory)
 }
 
+// ConditionRouterFactory ...
 type ConditionRouterFactory struct{}
 
+// NewConditionRouterFactory ...
 func NewConditionRouterFactory() cluster.RouterFactory {
 	return ConditionRouterFactory{}
 }
+
+// Router ...
 func (c ConditionRouterFactory) Router(url *common.URL) (cluster.Router, error) {
 	return newConditionRouter(url)
 }
diff --git a/common/config/environment.go b/common/config/environment.go
index 931f0460917d68d3bd7adcd6a6bc1b49c7d3bba8..071af31152ba4ce3c579f70aa23df59d718ce506 100644
--- a/common/config/environment.go
+++ b/common/config/environment.go
@@ -27,6 +27,7 @@ import (
 	"github.com/apache/dubbo-go/config_center"
 )
 
+// Environment
 // There is dubbo.properties file and application level config center configuration which higner than normal config center in java. So in java the
 // configuration sequence will be config center > application level config center > dubbo.properties > spring bean configuration.
 // But in go, neither the dubbo.properties file or application level config center configuration will not support for the time being.
@@ -45,12 +46,15 @@ var (
 	once     sync.Once
 )
 
+// GetEnvInstance ...
 func GetEnvInstance() *Environment {
 	once.Do(func() {
 		instance = &Environment{configCenterFirst: true}
 	})
 	return instance
 }
+
+// NewEnvInstance ...
 func NewEnvInstance() {
 	instance = &Environment{configCenterFirst: true}
 }
@@ -63,34 +67,40 @@ func NewEnvInstance() {
 //	return env.configCenterFirst
 //}
 
+// UpdateExternalConfigMap ...
 func (env *Environment) UpdateExternalConfigMap(externalMap map[string]string) {
 	for k, v := range externalMap {
 		env.externalConfigMap.Store(k, v)
 	}
 }
 
+// UpdateAppExternalConfigMap ...
 func (env *Environment) UpdateAppExternalConfigMap(externalMap map[string]string) {
 	for k, v := range externalMap {
 		env.appExternalConfigMap.Store(k, v)
 	}
 }
 
+// Configuration ...
 func (env *Environment) Configuration() *list.List {
-	list := list.New()
+	cfgList := list.New()
 	// The sequence would be: SystemConfiguration -> ExternalConfiguration -> AppExternalConfiguration -> AbstractConfig -> PropertiesConfiguration
-	list.PushFront(newInmemoryConfiguration(&(env.externalConfigMap)))
-	list.PushFront(newInmemoryConfiguration(&(env.appExternalConfigMap)))
-	return list
+	cfgList.PushFront(newInmemoryConfiguration(&(env.externalConfigMap)))
+	cfgList.PushFront(newInmemoryConfiguration(&(env.appExternalConfigMap)))
+	return cfgList
 }
 
+// SetDynamicConfiguration ...
 func (env *Environment) SetDynamicConfiguration(dc config_center.DynamicConfiguration) {
 	env.dynamicConfiguration = dc
 }
 
+// GetDynamicConfiguration ...
 func (env *Environment) GetDynamicConfiguration() config_center.DynamicConfiguration {
 	return env.dynamicConfiguration
 }
 
+// InmemoryConfiguration ...
 type InmemoryConfiguration struct {
 	store *sync.Map
 }
@@ -99,6 +109,7 @@ func newInmemoryConfiguration(p *sync.Map) *InmemoryConfiguration {
 	return &InmemoryConfiguration{store: p}
 }
 
+// GetProperty ...
 func (conf *InmemoryConfiguration) GetProperty(key string) (bool, string) {
 	if conf.store == nil {
 		return false, ""
@@ -112,6 +123,7 @@ func (conf *InmemoryConfiguration) GetProperty(key string) (bool, string) {
 	return false, ""
 }
 
+// GetSubProperty ...
 func (conf *InmemoryConfiguration) GetSubProperty(subKey string) map[string]struct{} {
 	if conf.store == nil {
 		return nil
diff --git a/common/constant/default.go b/common/constant/default.go
index 6e0f8488783ebe66939436ca14670395e2719be7..992fc32748bb4fc7777cffecc9137663c681c3f7 100644
--- a/common/constant/default.go
+++ b/common/constant/default.go
@@ -46,7 +46,7 @@ const (
 const (
 	DEFAULT_KEY               = "default"
 	PREFIX_DEFAULT_KEY        = "default."
-	DEFAULT_SERVICE_FILTERS   = "echo,token,accesslog,tps,execute,pshutdown"
+	DEFAULT_SERVICE_FILTERS   = "echo,token,accesslog,tps,generic_service,execute,pshutdown"
 	DEFAULT_REFERENCE_FILTERS = "cshutdown"
 	GENERIC_REFERENCE_FILTERS = "generic"
 	GENERIC                   = "$invoke"
diff --git a/common/constant/env.go b/common/constant/env.go
index 759cb0be0a2bd36a2a345a360c541b7d56813d70..cb5394bb82ec29d1d24e02627e9d8fafff212efa 100644
--- a/common/constant/env.go
+++ b/common/constant/env.go
@@ -18,7 +18,10 @@
 package constant
 
 const (
+	// CONF_CONSUMER_FILE_PATH ...
 	CONF_CONSUMER_FILE_PATH = "CONF_CONSUMER_FILE_PATH"
+	// CONF_PROVIDER_FILE_PATH ...
 	CONF_PROVIDER_FILE_PATH = "CONF_PROVIDER_FILE_PATH"
-	APP_LOG_CONF_FILE       = "APP_LOG_CONF_FILE"
+	// APP_LOG_CONF_FILE ...
+	APP_LOG_CONF_FILE = "APP_LOG_CONF_FILE"
 )
diff --git a/common/constant/key.go b/common/constant/key.go
index 7538a2995a89b0951c29f532b9ce9e475198f54e..eff704371c7c5b66ca11a846ad7603a01f8b5708 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -137,3 +137,25 @@ const (
 	NACOS_PROTOCOL_KEY           = "protocol"
 	NACOS_PATH_KEY               = "path"
 )
+
+const (
+	TRACING_REMOTE_SPAN_CTX = "tracing.remote.span.ctx"
+)
+
+const (
+	CONSUMER_SIGN_FILTER          = "sign"
+	PROVIDER_AUTH_FILTER          = "auth"
+	SERVICE_AUTH_KEY              = "auth"
+	AUTHENTICATOR_KEY             = "authenticator"
+	DEFAULT_AUTHENTICATOR         = "accesskeys"
+	DEFAULT_ACCESS_KEY_STORAGE    = "urlstorage"
+	ACCESS_KEY_STORAGE_KEY        = "accessKey.storage"
+	REQUEST_TIMESTAMP_KEY         = "timestamp"
+	REQUEST_SIGNATURE_KEY         = "signature"
+	AK_KEY                        = "ak"
+	SIGNATURE_STRING_FORMAT       = "%s#%s#%s#%s"
+	PARAMTER_SIGNATURE_ENABLE_KEY = "param.sign"
+	CONSUMER                      = "consumer"
+	ACCESS_KEY_ID_KEY             = "accessKeyId"
+	SECRET_ACCESS_KEY_KEY         = "secretAccessKey"
+)
diff --git a/common/constant/time.go b/common/constant/time.go
new file mode 100644
index 0000000000000000000000000000000000000000..be1baaca67f474aa92e86e529d03400948ef4612
--- /dev/null
+++ b/common/constant/time.go
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package constant
+
+import (
+	"time"
+)
+
+var (
+	MsToNanoRate = int64(time.Millisecond / time.Nanosecond)
+)
diff --git a/common/constant/version.go b/common/constant/version.go
index d4c6821e76894cbd82dc5fae09124263b5c6aa0f..730224376054a36b0c7cfeda7d5ea5e7ce058618 100644
--- a/common/constant/version.go
+++ b/common/constant/version.go
@@ -18,7 +18,10 @@
 package constant
 
 const (
-	Version = "2.6.0"
-	Name    = "dubbogo"
-	DATE    = "2019/05/06"
+	// Version apache/dubbo-go version
+	Version = "1.3.0"
+	// Name module name
+	Name = "dubbogo"
+	// Date release date
+	DATE = "2020/01/12"
 )
diff --git a/common/extension/auth.go b/common/extension/auth.go
new file mode 100644
index 0000000000000000000000000000000000000000..e57e22f660b6d4dec63f8b4a06c25b05bd5c8d72
--- /dev/null
+++ b/common/extension/auth.go
@@ -0,0 +1,32 @@
+package extension
+
+import (
+	"github.com/apache/dubbo-go/filter"
+)
+
+var (
+	authenticators    = make(map[string]func() filter.Authenticator)
+	accesskeyStorages = make(map[string]func() filter.AccessKeyStorage)
+)
+
+func SetAuthenticator(name string, fcn func() filter.Authenticator) {
+	authenticators[name] = fcn
+}
+
+func GetAuthenticator(name string) filter.Authenticator {
+	if authenticators[name] == nil {
+		panic("authenticator for " + name + " is not existing, make sure you have import the package.")
+	}
+	return authenticators[name]()
+}
+
+func SetAccesskeyStorages(name string, fcn func() filter.AccessKeyStorage) {
+	accesskeyStorages[name] = fcn
+}
+
+func GetAccesskeyStorages(name string) filter.AccessKeyStorage {
+	if accesskeyStorages[name] == nil {
+		panic("accesskeyStorages for " + name + " is not existing, make sure you have import the package.")
+	}
+	return accesskeyStorages[name]()
+}
diff --git a/common/extension/cluster.go b/common/extension/cluster.go
index 91e9f953b505e31c1a4f448e1504a6ae50a9663f..b2d81f6b1e56bb487b1d408b878308f6dfe042e4 100644
--- a/common/extension/cluster.go
+++ b/common/extension/cluster.go
@@ -25,10 +25,12 @@ var (
 	clusters = make(map[string]func() cluster.Cluster)
 )
 
+// SetCluster ...
 func SetCluster(name string, fcn func() cluster.Cluster) {
 	clusters[name] = fcn
 }
 
+// GetCluster ...
 func GetCluster(name string) cluster.Cluster {
 	if clusters[name] == nil {
 		panic("cluster for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/config_center.go b/common/extension/config_center.go
index be4b62ccdd9c36500c306c7f16abd054f91ae86b..03d27db46c94b0ea0e212646077d97f948a8e328 100644
--- a/common/extension/config_center.go
+++ b/common/extension/config_center.go
@@ -26,10 +26,12 @@ var (
 	configCenters = make(map[string]func(config *common.URL) (config_center.DynamicConfiguration, error))
 )
 
+// SetConfigCenter ...
 func SetConfigCenter(name string, v func(config *common.URL) (config_center.DynamicConfiguration, error)) {
 	configCenters[name] = v
 }
 
+// GetConfigCenter ...
 func GetConfigCenter(name string, config *common.URL) (config_center.DynamicConfiguration, error) {
 	if configCenters[name] == nil {
 		panic("config center for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/config_center_factory.go b/common/extension/config_center_factory.go
index 82e0ef6ebcf632ccff32aec5c69c2082a28c51af..85913fdce1ed3472c2bd9eb4aadbb0f631481dbd 100644
--- a/common/extension/config_center_factory.go
+++ b/common/extension/config_center_factory.go
@@ -25,10 +25,12 @@ var (
 	configCenterFactories = make(map[string]func() config_center.DynamicConfigurationFactory)
 )
 
+// SetConfigCenterFactory ...
 func SetConfigCenterFactory(name string, v func() config_center.DynamicConfigurationFactory) {
 	configCenterFactories[name] = v
 }
 
+// GetConfigCenterFactory ...
 func GetConfigCenterFactory(name string) config_center.DynamicConfigurationFactory {
 	if configCenterFactories[name] == nil {
 		panic("config center for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/configurator.go b/common/extension/configurator.go
index 40d134f474ae792afb76f1d8e3f56d172bfd07e2..de98f8a260ea1f3a2e2a1f32c82dc869585e2789 100644
--- a/common/extension/configurator.go
+++ b/common/extension/configurator.go
@@ -22,7 +22,10 @@ import (
 	"github.com/apache/dubbo-go/config_center"
 )
 
-const DefaultKey = "default"
+const (
+	// DefaultKey ...
+	DefaultKey = "default"
+)
 
 type getConfiguratorFunc func(url *common.URL) config_center.Configurator
 
@@ -30,10 +33,12 @@ var (
 	configurator = make(map[string]getConfiguratorFunc)
 )
 
+// SetConfigurator ...
 func SetConfigurator(name string, v getConfiguratorFunc) {
 	configurator[name] = v
 }
 
+// GetConfigurator ...
 func GetConfigurator(name string, url *common.URL) config_center.Configurator {
 	if configurator[name] == nil {
 		panic("configurator for " + name + " is not existing, make sure you have import the package.")
@@ -41,10 +46,13 @@ func GetConfigurator(name string, url *common.URL) config_center.Configurator {
 	return configurator[name](url)
 
 }
+
+// SetDefaultConfigurator ...
 func SetDefaultConfigurator(v getConfiguratorFunc) {
 	configurator[DefaultKey] = v
 }
 
+// GetDefaultConfigurator ...
 func GetDefaultConfigurator(url *common.URL) config_center.Configurator {
 	if configurator[DefaultKey] == nil {
 		panic("configurator for default is not existing, make sure you have import the package.")
@@ -52,6 +60,8 @@ func GetDefaultConfigurator(url *common.URL) config_center.Configurator {
 	return configurator[DefaultKey](url)
 
 }
+
+// GetDefaultConfiguratorFunc ...
 func GetDefaultConfiguratorFunc() getConfiguratorFunc {
 	if configurator[DefaultKey] == nil {
 		panic("configurator for default is not existing, make sure you have import the package.")
diff --git a/common/extension/filter.go b/common/extension/filter.go
index 93f7f8cf7ccc4108fe1120b685fad36a2f9f83df..deea2d908bc2741e0f15ecc36e9d4fc5975e531e 100644
--- a/common/extension/filter.go
+++ b/common/extension/filter.go
@@ -19,18 +19,19 @@ package extension
 
 import (
 	"github.com/apache/dubbo-go/filter"
-	"github.com/apache/dubbo-go/filter/common"
 )
 
 var (
 	filters                  = make(map[string]func() filter.Filter)
-	rejectedExecutionHandler = make(map[string]func() common.RejectedExecutionHandler)
+	rejectedExecutionHandler = make(map[string]func() filter.RejectedExecutionHandler)
 )
 
+// SetFilter ...
 func SetFilter(name string, v func() filter.Filter) {
 	filters[name] = v
 }
 
+// GetFilter ...
 func GetFilter(name string) filter.Filter {
 	if filters[name] == nil {
 		panic("filter for " + name + " is not existing, make sure you have imported the package.")
@@ -38,11 +39,13 @@ func GetFilter(name string) filter.Filter {
 	return filters[name]()
 }
 
-func SetRejectedExecutionHandler(name string, creator func() common.RejectedExecutionHandler) {
+// SetRejectedExecutionHandler ...
+func SetRejectedExecutionHandler(name string, creator func() filter.RejectedExecutionHandler) {
 	rejectedExecutionHandler[name] = creator
 }
 
-func GetRejectedExecutionHandler(name string) common.RejectedExecutionHandler {
+// GetRejectedExecutionHandler ...
+func GetRejectedExecutionHandler(name string) filter.RejectedExecutionHandler {
 	creator, ok := rejectedExecutionHandler[name]
 	if !ok {
 		panic("RejectedExecutionHandler for " + name + " is not existing, make sure you have import the package " +
diff --git a/common/extension/graceful_shutdown.go b/common/extension/graceful_shutdown.go
index c8807fcc28c18c1a6fddb4e97708e9b0d5cda243..3abd75c0aa328f3553c3d83340ae440b8dfe3356 100644
--- a/common/extension/graceful_shutdown.go
+++ b/common/extension/graceful_shutdown.go
@@ -26,6 +26,7 @@ var (
 )
 
 /**
+ * AddCustomShutdownCallback
  * you should not make any assumption about the order.
  * For example, if you have more than one callbacks, and you wish the order is:
  * callback1()
@@ -48,6 +49,7 @@ func AddCustomShutdownCallback(callback func()) {
 	customShutdownCallbacks.PushBack(callback)
 }
 
+// GetAllCustomShutdownCallbacks ...
 func GetAllCustomShutdownCallbacks() *list.List {
 	return customShutdownCallbacks
 }
diff --git a/common/extension/loadbalance.go b/common/extension/loadbalance.go
index f1f97b9399a2b33a3e06213fc0b2f84e73b002b7..0d557a4640ed892a18ad59a3247763ab5807a593 100644
--- a/common/extension/loadbalance.go
+++ b/common/extension/loadbalance.go
@@ -25,10 +25,12 @@ var (
 	loadbalances = make(map[string]func() cluster.LoadBalance)
 )
 
+// SetLoadbalance ...
 func SetLoadbalance(name string, fcn func() cluster.LoadBalance) {
 	loadbalances[name] = fcn
 }
 
+// GetLoadbalance ...
 func GetLoadbalance(name string) cluster.LoadBalance {
 	if loadbalances[name] == nil {
 		panic("loadbalance for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/metrics.go b/common/extension/metrics.go
new file mode 100644
index 0000000000000000000000000000000000000000..42fca7a2db36614fcef31dd5ba7324a156164d4f
--- /dev/null
+++ b/common/extension/metrics.go
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package extension
+
+import (
+	"github.com/apache/dubbo-go/metrics"
+)
+
+var (
+	// we couldn't store the instance because the some instance may initialize before loading configuration
+	// so lazy initialization will be better.
+	metricReporterMap = make(map[string]func() metrics.Reporter, 4)
+)
+
+// SetMetricReporter set a reporter with the name
+func SetMetricReporter(name string, reporterFunc func() metrics.Reporter) {
+	metricReporterMap[name] = reporterFunc
+}
+
+// GetMetricReporter find the reporter with name.
+// if not found, it will panic.
+// we should know that this method usually is called when system starts, so we should panic
+func GetMetricReporter(name string) metrics.Reporter {
+	reporterFunc, found := metricReporterMap[name]
+	if !found {
+		panic("Cannot find the reporter with name: " + name)
+	}
+	return reporterFunc()
+}
diff --git a/common/extension/metrics_test.go b/common/extension/metrics_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6a8a3fe538a9cd68c57c91592a88ec257ae4a267
--- /dev/null
+++ b/common/extension/metrics_test.go
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package extension
+
+import (
+	"context"
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/metrics"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+func TestGetMetricReporter(t *testing.T) {
+	reporter := &mockReporter{}
+	name := "mock"
+	SetMetricReporter(name, func() metrics.Reporter {
+		return reporter
+	})
+	res := GetMetricReporter(name)
+	assert.Equal(t, reporter, res)
+}
+
+type mockReporter struct {
+}
+
+func (m mockReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) {
+}
diff --git a/common/extension/protocol.go b/common/extension/protocol.go
index 50d339476d024c04b182c38632689a99bc5c1680..009687a17ace8cea567248af655e04604d09d9b8 100644
--- a/common/extension/protocol.go
+++ b/common/extension/protocol.go
@@ -25,10 +25,12 @@ var (
 	protocols = make(map[string]func() protocol.Protocol)
 )
 
+// SetProtocol ...
 func SetProtocol(name string, v func() protocol.Protocol) {
 	protocols[name] = v
 }
 
+// GetProtocol ...
 func GetProtocol(name string) protocol.Protocol {
 	if protocols[name] == nil {
 		panic("protocol for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/proxy_factory.go b/common/extension/proxy_factory.go
index 53cbbee54054bf8ad87964393b01ca6601106066..19826bb0560ea0d3fa471c04873b20a6878f57d8 100644
--- a/common/extension/proxy_factory.go
+++ b/common/extension/proxy_factory.go
@@ -22,18 +22,21 @@ import (
 )
 
 var (
-	proxy_factories = make(map[string]func(...proxy.Option) proxy.ProxyFactory)
+	proxyFactories = make(map[string]func(...proxy.Option) proxy.ProxyFactory)
 )
 
+// SetProxyFactory ...
 func SetProxyFactory(name string, f func(...proxy.Option) proxy.ProxyFactory) {
-	proxy_factories[name] = f
+	proxyFactories[name] = f
 }
+
+// GetProxyFactory ...
 func GetProxyFactory(name string) proxy.ProxyFactory {
 	if name == "" {
 		name = "default"
 	}
-	if proxy_factories[name] == nil {
+	if proxyFactories[name] == nil {
 		panic("proxy factory for " + name + " is not existing, make sure you have import the package.")
 	}
-	return proxy_factories[name]()
+	return proxyFactories[name]()
 }
diff --git a/common/extension/registry.go b/common/extension/registry.go
index 776c2b5df542e56f8c120c850f20093a971d8602..6ba746dc47382927d12ce39b7936212c5d75153d 100644
--- a/common/extension/registry.go
+++ b/common/extension/registry.go
@@ -26,10 +26,12 @@ var (
 	registrys = make(map[string]func(config *common.URL) (registry.Registry, error))
 )
 
+// SetRegistry ...
 func SetRegistry(name string, v func(config *common.URL) (registry.Registry, error)) {
 	registrys[name] = v
 }
 
+// GetRegistry ...
 func GetRegistry(name string, config *common.URL) (registry.Registry, error) {
 	if registrys[name] == nil {
 		panic("registry for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/router_factory.go b/common/extension/router_factory.go
index 6f27aafaebf87147116e74272cc229657f436201..c77cc291369ab02c5f58dfc6c283902ac0df4b95 100644
--- a/common/extension/router_factory.go
+++ b/common/extension/router_factory.go
@@ -25,10 +25,12 @@ var (
 	routers = make(map[string]func() cluster.RouterFactory)
 )
 
+// SetRouterFactory ...
 func SetRouterFactory(name string, fun func() cluster.RouterFactory) {
 	routers[name] = fun
 }
 
+// GetRouterFactory ...
 func GetRouterFactory(name string) cluster.RouterFactory {
 	if routers[name] == nil {
 		panic("router_factory for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/tps_limit.go b/common/extension/tps_limit.go
index 151c33ad5e64ffa4059489e2cbcfae6f2e823328..c72c2b030fc0f391362189bfe18a65582543693a 100644
--- a/common/extension/tps_limit.go
+++ b/common/extension/tps_limit.go
@@ -18,19 +18,21 @@
 package extension
 
 import (
-	"github.com/apache/dubbo-go/filter/impl/tps"
+	"github.com/apache/dubbo-go/filter"
 )
 
 var (
-	tpsLimitStrategy = make(map[string]tps.TpsLimitStrategyCreator)
-	tpsLimiter       = make(map[string]func() tps.TpsLimiter)
+	tpsLimitStrategy = make(map[string]filter.TpsLimitStrategyCreator)
+	tpsLimiter       = make(map[string]func() filter.TpsLimiter)
 )
 
-func SetTpsLimiter(name string, creator func() tps.TpsLimiter) {
+// SetTpsLimiter ...
+func SetTpsLimiter(name string, creator func() filter.TpsLimiter) {
 	tpsLimiter[name] = creator
 }
 
-func GetTpsLimiter(name string) tps.TpsLimiter {
+// GetTpsLimiter ...
+func GetTpsLimiter(name string) filter.TpsLimiter {
 	creator, ok := tpsLimiter[name]
 	if !ok {
 		panic("TpsLimiter for " + name + " is not existing, make sure you have import the package " +
@@ -39,11 +41,13 @@ func GetTpsLimiter(name string) tps.TpsLimiter {
 	return creator()
 }
 
-func SetTpsLimitStrategy(name string, creator tps.TpsLimitStrategyCreator) {
+// SetTpsLimitStrategy ...
+func SetTpsLimitStrategy(name string, creator filter.TpsLimitStrategyCreator) {
 	tpsLimitStrategy[name] = creator
 }
 
-func GetTpsLimitStrategyCreator(name string) tps.TpsLimitStrategyCreator {
+// GetTpsLimitStrategyCreator ...
+func GetTpsLimitStrategyCreator(name string) filter.TpsLimitStrategyCreator {
 	creator, ok := tpsLimitStrategy[name]
 	if !ok {
 		panic("TpsLimitStrategy for " + name + " is not existing, make sure you have import the package " +
diff --git a/common/logger/logger.go b/common/logger/logger.go
index db91d2e7c1e5f7a647eefbfa5aec14073c2b14a7..016afe69808f2007541c617f406db64beb511f1c 100644
--- a/common/logger/logger.go
+++ b/common/logger/logger.go
@@ -40,11 +40,13 @@ var (
 	logger Logger
 )
 
+// DubboLogger ...
 type DubboLogger struct {
 	Logger
 	dynamicLevel zap.AtomicLevel
 }
 
+// Logger ...
 type Logger interface {
 	Info(args ...interface{})
 	Warn(args ...interface{})
@@ -65,6 +67,7 @@ func init() {
 	}
 }
 
+// InitLog ...
 func InitLog(logConfFile string) error {
 	if logConfFile == "" {
 		InitLogger(nil)
@@ -93,6 +96,7 @@ func InitLog(logConfFile string) error {
 	return nil
 }
 
+// InitLogger ...
 func InitLogger(conf *zap.Config) {
 	var zapLoggerConfig zap.Config
 	if conf == nil {
@@ -121,15 +125,18 @@ func InitLogger(conf *zap.Config) {
 	getty.SetLogger(logger)
 }
 
+// SetLogger ...
 func SetLogger(log Logger) {
 	logger = log
 	getty.SetLogger(logger)
 }
 
+// GetLogger ...
 func GetLogger() Logger {
 	return logger
 }
 
+// SetLoggerLevel ...
 func SetLoggerLevel(level string) bool {
 	if l, ok := logger.(OpsLogger); ok {
 		l.SetLoggerLevel(level)
@@ -138,11 +145,13 @@ func SetLoggerLevel(level string) bool {
 	return false
 }
 
+// OpsLogger ...
 type OpsLogger interface {
 	Logger
 	SetLoggerLevel(level string)
 }
 
+// SetLoggerLevel ...
 func (dl *DubboLogger) SetLoggerLevel(level string) {
 	l := new(zapcore.Level)
 	l.Set(level)
diff --git a/common/logger/logging.go b/common/logger/logging.go
index 4638c9a41dfe986d256e1ff4d52b690c1747fc94..36d48ee61e8a4a986abfbaa79f3d361cd81494f4 100644
--- a/common/logger/logging.go
+++ b/common/logger/logging.go
@@ -17,27 +17,42 @@
 
 package logger
 
+// Info ...
 func Info(args ...interface{}) {
 	logger.Info(args...)
 }
+
+// Warn ...
 func Warn(args ...interface{}) {
 	logger.Warn(args...)
 }
+
+// Error ...
 func Error(args ...interface{}) {
 	logger.Error(args...)
 }
+
+// Debug ...
 func Debug(args ...interface{}) {
 	logger.Debug(args...)
 }
+
+// Infof ...
 func Infof(fmt string, args ...interface{}) {
 	logger.Infof(fmt, args...)
 }
+
+// Warnf ...
 func Warnf(fmt string, args ...interface{}) {
 	logger.Warnf(fmt, args...)
 }
+
+// Errorf ...
 func Errorf(fmt string, args ...interface{}) {
 	logger.Errorf(fmt, args...)
 }
+
+// Debugf ...
 func Debugf(fmt string, args ...interface{}) {
 	logger.Debugf(fmt, args...)
 }
diff --git a/common/node.go b/common/node.go
index 992ead38d8acf85bbb14f02eebca4c4fe5a0a1e2..979eee31ef3a63eb21af6c9045aee7f6d784f2ba 100644
--- a/common/node.go
+++ b/common/node.go
@@ -17,6 +17,7 @@
 
 package common
 
+// Node ...
 type Node interface {
 	GetUrl() URL
 	IsAvailable() bool
diff --git a/common/proxy/proxy.go b/common/proxy/proxy.go
index d13646dba86eea04adb3726d33ee9d20457276b6..43ca720d0e71577a446829f702c1d2fe23a32905 100644
--- a/common/proxy/proxy.go
+++ b/common/proxy/proxy.go
@@ -18,6 +18,7 @@
 package proxy
 
 import (
+	"context"
 	"reflect"
 	"sync"
 )
@@ -39,8 +40,11 @@ type Proxy struct {
 	once sync.Once
 }
 
-var typError = reflect.Zero(reflect.TypeOf((*error)(nil)).Elem()).Type()
+var (
+	typError = reflect.Zero(reflect.TypeOf((*error)(nil)).Elem()).Type()
+)
 
+// NewProxy ...
 func NewProxy(invoke protocol.Invoker, callBack interface{}, attachments map[string]string) *Proxy {
 	return &Proxy{
 		invoke:      invoke,
@@ -49,6 +53,7 @@ func NewProxy(invoke protocol.Invoker, callBack interface{}, attachments map[str
 	}
 }
 
+// Implement
 // proxy implement
 // In consumer, RPCService like:
 // 		type XxxProvider struct {
@@ -72,10 +77,11 @@ func (p *Proxy) Implement(v common.RPCService) {
 	makeDubboCallProxy := func(methodName string, outs []reflect.Type) func(in []reflect.Value) []reflect.Value {
 		return func(in []reflect.Value) []reflect.Value {
 			var (
-				err   error
-				inv   *invocation_impl.RPCInvocation
-				inArr []interface{}
-				reply reflect.Value
+				err    error
+				inv    *invocation_impl.RPCInvocation
+				inIArr []interface{}
+				inVArr []reflect.Value
+				reply  reflect.Value
 			)
 			if methodName == "Echo" {
 				methodName = "$echo"
@@ -93,8 +99,13 @@ func (p *Proxy) Implement(v common.RPCService) {
 
 			start := 0
 			end := len(in)
+			invCtx := context.Background()
 			if end > 0 {
 				if in[0].Type().String() == "context.Context" {
+					if !in[0].IsNil() {
+						// the user declared context as method's parameter
+						invCtx = in[0].Interface().(context.Context)
+					}
 					start += 1
 				}
 				if len(outs) == 1 && in[end-1].Type().Kind() == reflect.Ptr {
@@ -104,27 +115,31 @@ func (p *Proxy) Implement(v common.RPCService) {
 			}
 
 			if end-start <= 0 {
-				inArr = []interface{}{}
+				inIArr = []interface{}{}
+				inVArr = []reflect.Value{}
 			} else if v, ok := in[start].Interface().([]interface{}); ok && end-start == 1 {
-				inArr = v
+				inIArr = v
+				inVArr = []reflect.Value{in[start]}
 			} else {
-				inArr = make([]interface{}, end-start)
+				inIArr = make([]interface{}, end-start)
+				inVArr = make([]reflect.Value, end-start)
 				index := 0
 				for i := start; i < end; i++ {
-					inArr[index] = in[i].Interface()
+					inIArr[index] = in[i].Interface()
+					inVArr[index] = in[i]
 					index++
 				}
 			}
 
 			inv = invocation_impl.NewRPCInvocationWithOptions(invocation_impl.WithMethodName(methodName),
-				invocation_impl.WithArguments(inArr), invocation_impl.WithReply(reply.Interface()),
-				invocation_impl.WithCallBack(p.callBack))
+				invocation_impl.WithArguments(inIArr), invocation_impl.WithReply(reply.Interface()),
+				invocation_impl.WithCallBack(p.callBack), invocation_impl.WithParameterValues(inVArr))
 
 			for k, value := range p.attachments {
 				inv.SetAttachments(k, value)
 			}
 
-			result := p.invoke.Invoke(inv)
+			result := p.invoke.Invoke(invCtx, inv)
 
 			err = result.Error()
 			logger.Infof("[makeDubboCallProxy] result: %v, err: %v", result.Result(), err)
@@ -178,10 +193,12 @@ func (p *Proxy) Implement(v common.RPCService) {
 
 }
 
+// Get ...
 func (p *Proxy) Get() common.RPCService {
 	return p.rpc
 }
 
+// GetCallback ...
 func (p *Proxy) GetCallback() interface{} {
 	return p.callBack
 }
diff --git a/common/proxy/proxy_factory.go b/common/proxy/proxy_factory.go
index 116cfe06693b6923ca10e0df6964317dabd91d0e..7b249a3e9754b097130a80bf3819d282dad6b6e8 100644
--- a/common/proxy/proxy_factory.go
+++ b/common/proxy/proxy_factory.go
@@ -22,10 +22,12 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// ProxyFactory ...
 type ProxyFactory interface {
 	GetProxy(invoker protocol.Invoker, url *common.URL) *Proxy
 	GetAsyncProxy(invoker protocol.Invoker, callBack interface{}, url *common.URL) *Proxy
 	GetInvoker(url common.URL) protocol.Invoker
 }
 
+// Option ...
 type Option func(ProxyFactory)
diff --git a/common/proxy/proxy_factory/default.go b/common/proxy/proxy_factory/default.go
index 06824fdc1e27cde5e1905be3277451dd4395049c..114cfee2363022da5f7957a825a16fc42b8c928f 100644
--- a/common/proxy/proxy_factory/default.go
+++ b/common/proxy/proxy_factory/default.go
@@ -18,6 +18,7 @@
 package proxy_factory
 
 import (
+	"context"
 	"reflect"
 	"strings"
 )
@@ -39,6 +40,7 @@ func init() {
 	extension.SetProxyFactory("default", NewDefaultProxyFactory)
 }
 
+// DefaultProxyFactory ...
 type DefaultProxyFactory struct {
 	//delegate ProxyFactory
 }
@@ -51,13 +53,17 @@ type DefaultProxyFactory struct {
 //	}
 //}
 
+// NewDefaultProxyFactory ...
 func NewDefaultProxyFactory(options ...proxy.Option) proxy.ProxyFactory {
 	return &DefaultProxyFactory{}
 }
+
+// GetProxy ...
 func (factory *DefaultProxyFactory) GetProxy(invoker protocol.Invoker, url *common.URL) *proxy.Proxy {
 	return factory.GetAsyncProxy(invoker, nil, url)
 }
 
+// GetAsyncProxy ...
 func (factory *DefaultProxyFactory) GetAsyncProxy(invoker protocol.Invoker, callBack interface{}, url *common.URL) *proxy.Proxy {
 	//create proxy
 	attachments := map[string]string{}
@@ -65,17 +71,20 @@ func (factory *DefaultProxyFactory) GetAsyncProxy(invoker protocol.Invoker, call
 	return proxy.NewProxy(invoker, callBack, attachments)
 }
 
+// GetInvoker ...
 func (factory *DefaultProxyFactory) GetInvoker(url common.URL) protocol.Invoker {
 	return &ProxyInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
 	}
 }
 
+// ProxyInvoker ...
 type ProxyInvoker struct {
 	protocol.BaseInvoker
 }
 
-func (pi *ProxyInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+// Invoke ...
+func (pi *ProxyInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	result := &protocol.RPCResult{}
 	result.SetAttachments(invocation.Attachments())
 
@@ -104,7 +113,7 @@ func (pi *ProxyInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
 
 	in := []reflect.Value{svc.Rcvr()}
 	if method.CtxType() != nil {
-		in = append(in, method.SuiteContext(nil)) // todo: ctx will be used later.
+		in = append(in, method.SuiteContext(ctx))
 	}
 
 	// prepare argv
diff --git a/common/rpc_service.go b/common/rpc_service.go
index 4c9f083dd0850c3f110491ef820c7b677c8009aa..b235c32abc9a971d7144605c8b4b82953ac8f3c4 100644
--- a/common/rpc_service.go
+++ b/common/rpc_service.go
@@ -34,19 +34,22 @@ import (
 	"github.com/apache/dubbo-go/common/logger"
 )
 
-// rpc service interface
+// RPCService
+//rpc service interface
 type RPCService interface {
-	Reference() string // rpc service id or reference id
+	// Reference:
+	// rpc service id or reference id
+	Reference() string
 }
 
 //AsyncCallbackService callback interface for async
 type AsyncCallbackService interface {
-	CallBack(response CallbackResponse) // callback
+	// Callback: callback
+	CallBack(response CallbackResponse)
 }
 
 //CallbackResponse for different protocol
-type CallbackResponse interface {
-}
+type CallbackResponse interface{}
 
 //AsyncCallback async callback method
 type AsyncCallback func(response CallbackResponse)
@@ -55,13 +58,17 @@ type AsyncCallback func(response CallbackResponse)
 // func MethodMapper() map[string][string] {
 //     return map[string][string]{}
 // }
-const METHOD_MAPPER = "MethodMapper"
+const (
+	// METHOD_MAPPER ...
+	METHOD_MAPPER = "MethodMapper"
+)
 
 var (
 	// Precompute the reflect type for error. Can't use error directly
 	// because Typeof takes an empty interface value. This is annoying.
 	typeOfError = reflect.TypeOf((*error)(nil)).Elem()
 
+	// ServiceMap ...
 	// todo: lowerecas?
 	ServiceMap = &serviceMap{
 		serviceMap: make(map[string]map[string]*Service),
@@ -72,6 +79,7 @@ var (
 // info of method
 //////////////////////////
 
+// MethodType ...
 type MethodType struct {
 	method    reflect.Method
 	ctxType   reflect.Type   // request context
@@ -79,18 +87,27 @@ type MethodType struct {
 	replyType reflect.Type   // return value, otherwise it is nil
 }
 
+// Method ...
 func (m *MethodType) Method() reflect.Method {
 	return m.method
 }
+
+// CtxType ...
 func (m *MethodType) CtxType() reflect.Type {
 	return m.ctxType
 }
+
+// ArgsType ...
 func (m *MethodType) ArgsType() []reflect.Type {
 	return m.argsType
 }
+
+// ReplyType ...
 func (m *MethodType) ReplyType() reflect.Type {
 	return m.replyType
 }
+
+// SuiteContext ...
 func (m *MethodType) SuiteContext(ctx context.Context) reflect.Value {
 	if contextv := reflect.ValueOf(ctx); contextv.IsValid() {
 		return contextv
@@ -102,6 +119,7 @@ func (m *MethodType) SuiteContext(ctx context.Context) reflect.Value {
 // info of service interface
 //////////////////////////
 
+// Service ...
 type Service struct {
 	name     string
 	rcvr     reflect.Value
@@ -109,12 +127,17 @@ type Service struct {
 	methods  map[string]*MethodType
 }
 
+// Method ...
 func (s *Service) Method() map[string]*MethodType {
 	return s.methods
 }
+
+// RcvrType ...
 func (s *Service) RcvrType() reflect.Type {
 	return s.rcvrType
 }
+
+// Rcvr ...
 func (s *Service) Rcvr() reflect.Value {
 	return s.rcvr
 }
@@ -210,8 +233,8 @@ func (sm *serviceMap) UnRegister(protocol, serviceId string) error {
 
 // Is this an exported - upper case - name
 func isExported(name string) bool {
-	rune, _ := utf8.DecodeRuneInString(name)
-	return unicode.IsUpper(rune)
+	s, _ := utf8.DecodeRuneInString(name)
+	return unicode.IsUpper(s)
 }
 
 // Is this type exported or a builtin?
diff --git a/common/rpc_service_test.go b/common/rpc_service_test.go
index 7df039b905d3cc064c5d6d9404fc874cf693dac9..8c9b9d15cdd4061dbe2f445b5fff7a868e5ae67e 100644
--- a/common/rpc_service_test.go
+++ b/common/rpc_service_test.go
@@ -122,9 +122,8 @@ func TestServiceMap_UnRegister(t *testing.T) {
 
 func TestMethodType_SuiteContext(t *testing.T) {
 	mt := &MethodType{ctxType: reflect.TypeOf(context.TODO())}
-	c := context.TODO()
-	c = context.WithValue(c, "key", "value")
-	assert.Equal(t, reflect.ValueOf(c), mt.SuiteContext(c))
+	ctx := context.WithValue(context.Background(), "key", "value")
+	assert.Equal(t, reflect.ValueOf(ctx), mt.SuiteContext(ctx))
 
 	assert.Equal(t, reflect.Zero(mt.ctxType), mt.SuiteContext(nil))
 }
diff --git a/common/url.go b/common/url.go
index c010298bf58d65b6c2fcfc7859e03b0131bf7f54..360f0aa4caa185d8086eb07497176ae627f47d47 100644
--- a/common/url.go
+++ b/common/url.go
@@ -19,7 +19,6 @@ package common
 
 import (
 	"bytes"
-	"context"
 	"encoding/base64"
 	"fmt"
 	"math"
@@ -31,7 +30,7 @@ import (
 )
 
 import (
-	"github.com/dubbogo/gost/container/gxset"
+	gxset "github.com/dubbogo/gost/container/set"
 	"github.com/jinzhu/copier"
 	perrors "github.com/pkg/errors"
 	"github.com/satori/go.uuid"
@@ -45,24 +44,33 @@ import (
 // dubbo role type
 /////////////////////////////////
 
+// role constant
 const (
+	// CONSUMER ...
 	CONSUMER = iota
+	// CONFIGURATOR ...
 	CONFIGURATOR
+	// ROUTER ...
 	ROUTER
+	// PROVIDER ...
 	PROVIDER
 )
 
 var (
+	// DubboNodes ...
 	DubboNodes = [...]string{"consumers", "configurators", "routers", "providers"}
-	DubboRole  = [...]string{"consumer", "", "", "provider"}
+	// DubboRole ...
+	DubboRole = [...]string{"consumer", "", "", "provider"}
 )
 
+// RoleType ...
 type RoleType int
 
 func (t RoleType) String() string {
 	return DubboNodes[t]
 }
 
+// Role ...
 func (t RoleType) Role() string {
 	return DubboRole[t]
 }
@@ -76,9 +84,9 @@ type baseUrl struct {
 	paramsLock   sync.RWMutex
 	params       url.Values
 	PrimitiveURL string
-	ctx          context.Context
 }
 
+// URL ...
 type URL struct {
 	baseUrl
 	Path     string // like  /com.ikurento.dubbo.UserProvider3
@@ -91,66 +99,77 @@ type URL struct {
 
 type option func(*URL)
 
+// WithUsername ...
 func WithUsername(username string) option {
 	return func(url *URL) {
 		url.Username = username
 	}
 }
 
+// WithPassword ...
 func WithPassword(pwd string) option {
 	return func(url *URL) {
 		url.Password = pwd
 	}
 }
 
+// WithMethods ...
 func WithMethods(methods []string) option {
 	return func(url *URL) {
 		url.Methods = methods
 	}
 }
 
+// WithParams ...
 func WithParams(params url.Values) option {
 	return func(url *URL) {
 		url.params = params
 	}
 }
 
+// WithParamsValue ...
 func WithParamsValue(key, val string) option {
 	return func(url *URL) {
 		url.SetParam(key, val)
 	}
 }
 
+// WithProtocol ...
 func WithProtocol(proto string) option {
 	return func(url *URL) {
 		url.Protocol = proto
 	}
 }
 
+// WithIp ...
 func WithIp(ip string) option {
 	return func(url *URL) {
 		url.Ip = ip
 	}
 }
 
+// WithPort ...
 func WithPort(port string) option {
 	return func(url *URL) {
 		url.Port = port
 	}
 }
 
+// WithPath ...
 func WithPath(path string) option {
 	return func(url *URL) {
 		url.Path = "/" + strings.TrimPrefix(path, "/")
 	}
 }
 
+// WithLocation ...
 func WithLocation(location string) option {
 	return func(url *URL) {
 		url.Location = location
 	}
 }
 
+// WithToken ...
 func WithToken(token string) option {
 	return func(url *URL) {
 		if len(token) > 0 {
@@ -163,6 +182,7 @@ func WithToken(token string) option {
 	}
 }
 
+// NewURLWithOptions ...
 func NewURLWithOptions(opts ...option) *URL {
 	url := &URL{}
 	for _, opt := range opts {
@@ -172,13 +192,15 @@ func NewURLWithOptions(opts ...option) *URL {
 	return url
 }
 
-func NewURL(ctx context.Context, urlString string, opts ...option) (URL, error) {
+// NewURL will create a new url
+// the urlString should not be empty
+func NewURL(urlString string, opts ...option) (URL, error) {
 
 	var (
 		err          error
 		rawUrlString string
 		serviceUrl   *url.URL
-		s            = URL{baseUrl: baseUrl{ctx: ctx}}
+		s            = URL{baseUrl: baseUrl{}}
 	)
 
 	// new a null instance
@@ -193,7 +215,7 @@ func NewURL(ctx context.Context, urlString string, opts ...option) (URL, error)
 
 	//rawUrlString = "//" + rawUrlString
 	if strings.Index(rawUrlString, "//") < 0 {
-		t := URL{baseUrl: baseUrl{ctx: ctx}}
+		t := URL{baseUrl: baseUrl{}}
 		for _, opt := range opts {
 			opt(&t)
 		}
@@ -227,6 +249,7 @@ func NewURL(ctx context.Context, urlString string, opts ...option) (URL, error)
 	return s, nil
 }
 
+// URLEqual ...
 func (c URL) URLEqual(url URL) bool {
 	c.Ip = ""
 	c.Port = ""
@@ -282,6 +305,7 @@ func (c URL) String() string {
 	return buildString
 }
 
+// Key ...
 func (c URL) Key() string {
 	buildString := fmt.Sprintf(
 		"%s://%s:%s@%s:%s/?interface=%s&group=%s&version=%s",
@@ -290,6 +314,7 @@ func (c URL) Key() string {
 	//return c.ServiceKey()
 }
 
+// ServiceKey ...
 func (c URL) ServiceKey() string {
 	intf := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
 	if intf == "" {
@@ -313,15 +338,35 @@ func (c URL) ServiceKey() string {
 	return buf.String()
 }
 
+// ColonSeparatedKey
+// The format is "{interface}:[version]:[group]"
+func (c *URL) ColonSeparatedKey() string {
+	intf := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
+	if intf == "" {
+		return ""
+	}
+	buf := &bytes.Buffer{}
+	buf.WriteString(intf)
+	buf.WriteString(":")
+	version := c.GetParam(constant.VERSION_KEY, "")
+	if version != "" && version != "0.0.0" {
+		buf.WriteString(version)
+	}
+	group := c.GetParam(constant.GROUP_KEY, "")
+	buf.WriteString(":")
+	if group != "" {
+		buf.WriteString(group)
+	}
+	return buf.String()
+}
+
+// EncodedServiceKey ...
 func (c *URL) EncodedServiceKey() string {
 	serviceKey := c.ServiceKey()
 	return strings.Replace(serviceKey, "/", "*", 1)
 }
 
-func (c URL) Context() context.Context {
-	return c.ctx
-}
-
+// Service ...
 func (c URL) Service() string {
 	service := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
 	if service != "" {
@@ -335,18 +380,21 @@ func (c URL) Service() string {
 	return ""
 }
 
+// AddParam ...
 func (c *URL) AddParam(key string, value string) {
 	c.paramsLock.Lock()
 	c.params.Add(key, value)
 	c.paramsLock.Unlock()
 }
 
+// SetParam ...
 func (c *URL) SetParam(key string, value string) {
 	c.paramsLock.Lock()
 	c.params.Set(key, value)
 	c.paramsLock.Unlock()
 }
 
+// RangeParams ...
 func (c *URL) RangeParams(f func(key, value string) bool) {
 	c.paramsLock.RLock()
 	defer c.paramsLock.RUnlock()
@@ -357,6 +405,7 @@ func (c *URL) RangeParams(f func(key, value string) bool) {
 	}
 }
 
+// GetParam ...
 func (c URL) GetParam(s string, d string) string {
 	var r string
 	c.paramsLock.RLock()
@@ -367,10 +416,12 @@ func (c URL) GetParam(s string, d string) string {
 	return r
 }
 
+// GetParams ...
 func (c URL) GetParams() url.Values {
 	return c.params
 }
 
+// GetParamAndDecoded ...
 func (c URL) GetParamAndDecoded(key string) (string, error) {
 	c.paramsLock.RLock()
 	defer c.paramsLock.RUnlock()
@@ -379,6 +430,7 @@ func (c URL) GetParamAndDecoded(key string) (string, error) {
 	return value, err
 }
 
+// GetRawParam ...
 func (c URL) GetRawParam(key string) string {
 	switch key {
 	case "protocol":
@@ -398,7 +450,7 @@ func (c URL) GetRawParam(key string) string {
 	}
 }
 
-// GetParamBool
+// GetParamBool ...
 func (c URL) GetParamBool(s string, d bool) bool {
 
 	var r bool
@@ -409,6 +461,7 @@ func (c URL) GetParamBool(s string, d bool) bool {
 	return r
 }
 
+// GetParamInt ...
 func (c URL) GetParamInt(s string, d int64) int64 {
 	var r int
 	var err error
@@ -419,6 +472,7 @@ func (c URL) GetParamInt(s string, d int64) int64 {
 	return int64(r)
 }
 
+// GetMethodParamInt ...
 func (c URL) GetMethodParamInt(method string, key string, d int64) int64 {
 	var r int
 	var err error
@@ -430,6 +484,7 @@ func (c URL) GetMethodParamInt(method string, key string, d int64) int64 {
 	return int64(r)
 }
 
+// GetMethodParamInt64 ...
 func (c URL) GetMethodParamInt64(method string, key string, d int64) int64 {
 	r := c.GetMethodParamInt(method, key, math.MinInt64)
 	if r == math.MinInt64 {
@@ -439,6 +494,7 @@ func (c URL) GetMethodParamInt64(method string, key string, d int64) int64 {
 	return r
 }
 
+// GetMethodParam ...
 func (c URL) GetMethodParam(method string, key string, d string) string {
 	var r string
 	if r = c.GetParam("methods."+method+"."+key, ""); r == "" {
@@ -447,11 +503,13 @@ func (c URL) GetMethodParam(method string, key string, d string) string {
 	return r
 }
 
+// GetMethodParamBool ...
 func (c URL) GetMethodParamBool(method string, key string, d bool) bool {
 	r := c.GetParamBool("methods."+method+"."+key, d)
 	return r
 }
 
+// RemoveParams ...
 func (c *URL) RemoveParams(set *gxset.HashSet) {
 	c.paramsLock.Lock()
 	defer c.paramsLock.Unlock()
@@ -461,6 +519,7 @@ func (c *URL) RemoveParams(set *gxset.HashSet) {
 	}
 }
 
+// SetParams ...
 func (c *URL) SetParams(m url.Values) {
 	for k := range m {
 		c.SetParam(k, m.Get(k))
@@ -512,6 +571,7 @@ func (c URL) ToMap() map[string]string {
 //  in this function we should merge the reference local url config into the service url from registry.
 //TODO configuration merge, in the future , the configuration center's config should merge too.
 
+// MergeUrl ...
 func MergeUrl(serviceUrl *URL, referenceUrl *URL) *URL {
 	mergedUrl := serviceUrl.Clone()
 
@@ -523,7 +583,7 @@ func MergeUrl(serviceUrl *URL, referenceUrl *URL) *URL {
 		return true
 	})
 	//loadBalance,cluster,retries strategy config
-	methodConfigMergeFcn := mergeNormalParam(mergedUrl, referenceUrl, []string{constant.LOADBALANCE_KEY, constant.CLUSTER_KEY, constant.RETRIES_KEY})
+	methodConfigMergeFcn := mergeNormalParam(mergedUrl, referenceUrl, []string{constant.LOADBALANCE_KEY, constant.CLUSTER_KEY, constant.RETRIES_KEY, constant.TIMEOUT_KEY})
 
 	//remote timestamp
 	if v := serviceUrl.GetParam(constant.TIMESTAMP_KEY, ""); len(v) > 0 {
@@ -540,6 +600,8 @@ func MergeUrl(serviceUrl *URL, referenceUrl *URL) *URL {
 
 	return mergedUrl
 }
+
+// Clone ...
 func (c *URL) Clone() *URL {
 	newUrl := &URL{}
 	copier.Copy(newUrl, c)
diff --git a/common/url_test.go b/common/url_test.go
index 4d60d7f13f5d139e964b0837380f1054871c5d15..835973065b6d7426e5487fe76602ca27701130a1 100644
--- a/common/url_test.go
+++ b/common/url_test.go
@@ -18,7 +18,6 @@
 package common
 
 import (
-	"context"
 	"encoding/base64"
 	"net/url"
 	"testing"
@@ -56,10 +55,10 @@ func TestNewURLWithOptions(t *testing.T) {
 }
 
 func TestURL(t *testing.T) {
-	u, err := NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
+	u, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
 		"side=provider&timeout=3000&timestamp=1556509797245")
 	assert.NoError(t, err)
 
@@ -83,7 +82,7 @@ func TestURL(t *testing.T) {
 }
 
 func TestURLWithoutSchema(t *testing.T) {
-	u, err := NewURL(context.TODO(), "127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
+	u, err := NewURL("127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
 		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
 		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
 		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
@@ -110,13 +109,13 @@ func TestURLWithoutSchema(t *testing.T) {
 }
 
 func TestURL_URLEqual(t *testing.T) {
-	u1, err := NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
+	u1, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
 	assert.NoError(t, err)
-	u2, err := NewURL(context.TODO(), "dubbo://127.0.0.2:20001/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
+	u2, err := NewURL("dubbo://127.0.0.2:20001/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
 	assert.NoError(t, err)
 	assert.True(t, u1.URLEqual(u2))
 
-	u3, err := NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0")
+	u3, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0")
 	assert.NoError(t, err)
 	assert.False(t, u1.URLEqual(u3))
 }
@@ -166,7 +165,7 @@ func TestURL_GetParamAndDecoded(t *testing.T) {
 	assert.Equal(t, rule, v)
 }
 func TestURL_GetRawParam(t *testing.T) {
-	u, _ := NewURL(context.TODO(), "condition://0.0.0.0:8080/com.foo.BarService?serialization=fastjson")
+	u, _ := NewURL("condition://0.0.0.0:8080/com.foo.BarService?serialization=fastjson")
 	u.Username = "test"
 	u.Password = "test"
 	assert.Equal(t, "condition", u.GetRawParam("protocol"))
@@ -178,7 +177,7 @@ func TestURL_GetRawParam(t *testing.T) {
 	assert.Equal(t, "fastjson", u.GetRawParam("serialization"))
 }
 func TestURL_ToMap(t *testing.T) {
-	u, _ := NewURL(context.TODO(), "condition://0.0.0.0:8080/com.foo.BarService?serialization=fastjson")
+	u, _ := NewURL("condition://0.0.0.0:8080/com.foo.BarService?serialization=fastjson")
 	u.Username = "test"
 	u.Password = "test"
 
@@ -239,20 +238,20 @@ func TestMergeUrl(t *testing.T) {
 	serviceUrlParams.Set("test2", "1")
 	serviceUrlParams.Set(constant.CLUSTER_KEY, "roundrobin")
 	serviceUrlParams.Set(constant.RETRIES_KEY, "2")
-	serviceUrlParams.Set("methods.testMethod."+constant.RETRIES_KEY, "2")
-	referenceUrl, _ := NewURL(context.TODO(), "mock1://127.0.0.1:1111", WithParams(referenceUrlParams), WithMethods([]string{"testMethod"}))
-	serviceUrl, _ := NewURL(context.TODO(), "mock2://127.0.0.1:20000", WithParams(serviceUrlParams))
+	serviceUrlParams.Set(constant.METHOD_KEYS+".testMethod."+constant.RETRIES_KEY, "2")
+	referenceUrl, _ := NewURL("mock1://127.0.0.1:1111", WithParams(referenceUrlParams), WithMethods([]string{"testMethod"}))
+	serviceUrl, _ := NewURL("mock2://127.0.0.1:20000", WithParams(serviceUrlParams))
 
 	mergedUrl := MergeUrl(&serviceUrl, &referenceUrl)
 	assert.Equal(t, "random", mergedUrl.GetParam(constant.CLUSTER_KEY, ""))
 	assert.Equal(t, "1", mergedUrl.GetParam("test2", ""))
 	assert.Equal(t, "1", mergedUrl.GetParam("test3", ""))
 	assert.Equal(t, "1", mergedUrl.GetParam(constant.RETRIES_KEY, ""))
-	assert.Equal(t, "1", mergedUrl.GetParam("methods.testMethod."+constant.RETRIES_KEY, ""))
+	assert.Equal(t, "2", mergedUrl.GetParam(constant.METHOD_KEYS+".testMethod."+constant.RETRIES_KEY, ""))
 }
 
 func TestURL_SetParams(t *testing.T) {
-	u1, err := NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&configVersion=1.0")
+	u1, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&configVersion=1.0")
 	assert.NoError(t, err)
 	params := url.Values{}
 	params.Set("key", "3")
@@ -262,7 +261,7 @@ func TestURL_SetParams(t *testing.T) {
 }
 
 func TestClone(t *testing.T) {
-	u1, err := NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&configVersion=1.0")
+	u1, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&configVersion=1.0")
 	assert.NoError(t, err)
 	u2 := u1.Clone()
 	assert.Equal(t, u2.Protocol, "dubbo")
@@ -271,3 +270,17 @@ func TestClone(t *testing.T) {
 	assert.Equal(t, u1.Protocol, "dubbo")
 	assert.Equal(t, u2.Protocol, "provider")
 }
+
+func TestColonSeparatedKey(t *testing.T) {
+	u1, _ := NewURL("dubbo://127.0.0.1:20000")
+	u1.AddParam(constant.INTERFACE_KEY, "com.ikurento.user.UserProvider")
+
+	assert.Equal(t, u1.ColonSeparatedKey(), u1.GetParam(constant.INTERFACE_KEY, "")+"::")
+	u1.AddParam(constant.VERSION_KEY, "version1")
+	assert.Equal(t, u1.ColonSeparatedKey(), u1.GetParam(constant.INTERFACE_KEY, "")+":version1:")
+	u1.AddParam(constant.GROUP_KEY, "group1")
+	assert.Equal(t, u1.ColonSeparatedKey(), u1.GetParam(constant.INTERFACE_KEY, "")+":version1:group1")
+	u1.SetParam(constant.VERSION_KEY, "")
+	assert.Equal(t, u1.ColonSeparatedKey(), u1.GetParam(constant.INTERFACE_KEY, "")+"::group1")
+
+}
diff --git a/config/application_config.go b/config/application_config.go
index fcd4d38c9b55963c32d58fdd1b80375083a76d8c..23ab7d34aceaba02d7f592906d6f4e3d6cf36dae 100644
--- a/config/application_config.go
+++ b/config/application_config.go
@@ -25,6 +25,7 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
+// ApplicationConfig ...
 type ApplicationConfig struct {
 	Organization string `yaml:"organization"  json:"organization,omitempty" property:"organization"`
 	Name         string `yaml:"name" json:"name,omitempty" property:"name"`
@@ -34,15 +35,22 @@ type ApplicationConfig struct {
 	Environment  string `yaml:"environment" json:"environment,omitempty" property:"environment"`
 }
 
+// Prefix ...
 func (*ApplicationConfig) Prefix() string {
 	return constant.DUBBO + ".application."
 }
+
+// Id ...
 func (c *ApplicationConfig) Id() string {
 	return ""
 }
+
+// SetId ...
 func (c *ApplicationConfig) SetId(id string) {
 
 }
+
+// UnmarshalYAML ...
 func (c *ApplicationConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
diff --git a/config/base_config.go b/config/base_config.go
index 64418f0a6d4c09270d48e6e9e6366a02783508d3..942e966eb31e9570e957ad74aa696aa9ef29c5b0 100644
--- a/config/base_config.go
+++ b/config/base_config.go
@@ -14,10 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package config
 
 import (
-	"context"
 	"reflect"
 	"strconv"
 	"strings"
@@ -39,15 +39,21 @@ type multiConfiger interface {
 	Prefix() string
 }
 
+// BaseConfig is the common configuration for provider and consumer
 type BaseConfig struct {
 	ConfigCenterConfig *ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"`
 	configCenterUrl    *common.URL
 	prefix             string
 	fatherConfig       interface{}
+
+	MetricConfig *MetricConfig `yaml:"metrics" json:"metrics,omitempty"`
 }
 
-func (c *BaseConfig) startConfigCenter(ctx context.Context) error {
-	url, err := common.NewURL(ctx, c.ConfigCenterConfig.Address, common.WithProtocol(c.ConfigCenterConfig.Protocol), common.WithParams(c.ConfigCenterConfig.GetUrlMap()))
+// startConfigCenter will start the config center.
+// it will prepare the environment
+func (c *BaseConfig) startConfigCenter() error {
+	url, err := common.NewURL(c.ConfigCenterConfig.Address,
+		common.WithProtocol(c.ConfigCenterConfig.Protocol), common.WithParams(c.ConfigCenterConfig.GetUrlMap()))
 	if err != nil {
 		return err
 	}
@@ -89,6 +95,9 @@ func (c *BaseConfig) prepareEnvironment() error {
 			configFile = c.ConfigCenterConfig.ConfigFile
 		}
 		appContent, err = dynamicConfig.GetProperties(configFile, config_center.WithGroup(appGroup))
+		if err != nil {
+			return perrors.WithStack(err)
+		}
 	}
 	//global config file
 	mapContent, err := dynamicConfig.Parser().Parse(content)
@@ -294,8 +303,8 @@ func setFieldValue(val reflect.Value, id reflect.Value, config *config.InmemoryC
 func (c *BaseConfig) fresh() {
 	configList := config.GetEnvInstance().Configuration()
 	for element := configList.Front(); element != nil; element = element.Next() {
-		config := element.Value.(*config.InmemoryConfiguration)
-		c.freshInternalConfig(config)
+		cfg := element.Value.(*config.InmemoryConfiguration)
+		c.freshInternalConfig(cfg)
 	}
 }
 
@@ -308,6 +317,7 @@ func (c *BaseConfig) freshInternalConfig(config *config.InmemoryConfiguration) {
 	setFieldValue(val, reflect.Value{}, config)
 }
 
+// SetFatherConfig ...
 func (c *BaseConfig) SetFatherConfig(fatherConfig interface{}) {
 	c.fatherConfig = fatherConfig
 }
diff --git a/config/base_config_test.go b/config/base_config_test.go
index ab2769578072387e4686593f3c2c10fb8e49731d..d16b2420922ece60ef2135729cd47d5aa73a3760 100644
--- a/config/base_config_test.go
+++ b/config/base_config_test.go
@@ -17,7 +17,6 @@
 package config
 
 import (
-	"context"
 	"fmt"
 	"reflect"
 	"testing"
@@ -492,7 +491,7 @@ func Test_startConfigCenter(t *testing.T) {
 		Group:      "dubbo",
 		ConfigFile: "mockDubbo.properties",
 	}}
-	err := c.startConfigCenter(context.Background())
+	err := c.startConfigCenter()
 	assert.NoError(t, err)
 	b, v := config.GetEnvInstance().Configuration().Back().Value.(*config.InmemoryConfiguration).GetProperty("dubbo.application.organization")
 	assert.True(t, b)
diff --git a/config/config_center_config.go b/config/config_center_config.go
index 013d23946a042906021d3b1d37b38f326f67f50a..40b9b6517186a8a4f7956db3d23f0a1cdfbdc8cb 100644
--- a/config/config_center_config.go
+++ b/config/config_center_config.go
@@ -31,6 +31,7 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
+// ConfigCenterConfig ...
 type ConfigCenterConfig struct {
 	context       context.Context
 	Protocol      string `required:"true"  yaml:"protocol"  json:"protocol,omitempty"`
@@ -40,13 +41,14 @@ type ConfigCenterConfig struct {
 	Username      string `yaml:"username" json:"username,omitempty"`
 	Password      string `yaml:"password" json:"password,omitempty"`
 	ConfigFile    string `default:"dubbo.properties" yaml:"config_file"  json:"config_file,omitempty"`
-	Namespace     string `default:"dubbo.properties" yaml:"namespace"  json:"namespace,omitempty"`
+	Namespace     string `default:"dubbo" yaml:"namespace"  json:"namespace,omitempty"`
 	AppConfigFile string `default:"dubbo.properties" yaml:"app_config_file"  json:"app_config_file,omitempty"`
 	AppId         string `default:"dubbo" yaml:"app_id"  json:"app_id,omitempty"`
 	TimeoutStr    string `yaml:"timeout"  json:"timeout,omitempty"`
 	timeout       time.Duration
 }
 
+// UnmarshalYAML ...
 func (c *ConfigCenterConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
@@ -58,6 +60,7 @@ func (c *ConfigCenterConfig) UnmarshalYAML(unmarshal func(interface{}) error) er
 	return nil
 }
 
+// GetUrlMap ...
 func (c *ConfigCenterConfig) GetUrlMap() url.Values {
 	urlMap := url.Values{}
 	urlMap.Set(constant.CONFIG_NAMESPACE_KEY, c.Namespace)
diff --git a/config/config_loader.go b/config/config_loader.go
index 414bb479025c5d6111a6373fa2626f21ffa73ef0..875d1f6ddb84434d32296076cd31be96c1385b8a 100644
--- a/config/config_loader.go
+++ b/config/config_loader.go
@@ -31,9 +31,11 @@ import (
 )
 
 var (
-	consumerConfig *ConsumerConfig
-	providerConfig *ProviderConfig
-	maxWait        = 3
+	consumerConfig    *ConsumerConfig
+	providerConfig    *ProviderConfig
+	metricConfig      *MetricConfig
+	applicationConfig *ApplicationConfig
+	maxWait           = 3
 )
 
 // loaded consumer & provider config from xxx.yml, and log config from xxx.xml
@@ -69,12 +71,16 @@ func checkApplicationName(config *ApplicationConfig) {
 	}
 }
 
-// Dubbo Init
+// Load Dubbo Init
 func Load() {
 	// reference config
 	if consumerConfig == nil {
 		logger.Warnf("consumerConfig is nil!")
 	} else {
+
+		metricConfig = consumerConfig.MetricConfig
+		applicationConfig = consumerConfig.ApplicationConfig
+
 		checkApplicationName(consumerConfig.ApplicationConfig)
 		if err := configCenterRefreshConsumer(); err != nil {
 			logger.Errorf("[consumer config center refresh] %#v", err)
@@ -91,7 +97,7 @@ func Load() {
 				continue
 			}
 			ref.id = key
-			ref.Refer()
+			ref.Refer(rpcService)
 			ref.Implement(rpcService)
 		}
 		//wait for invoker is available, if wait over default 3s, then panic
@@ -131,6 +137,11 @@ func Load() {
 	if providerConfig == nil {
 		logger.Warnf("providerConfig is nil!")
 	} else {
+
+		// so, you should know that the consumer's config will be override
+		metricConfig = providerConfig.MetricConfig
+		applicationConfig = providerConfig.ApplicationConfig
+
 		checkApplicationName(providerConfig.ApplicationConfig)
 		if err := configCenterRefreshProvider(); err != nil {
 			logger.Errorf("[provider config center refresh] %#v", err)
@@ -153,12 +164,51 @@ func Load() {
 	GracefulShutdownInit()
 }
 
-// get rpc service for consumer
+// GetRPCService get rpc service for consumer
 func GetRPCService(name string) common.RPCService {
 	return consumerConfig.References[name].GetRPCService()
 }
 
-// create rpc service for consumer
+// RPCService create rpc service for consumer
 func RPCService(service common.RPCService) {
 	consumerConfig.References[service.Reference()].Implement(service)
 }
+
+// GetMetricConfig find the MetricConfig
+// if it is nil, create a new one
+func GetMetricConfig() *MetricConfig {
+	if metricConfig == nil {
+		metricConfig = &MetricConfig{}
+	}
+	return metricConfig
+}
+
+// GetApplicationConfig find the application config
+// if not, we will create one
+// Usually applicationConfig will be initialized when system start
+func GetApplicationConfig() *ApplicationConfig {
+	if applicationConfig == nil {
+		applicationConfig = &ApplicationConfig{}
+	}
+	return applicationConfig
+}
+
+// GetProviderConfig find the provider config
+// if not found, create new one
+func GetProviderConfig() ProviderConfig {
+	if providerConfig == nil {
+		logger.Warnf("providerConfig is nil!")
+		return ProviderConfig{}
+	}
+	return *providerConfig
+}
+
+// GetConsumerConfig find the consumer config
+// if not found, create new one
+func GetConsumerConfig() ConsumerConfig {
+	if consumerConfig == nil {
+		logger.Warnf("consumerConfig is nil!")
+		return ConsumerConfig{}
+	}
+	return *consumerConfig
+}
diff --git a/config/consumer_config.go b/config/consumer_config.go
index 72f60b5f77b9b9cc633d8939713c0eb93563deac..98917ebca2ff3abcce6c952a9bc78d93cd74f5d8 100644
--- a/config/consumer_config.go
+++ b/config/consumer_config.go
@@ -14,10 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package config
 
 import (
-	"context"
 	"io/ioutil"
 	"path"
 	"time"
@@ -25,6 +25,7 @@ import (
 
 import (
 	"github.com/creasty/defaults"
+	"github.com/dubbogo/getty"
 	perrors "github.com/pkg/errors"
 	"gopkg.in/yaml.v2"
 )
@@ -38,6 +39,7 @@ import (
 // consumerConfig
 /////////////////////////
 
+// ConsumerConfig ...
 type ConsumerConfig struct {
 	BaseConfig `yaml:",inline"`
 	Filter     string `yaml:"filter" json:"filter,omitempty" property:"filter"`
@@ -60,6 +62,7 @@ type ConsumerConfig struct {
 	ShutdownConfig *ShutdownConfig             `yaml:"shutdown_conf" json:"shutdown_conf,omitempty" property:"shutdown_conf" `
 }
 
+// UnmarshalYAML ...
 func (c *ConsumerConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
@@ -71,22 +74,17 @@ func (c *ConsumerConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
 	return nil
 }
 
+// Prefix ...
 func (*ConsumerConfig) Prefix() string {
 	return constant.ConsumerConfigPrefix
 }
 
+// SetConsumerConfig ...
 func SetConsumerConfig(c ConsumerConfig) {
 	consumerConfig = &c
 }
 
-func GetConsumerConfig() ConsumerConfig {
-	if consumerConfig == nil {
-		logger.Warnf("consumerConfig is nil!")
-		return ConsumerConfig{}
-	}
-	return *consumerConfig
-}
-
+// ConsumerInit ...
 func ConsumerInit(confConFile string) error {
 	if confConFile == "" {
 		return perrors.Errorf("application configure(consumer) file name is nil")
@@ -118,6 +116,10 @@ func ConsumerInit(confConFile string) error {
 		if consumerConfig.RequestTimeout, err = time.ParseDuration(consumerConfig.Request_Timeout); err != nil {
 			return perrors.WithMessagef(err, "time.ParseDuration(Request_Timeout{%#v})", consumerConfig.Request_Timeout)
 		}
+		if consumerConfig.RequestTimeout >= time.Duration(getty.MaxWheelTimeSpan) {
+			return perrors.WithMessagef(err, "request_timeout %s should be less than %s",
+				consumerConfig.Request_Timeout, time.Duration(getty.MaxWheelTimeSpan))
+		}
 	}
 	if consumerConfig.Connect_Timeout != "" {
 		if consumerConfig.ConnectTimeout, err = time.ParseDuration(consumerConfig.Connect_Timeout); err != nil {
@@ -133,7 +135,7 @@ func configCenterRefreshConsumer() error {
 	var err error
 	if consumerConfig.ConfigCenterConfig != nil {
 		consumerConfig.SetFatherConfig(consumerConfig)
-		if err := consumerConfig.startConfigCenter(context.Background()); err != nil {
+		if err := consumerConfig.startConfigCenter(); err != nil {
 			return perrors.Errorf("start config center error , error message is {%v}", perrors.WithStack(err))
 		}
 		consumerConfig.fresh()
diff --git a/config/generic_service.go b/config/generic_service.go
index 8a4e88df9788554bc4a5ee33884166e4ccede37f..9895486e977a9848e576597f31b724d51d144d4e 100644
--- a/config/generic_service.go
+++ b/config/generic_service.go
@@ -14,17 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package config
 
+// GenericService ...
 type GenericService struct {
 	Invoke       func(req []interface{}) (interface{}, error) `dubbo:"$invoke"`
 	referenceStr string
 }
 
+// NewGenericService ...
 func NewGenericService(referenceStr string) *GenericService {
 	return &GenericService{referenceStr: referenceStr}
 }
 
+// Reference ...
 func (u *GenericService) Reference() string {
 	return u.referenceStr
 }
diff --git a/config/graceful_shutdown.go b/config/graceful_shutdown.go
index fedb2c15ecdab62d17f0a4e83c45522f1c18acb0..382f05c8d57c4363108873433fd03565d03b9a50 100644
--- a/config/graceful_shutdown.go
+++ b/config/graceful_shutdown.go
@@ -25,7 +25,7 @@ import (
 )
 
 import (
-	"github.com/dubbogo/gost/container/gxset"
+	gxset "github.com/dubbogo/gost/container/set"
 )
 
 import (
@@ -52,6 +52,7 @@ import (
  * We define them by using 'package build' feature https://golang.org/pkg/go/build/
  */
 
+// GracefulShutdownInit ...
 func GracefulShutdownInit() {
 
 	signals := make(chan os.Signal, 1)
@@ -82,6 +83,7 @@ func GracefulShutdownInit() {
 	}()
 }
 
+// BeforeShutdown ...
 func BeforeShutdown() {
 
 	destroyAllRegistries()
diff --git a/config/graceful_shutdown_config.go b/config/graceful_shutdown_config.go
index df55728565f6cf14ce4357f8c9c7927c30d80e40..6bbabebf2538effcbbe4bddc50857acf5f962a61 100644
--- a/config/graceful_shutdown_config.go
+++ b/config/graceful_shutdown_config.go
@@ -31,6 +31,7 @@ const (
 	defaultStepTimeout = 10 * time.Second
 )
 
+// ShutdownConfig ...
 type ShutdownConfig struct {
 	/*
 	 * Total timeout. Even though we don't release all resources,
@@ -57,10 +58,12 @@ type ShutdownConfig struct {
 	RequestsFinished bool
 }
 
+// Prefix ...
 func (config *ShutdownConfig) Prefix() string {
 	return constant.ShutdownConfigPrefix
 }
 
+// GetTimeout ...
 func (config *ShutdownConfig) GetTimeout() time.Duration {
 	result, err := time.ParseDuration(config.Timeout)
 	if err != nil {
@@ -71,6 +74,7 @@ func (config *ShutdownConfig) GetTimeout() time.Duration {
 	return result
 }
 
+// GetStepTimeout ...
 func (config *ShutdownConfig) GetStepTimeout() time.Duration {
 	result, err := time.ParseDuration(config.StepTimeout)
 	if err != nil {
diff --git a/config/graceful_shutdown_signal_darwin.go b/config/graceful_shutdown_signal_darwin.go
index 59c1a5d149c2e9db8e9ac981adec107cafc863ad..8ad79ffa62ceed4096c60bfb9139b7ff1586808e 100644
--- a/config/graceful_shutdown_signal_darwin.go
+++ b/config/graceful_shutdown_signal_darwin.go
@@ -22,9 +22,13 @@ import (
 	"syscall"
 )
 
-var ShutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL, syscall.SIGSTOP,
-	syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
-	syscall.SIGABRT, syscall.SIGSYS}
+var (
+	// ShutdownSignals ...
+	ShutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL, syscall.SIGSTOP,
+		syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
+		syscall.SIGABRT, syscall.SIGSYS}
 
-var DumpHeapShutdownSignals = []os.Signal{syscall.SIGQUIT, syscall.SIGILL,
-	syscall.SIGTRAP, syscall.SIGABRT, syscall.SIGSYS}
+	// DumpHeapShutdownSignals ...
+	DumpHeapShutdownSignals = []os.Signal{syscall.SIGQUIT, syscall.SIGILL,
+		syscall.SIGTRAP, syscall.SIGABRT, syscall.SIGSYS}
+)
diff --git a/config/graceful_shutdown_signal_linux.go b/config/graceful_shutdown_signal_linux.go
index 59c1a5d149c2e9db8e9ac981adec107cafc863ad..8ad79ffa62ceed4096c60bfb9139b7ff1586808e 100644
--- a/config/graceful_shutdown_signal_linux.go
+++ b/config/graceful_shutdown_signal_linux.go
@@ -22,9 +22,13 @@ import (
 	"syscall"
 )
 
-var ShutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL, syscall.SIGSTOP,
-	syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
-	syscall.SIGABRT, syscall.SIGSYS}
+var (
+	// ShutdownSignals ...
+	ShutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL, syscall.SIGSTOP,
+		syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
+		syscall.SIGABRT, syscall.SIGSYS}
 
-var DumpHeapShutdownSignals = []os.Signal{syscall.SIGQUIT, syscall.SIGILL,
-	syscall.SIGTRAP, syscall.SIGABRT, syscall.SIGSYS}
+	// DumpHeapShutdownSignals ...
+	DumpHeapShutdownSignals = []os.Signal{syscall.SIGQUIT, syscall.SIGILL,
+		syscall.SIGTRAP, syscall.SIGABRT, syscall.SIGSYS}
+)
diff --git a/config/graceful_shutdown_signal_windows.go b/config/graceful_shutdown_signal_windows.go
index 91b2bce7c2311ecbe9a1255be3e7b7b357a9b403..815a05ecb20a8fc202debaf6f39d699845cd689e 100644
--- a/config/graceful_shutdown_signal_windows.go
+++ b/config/graceful_shutdown_signal_windows.go
@@ -22,8 +22,12 @@ import (
 	"syscall"
 )
 
-var ShutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL,
-	syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
-	syscall.SIGABRT}
+var (
+	// ShutdownSignals ...
+	ShutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL,
+		syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
+		syscall.SIGABRT}
 
-var DumpHeapShutdownSignals = []os.Signal{syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP, syscall.SIGABRT}
+	// DumpHeapShutdownSignals ...
+	DumpHeapShutdownSignals = []os.Signal{syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP, syscall.SIGABRT}
+)
diff --git a/config/method_config.go b/config/method_config.go
index 876abeeae0c7d37070c5938107d1bb1dd5dbbaa9..8f196d9e2c03071a663db03cb185fb9106d6484a 100644
--- a/config/method_config.go
+++ b/config/method_config.go
@@ -14,6 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package config
 
 import (
@@ -24,6 +25,7 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
+// MethodConfig ...
 type MethodConfig struct {
 	InterfaceId                 string
 	InterfaceName               string
@@ -37,16 +39,19 @@ type MethodConfig struct {
 	ExecuteLimit                string `yaml:"execute.limit" json:"execute.limit,omitempty" property:"execute.limit"`
 	ExecuteLimitRejectedHandler string `yaml:"execute.limit.rejected.handler" json:"execute.limit.rejected.handler,omitempty" property:"execute.limit.rejected.handler"`
 	Sticky                      bool   `yaml:"sticky"   json:"sticky,omitempty" property:"sticky"`
+	RequestTimeout              string `yaml:"timeout"  json:"timeout,omitempty" property:"timeout"`
 }
 
+// Prefix ...
 func (c *MethodConfig) Prefix() string {
-	if c.InterfaceId != "" {
+	if len(c.InterfaceId) != 0 {
 		return constant.DUBBO + "." + c.InterfaceName + "." + c.InterfaceId + "." + c.Name + "."
-	} else {
-		return constant.DUBBO + "." + c.InterfaceName + "." + c.Name + "."
 	}
+
+	return constant.DUBBO + "." + c.InterfaceName + "." + c.Name + "."
 }
 
+// UnmarshalYAML ...
 func (c *MethodConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
diff --git a/config/metric_config.go b/config/metric_config.go
new file mode 100644
index 0000000000000000000000000000000000000000..73a3ca1cfe4f1461db2e225947dd13199b2ad55e
--- /dev/null
+++ b/config/metric_config.go
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package config
+
+var (
+	defaultHistogramBucket = []float64{10, 50, 100, 200, 500, 1000, 10000}
+)
+
+// This is the config struct for all metrics implementation
+type MetricConfig struct {
+	Reporters       []string  `yaml:"reporters" json:"reporters,omitempty"`
+	HistogramBucket []float64 `yaml:"histogram_bucket" json:"histogram_bucket,omitempty"`
+}
+
+// find the histogram bucket
+// if it's empty, the default value will be return
+func (mc *MetricConfig) GetHistogramBucket() []float64 {
+	if len(mc.HistogramBucket) == 0 {
+		mc.HistogramBucket = defaultHistogramBucket
+	}
+	return mc.HistogramBucket
+}
diff --git a/config/metric_config_test.go b/config/metric_config_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..fe9d2493f37c0bd563931f5acf133105d72d0e53
--- /dev/null
+++ b/config/metric_config_test.go
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package config
+
+import (
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+func TestGetMetricConfig(t *testing.T) {
+	empty := GetMetricConfig()
+	assert.NotNil(t, empty)
+}
diff --git a/config/mock_rpcservice.go b/config/mock_rpcservice.go
index 64d431ffb6dfbc7e25a988c6093cf0ab5cbd2db5..6c43699128247bf0ec483eb83f879bf4c3b67a37 100644
--- a/config/mock_rpcservice.go
+++ b/config/mock_rpcservice.go
@@ -21,16 +21,20 @@ import (
 	"context"
 )
 
+// MockService ...
 type MockService struct{}
 
+// Reference ...
 func (*MockService) Reference() string {
 	return "MockService"
 }
 
+// GetUser ...
 func (*MockService) GetUser(ctx context.Context, itf []interface{}, str *struct{}) error {
 	return nil
 }
 
+// GetUser1 ...
 func (*MockService) GetUser1(ctx context.Context, itf []interface{}, str *struct{}) error {
 	return nil
 }
diff --git a/config/protocol_config.go b/config/protocol_config.go
index 2803456dbcd44211fb6deef883beb7f5dbbf54ad..4828d6e5bd28de19d896340f39c5633d0acd4874 100644
--- a/config/protocol_config.go
+++ b/config/protocol_config.go
@@ -14,6 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package config
 
 import (
@@ -24,12 +25,14 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
+// ProtocolConfig ...
 type ProtocolConfig struct {
 	Name string `required:"true" yaml:"name"  json:"name,omitempty" property:"name"`
 	Ip   string `required:"true" yaml:"ip"  json:"ip,omitempty" property:"ip"`
 	Port string `required:"true" yaml:"port"  json:"port,omitempty" property:"port"`
 }
 
+// Prefix ...
 func (c *ProtocolConfig) Prefix() string {
 	return constant.ProtocolConfigPrefix
 }
diff --git a/config/provider_config.go b/config/provider_config.go
index 0fed44c81b124cd40825695981a5394c273203fa..2967ecad3a49218aecf87be7d8e2f76281bfb1b4 100644
--- a/config/provider_config.go
+++ b/config/provider_config.go
@@ -14,10 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package config
 
 import (
-	"context"
 	"io/ioutil"
 	"path"
 )
@@ -37,6 +37,7 @@ import (
 // providerConfig
 /////////////////////////
 
+// ProviderConfig ...
 type ProviderConfig struct {
 	BaseConfig   `yaml:",inline"`
 	Filter       string `yaml:"filter" json:"filter,omitempty" property:"filter"`
@@ -52,6 +53,7 @@ type ProviderConfig struct {
 	ShutdownConfig    *ShutdownConfig            `yaml:"shutdown_conf" json:"shutdown_conf,omitempty" property:"shutdown_conf" `
 }
 
+// UnmarshalYAML ...
 func (c *ProviderConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
@@ -63,21 +65,17 @@ func (c *ProviderConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
 	return nil
 }
 
+// Prefix ...
 func (*ProviderConfig) Prefix() string {
 	return constant.ProviderConfigPrefix
 }
 
+// SetProviderConfig ...
 func SetProviderConfig(p ProviderConfig) {
 	providerConfig = &p
 }
-func GetProviderConfig() ProviderConfig {
-	if providerConfig == nil {
-		logger.Warnf("providerConfig is nil!")
-		return ProviderConfig{}
-	}
-	return *providerConfig
-}
 
+// ProviderInit ...
 func ProviderInit(confProFile string) error {
 	if len(confProFile) == 0 {
 		return perrors.Errorf("application configure(provider) file name is nil")
@@ -115,7 +113,7 @@ func configCenterRefreshProvider() error {
 	//fresh it
 	if providerConfig.ConfigCenterConfig != nil {
 		providerConfig.fatherConfig = providerConfig
-		if err := providerConfig.startConfigCenter(context.Background()); err != nil {
+		if err := providerConfig.startConfigCenter(); err != nil {
 			return perrors.Errorf("start config center error , error message is {%v}", perrors.WithStack(err))
 		}
 		providerConfig.fresh()
diff --git a/config/reference_config.go b/config/reference_config.go
index 4e0c56c0bc25e3b71b8edf015580cbe5ac5f0d9c..edfa17a27e88a605b71bc7f6dec1b133bd29abe9 100644
--- a/config/reference_config.go
+++ b/config/reference_config.go
@@ -39,40 +39,44 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// ReferenceConfig ...
 type ReferenceConfig struct {
-	context       context.Context
-	pxy           *proxy.Proxy
-	id            string
-	InterfaceName string            `required:"true"  yaml:"interface"  json:"interface,omitempty" property:"interface"`
-	Check         *bool             `yaml:"check"  json:"check,omitempty" property:"check"`
-	Url           string            `yaml:"url"  json:"url,omitempty" property:"url"`
-	Filter        string            `yaml:"filter" json:"filter,omitempty" property:"filter"`
-	Protocol      string            `default:"dubbo"  yaml:"protocol"  json:"protocol,omitempty" property:"protocol"`
-	Registry      string            `yaml:"registry"  json:"registry,omitempty"  property:"registry"`
-	Cluster       string            `yaml:"cluster"  json:"cluster,omitempty" property:"cluster"`
-	Loadbalance   string            `yaml:"loadbalance"  json:"loadbalance,omitempty" property:"loadbalance"`
-	Retries       string            `yaml:"retries"  json:"retries,omitempty" property:"retries"`
-	Group         string            `yaml:"group"  json:"group,omitempty" property:"group"`
-	Version       string            `yaml:"version"  json:"version,omitempty" property:"version"`
-	Methods       []*MethodConfig   `yaml:"methods"  json:"methods,omitempty" property:"methods"`
-	Async         bool              `yaml:"async"  json:"async,omitempty" property:"async"`
-	Params        map[string]string `yaml:"params"  json:"params,omitempty" property:"params"`
-	invoker       protocol.Invoker
-	urls          []*common.URL
-	Generic       bool `yaml:"generic"  json:"generic,omitempty" property:"generic"`
-	Sticky        bool `yaml:"sticky"   json:"sticky,omitempty" property:"sticky"`
+	context        context.Context
+	pxy            *proxy.Proxy
+	id             string
+	InterfaceName  string            `required:"true"  yaml:"interface"  json:"interface,omitempty" property:"interface"`
+	Check          *bool             `yaml:"check"  json:"check,omitempty" property:"check"`
+	Url            string            `yaml:"url"  json:"url,omitempty" property:"url"`
+	Filter         string            `yaml:"filter" json:"filter,omitempty" property:"filter"`
+	Protocol       string            `default:"dubbo"  yaml:"protocol"  json:"protocol,omitempty" property:"protocol"`
+	Registry       string            `yaml:"registry"  json:"registry,omitempty"  property:"registry"`
+	Cluster        string            `yaml:"cluster"  json:"cluster,omitempty" property:"cluster"`
+	Loadbalance    string            `yaml:"loadbalance"  json:"loadbalance,omitempty" property:"loadbalance"`
+	Retries        string            `yaml:"retries"  json:"retries,omitempty" property:"retries"`
+	Group          string            `yaml:"group"  json:"group,omitempty" property:"group"`
+	Version        string            `yaml:"version"  json:"version,omitempty" property:"version"`
+	Methods        []*MethodConfig   `yaml:"methods"  json:"methods,omitempty" property:"methods"`
+	Async          bool              `yaml:"async"  json:"async,omitempty" property:"async"`
+	Params         map[string]string `yaml:"params"  json:"params,omitempty" property:"params"`
+	invoker        protocol.Invoker
+	urls           []*common.URL
+	Generic        bool   `yaml:"generic"  json:"generic,omitempty" property:"generic"`
+	Sticky         bool   `yaml:"sticky"   json:"sticky,omitempty" property:"sticky"`
+	RequestTimeout string `yaml:"timeout"  json:"timeout,omitempty" property:"timeout"`
 }
 
+// Prefix ...
 func (c *ReferenceConfig) Prefix() string {
 	return constant.ReferenceConfigPrefix + c.InterfaceName + "."
 }
 
-// The only way to get a new ReferenceConfig
+// NewReferenceConfig The only way to get a new ReferenceConfig
 func NewReferenceConfig(id string, ctx context.Context) *ReferenceConfig {
 	return &ReferenceConfig{id: id, context: ctx}
 }
 
-func (refconfig *ReferenceConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
+// UnmarshalYAML ...
+func (c *ReferenceConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 
 	type rf ReferenceConfig
 	raw := rf{} // Put your defaults here
@@ -80,53 +84,59 @@ func (refconfig *ReferenceConfig) UnmarshalYAML(unmarshal func(interface{}) erro
 		return err
 	}
 
-	*refconfig = ReferenceConfig(raw)
-	if err := defaults.Set(refconfig); err != nil {
+	*c = ReferenceConfig(raw)
+	if err := defaults.Set(c); err != nil {
 		return err
 	}
 
 	return nil
 }
 
-func (refconfig *ReferenceConfig) Refer() {
-	url := common.NewURLWithOptions(common.WithPath(refconfig.id), common.WithProtocol(refconfig.Protocol), common.WithParams(refconfig.getUrlMap()))
+// Refer ...
+func (c *ReferenceConfig) Refer(_ interface{}) {
+	cfgURL := common.NewURLWithOptions(
+		common.WithPath(c.id),
+		common.WithProtocol(c.Protocol),
+		common.WithParams(c.getUrlMap()),
+		common.WithParamsValue(constant.BEAN_NAME_KEY, c.id),
+	)
 
 	//1. user specified URL, could be peer-to-peer address, or register center's address.
-	if refconfig.Url != "" {
-		urlStrings := gxstrings.RegSplit(refconfig.Url, "\\s*[;]+\\s*")
+	if c.Url != "" {
+		urlStrings := gxstrings.RegSplit(c.Url, "\\s*[;]+\\s*")
 		for _, urlStr := range urlStrings {
-			serviceUrl, err := common.NewURL(context.Background(), urlStr)
+			serviceUrl, err := common.NewURL(urlStr)
 			if err != nil {
 				panic(fmt.Sprintf("user specified URL %v refer error, error message is %v ", urlStr, err.Error()))
 			}
 			if serviceUrl.Protocol == constant.REGISTRY_PROTOCOL {
-				serviceUrl.SubURL = url
-				refconfig.urls = append(refconfig.urls, &serviceUrl)
+				serviceUrl.SubURL = cfgURL
+				c.urls = append(c.urls, &serviceUrl)
 			} else {
 				if serviceUrl.Path == "" {
-					serviceUrl.Path = "/" + refconfig.id
+					serviceUrl.Path = "/" + c.id
 				}
 				// merge url need to do
-				newUrl := common.MergeUrl(&serviceUrl, url)
-				refconfig.urls = append(refconfig.urls, newUrl)
+				newUrl := common.MergeUrl(&serviceUrl, cfgURL)
+				c.urls = append(c.urls, newUrl)
 			}
 
 		}
 	} else {
 		//2. assemble SubURL from register center's configuration模式
-		refconfig.urls = loadRegistries(refconfig.Registry, consumerConfig.Registries, common.CONSUMER)
+		c.urls = loadRegistries(c.Registry, consumerConfig.Registries, common.CONSUMER)
 
 		//set url to regUrls
-		for _, regUrl := range refconfig.urls {
-			regUrl.SubURL = url
+		for _, regUrl := range c.urls {
+			regUrl.SubURL = cfgURL
 		}
 	}
-	if len(refconfig.urls) == 1 {
-		refconfig.invoker = extension.GetProtocol(refconfig.urls[0].Protocol).Refer(*refconfig.urls[0])
+	if len(c.urls) == 1 {
+		c.invoker = extension.GetProtocol(c.urls[0].Protocol).Refer(*c.urls[0])
 	} else {
 		invokers := []protocol.Invoker{}
 		var regUrl *common.URL
-		for _, u := range refconfig.urls {
+		for _, u := range c.urls {
 			invokers = append(invokers, extension.GetProtocol(u.Protocol).Refer(*u))
 			if u.Protocol == constant.REGISTRY_PROTOCOL {
 				regUrl = u
@@ -134,49 +144,54 @@ func (refconfig *ReferenceConfig) Refer() {
 		}
 		if regUrl != nil {
 			cluster := extension.GetCluster("registryAware")
-			refconfig.invoker = cluster.Join(directory.NewStaticDirectory(invokers))
+			c.invoker = cluster.Join(directory.NewStaticDirectory(invokers))
 		} else {
-			cluster := extension.GetCluster(refconfig.Cluster)
-			refconfig.invoker = cluster.Join(directory.NewStaticDirectory(invokers))
+			cluster := extension.GetCluster(c.Cluster)
+			c.invoker = cluster.Join(directory.NewStaticDirectory(invokers))
 		}
 	}
 
 	//create proxy
-	if refconfig.Async {
-		callback := GetCallback(refconfig.id)
-		refconfig.pxy = extension.GetProxyFactory(consumerConfig.ProxyFactory).GetAsyncProxy(refconfig.invoker, callback, url)
+	if c.Async {
+		callback := GetCallback(c.id)
+		c.pxy = extension.GetProxyFactory(consumerConfig.ProxyFactory).GetAsyncProxy(c.invoker, callback, cfgURL)
 	} else {
-		refconfig.pxy = extension.GetProxyFactory(consumerConfig.ProxyFactory).GetProxy(refconfig.invoker, url)
+		c.pxy = extension.GetProxyFactory(consumerConfig.ProxyFactory).GetProxy(c.invoker, cfgURL)
 	}
 }
 
+// Implement
 // @v is service provider implemented RPCService
-func (refconfig *ReferenceConfig) Implement(v common.RPCService) {
-	refconfig.pxy.Implement(v)
+func (c *ReferenceConfig) Implement(v common.RPCService) {
+	c.pxy.Implement(v)
 }
 
-func (refconfig *ReferenceConfig) GetRPCService() common.RPCService {
-	return refconfig.pxy.Get()
+// GetRPCService ...
+func (c *ReferenceConfig) GetRPCService() common.RPCService {
+	return c.pxy.Get()
 }
 
-func (refconfig *ReferenceConfig) getUrlMap() url.Values {
+func (c *ReferenceConfig) getUrlMap() url.Values {
 	urlMap := url.Values{}
 	//first set user params
-	for k, v := range refconfig.Params {
+	for k, v := range c.Params {
 		urlMap.Set(k, v)
 	}
-	urlMap.Set(constant.INTERFACE_KEY, refconfig.InterfaceName)
+	urlMap.Set(constant.INTERFACE_KEY, c.InterfaceName)
 	urlMap.Set(constant.TIMESTAMP_KEY, strconv.FormatInt(time.Now().Unix(), 10))
-	urlMap.Set(constant.CLUSTER_KEY, refconfig.Cluster)
-	urlMap.Set(constant.LOADBALANCE_KEY, refconfig.Loadbalance)
-	urlMap.Set(constant.RETRIES_KEY, refconfig.Retries)
-	urlMap.Set(constant.GROUP_KEY, refconfig.Group)
-	urlMap.Set(constant.VERSION_KEY, refconfig.Version)
-	urlMap.Set(constant.GENERIC_KEY, strconv.FormatBool(refconfig.Generic))
+	urlMap.Set(constant.CLUSTER_KEY, c.Cluster)
+	urlMap.Set(constant.LOADBALANCE_KEY, c.Loadbalance)
+	urlMap.Set(constant.RETRIES_KEY, c.Retries)
+	urlMap.Set(constant.GROUP_KEY, c.Group)
+	urlMap.Set(constant.VERSION_KEY, c.Version)
+	urlMap.Set(constant.GENERIC_KEY, strconv.FormatBool(c.Generic))
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
+	if len(c.RequestTimeout) != 0 {
+		urlMap.Set(constant.TIMEOUT_KEY, c.RequestTimeout)
+	}
 	//getty invoke async or sync
-	urlMap.Set(constant.ASYNC_KEY, strconv.FormatBool(refconfig.Async))
-	urlMap.Set(constant.STICKY_KEY, strconv.FormatBool(refconfig.Sticky))
+	urlMap.Set(constant.ASYNC_KEY, strconv.FormatBool(c.Async))
+	urlMap.Set(constant.STICKY_KEY, strconv.FormatBool(c.Sticky))
 
 	//application info
 	urlMap.Set(constant.APPLICATION_KEY, consumerConfig.ApplicationConfig.Name)
@@ -189,25 +204,30 @@ func (refconfig *ReferenceConfig) getUrlMap() url.Values {
 
 	//filter
 	var defaultReferenceFilter = constant.DEFAULT_REFERENCE_FILTERS
-	if refconfig.Generic {
+	if c.Generic {
 		defaultReferenceFilter = constant.GENERIC_REFERENCE_FILTERS + "," + defaultReferenceFilter
 	}
-	urlMap.Set(constant.REFERENCE_FILTER_KEY, mergeValue(consumerConfig.Filter, refconfig.Filter, defaultReferenceFilter))
+	urlMap.Set(constant.REFERENCE_FILTER_KEY, mergeValue(consumerConfig.Filter, c.Filter, defaultReferenceFilter))
 
-	for _, v := range refconfig.Methods {
+	for _, v := range c.Methods {
 		urlMap.Set("methods."+v.Name+"."+constant.LOADBALANCE_KEY, v.Loadbalance)
 		urlMap.Set("methods."+v.Name+"."+constant.RETRIES_KEY, v.Retries)
 		urlMap.Set("methods."+v.Name+"."+constant.STICKY_KEY, strconv.FormatBool(v.Sticky))
+		if len(v.RequestTimeout) != 0 {
+			urlMap.Set("methods."+v.Name+"."+constant.TIMEOUT_KEY, v.RequestTimeout)
+		}
 	}
 
 	return urlMap
 
 }
-func (refconfig *ReferenceConfig) GenericLoad(id string) {
-	genericService := NewGenericService(refconfig.id)
+
+// GenericLoad ...
+func (c *ReferenceConfig) GenericLoad(id string) {
+	genericService := NewGenericService(c.id)
 	SetConsumerService(genericService)
-	refconfig.id = id
-	refconfig.Refer()
-	refconfig.Implement(genericService)
+	c.id = id
+	c.Refer(genericService)
+	c.Implement(genericService)
 	return
 }
diff --git a/config/reference_config_test.go b/config/reference_config_test.go
index e689c471ed12b58a40d4416efaa16abfe107e09b..7a65e55f09c997cb49b83f1f185faf9338cf0f5a 100644
--- a/config/reference_config_test.go
+++ b/config/reference_config_test.go
@@ -184,7 +184,7 @@ func Test_ReferMultireg(t *testing.T) {
 	extension.SetCluster("registryAware", cluster_impl.NewRegistryAwareCluster)
 
 	for _, reference := range consumerConfig.References {
-		reference.Refer()
+		reference.Refer(nil)
 		assert.NotNil(t, reference.invoker)
 		assert.NotNil(t, reference.pxy)
 	}
@@ -197,7 +197,7 @@ func Test_Refer(t *testing.T) {
 	extension.SetCluster("registryAware", cluster_impl.NewRegistryAwareCluster)
 
 	for _, reference := range consumerConfig.References {
-		reference.Refer()
+		reference.Refer(nil)
 		assert.Equal(t, "soa.mock", reference.Params["serviceid"])
 		assert.NotNil(t, reference.invoker)
 		assert.NotNil(t, reference.pxy)
@@ -211,7 +211,7 @@ func Test_ReferAsync(t *testing.T) {
 	extension.SetCluster("registryAware", cluster_impl.NewRegistryAwareCluster)
 
 	for _, reference := range consumerConfig.References {
-		reference.Refer()
+		reference.Refer(nil)
 		assert.Equal(t, "soa.mock", reference.Params["serviceid"])
 		assert.NotNil(t, reference.invoker)
 		assert.NotNil(t, reference.pxy)
@@ -227,7 +227,7 @@ func Test_ReferP2P(t *testing.T) {
 	m.Url = "dubbo://127.0.0.1:20000"
 
 	for _, reference := range consumerConfig.References {
-		reference.Refer()
+		reference.Refer(nil)
 		assert.NotNil(t, reference.invoker)
 		assert.NotNil(t, reference.pxy)
 	}
@@ -241,7 +241,7 @@ func Test_ReferMultiP2P(t *testing.T) {
 	m.Url = "dubbo://127.0.0.1:20000;dubbo://127.0.0.2:20000"
 
 	for _, reference := range consumerConfig.References {
-		reference.Refer()
+		reference.Refer(nil)
 		assert.NotNil(t, reference.invoker)
 		assert.NotNil(t, reference.pxy)
 	}
@@ -256,7 +256,7 @@ func Test_ReferMultiP2PWithReg(t *testing.T) {
 	m.Url = "dubbo://127.0.0.1:20000;registry://127.0.0.2:20000"
 
 	for _, reference := range consumerConfig.References {
-		reference.Refer()
+		reference.Refer(nil)
 		assert.NotNil(t, reference.invoker)
 		assert.NotNil(t, reference.pxy)
 	}
@@ -268,7 +268,7 @@ func Test_Implement(t *testing.T) {
 	extension.SetProtocol("registry", GetProtocol)
 	extension.SetCluster("registryAware", cluster_impl.NewRegistryAwareCluster)
 	for _, reference := range consumerConfig.References {
-		reference.Refer()
+		reference.Refer(nil)
 		reference.Implement(&MockService{})
 		assert.NotNil(t, reference.GetRPCService())
 
@@ -284,7 +284,7 @@ func Test_Forking(t *testing.T) {
 	m.Url = "dubbo://127.0.0.1:20000;registry://127.0.0.2:20000"
 
 	for _, reference := range consumerConfig.References {
-		reference.Refer()
+		reference.Refer(nil)
 		forks := int(reference.invoker.GetUrl().GetParamInt(constant.FORKS_KEY, constant.DEFAULT_FORKS))
 		assert.Equal(t, 5, forks)
 		assert.NotNil(t, reference.pxy)
@@ -301,7 +301,7 @@ func Test_Sticky(t *testing.T) {
 	m.Url = "dubbo://127.0.0.1:20000;registry://127.0.0.2:20000"
 
 	reference := consumerConfig.References["MockService"]
-	reference.Refer()
+	reference.Refer(nil)
 	referenceSticky := reference.invoker.GetUrl().GetParam(constant.STICKY_KEY, "false")
 	assert.Equal(t, "false", referenceSticky)
 
diff --git a/config/registry_config.go b/config/registry_config.go
index 9ffa41eb5b5b3b5ae4dc9f77812c0aef5ce9835f..4e4b6e97d79a9402616b6cac954f7a09b2973dcc 100644
--- a/config/registry_config.go
+++ b/config/registry_config.go
@@ -18,7 +18,6 @@
 package config
 
 import (
-	"context"
 	"net/url"
 	"strconv"
 	"strings"
@@ -34,6 +33,7 @@ import (
 	"github.com/apache/dubbo-go/common/logger"
 )
 
+// RegistryConfig ...
 type RegistryConfig struct {
 	Protocol string `required:"true" yaml:"protocol"  json:"protocol,omitempty" property:"protocol"`
 	//I changed "type" to "protocol" ,the same as "protocol" field in java class RegistryConfig
@@ -46,6 +46,7 @@ type RegistryConfig struct {
 	Params   map[string]string `yaml:"params" json:"params,omitempty" property:"params"`
 }
 
+// UnmarshalYAML ...
 func (c *RegistryConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
@@ -57,6 +58,7 @@ func (c *RegistryConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
 	return nil
 }
 
+// Prefix ...
 func (*RegistryConfig) Prefix() string {
 	return constant.RegistryConfigPrefix + "|" + constant.SingleRegistryConfigPrefix
 }
@@ -92,9 +94,7 @@ func loadRegistries(targetRegistries string, registries map[string]*RegistryConf
 			addresses := strings.Split(registryConf.Address, ",")
 			address := addresses[0]
 			address = traslateRegistryConf(address, registryConf)
-			url, err = common.NewURL(
-				context.Background(),
-				constant.REGISTRY_PROTOCOL+"://"+address,
+			url, err = common.NewURL(constant.REGISTRY_PROTOCOL+"://"+address,
 				common.WithParams(registryConf.getUrlMap(roleType)),
 				common.WithUsername(registryConf.Username),
 				common.WithPassword(registryConf.Password),
@@ -114,15 +114,16 @@ func loadRegistries(targetRegistries string, registries map[string]*RegistryConf
 	return urls
 }
 
-func (regconfig *RegistryConfig) getUrlMap(roleType common.RoleType) url.Values {
+func (c *RegistryConfig) getUrlMap(roleType common.RoleType) url.Values {
 	urlMap := url.Values{}
-	urlMap.Set(constant.GROUP_KEY, regconfig.Group)
+	urlMap.Set(constant.GROUP_KEY, c.Group)
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(int(roleType)))
-	urlMap.Set(constant.REGISTRY_KEY, regconfig.Protocol)
-	urlMap.Set(constant.REGISTRY_TIMEOUT_KEY, regconfig.TimeoutStr)
-	for k, v := range regconfig.Params {
+	urlMap.Set(constant.REGISTRY_KEY, c.Protocol)
+	urlMap.Set(constant.REGISTRY_TIMEOUT_KEY, c.TimeoutStr)
+	for k, v := range c.Params {
 		urlMap.Set(k, v)
 	}
+
 	return urlMap
 }
 
diff --git a/config/service.go b/config/service.go
index f1b51790ca13df0534882837397181e45e56ffa3..b7e7dc2a425b42363d570fc37a70e2e5094e7d9d 100644
--- a/config/service.go
+++ b/config/service.go
@@ -26,24 +26,27 @@ var (
 	proServices = map[string]common.RPCService{} // service name -> service
 )
 
-// SetConService is called by init() of implement of RPCService
+// SetConsumerService is called by init() of implement of RPCService
 func SetConsumerService(service common.RPCService) {
 	conServices[service.Reference()] = service
 }
 
-// SetProService is called by init() of implement of RPCService
+// SetProviderService is called by init() of implement of RPCService
 func SetProviderService(service common.RPCService) {
 	proServices[service.Reference()] = service
 }
 
+// GetConsumerService ...
 func GetConsumerService(name string) common.RPCService {
 	return conServices[name]
 }
 
+// GetProviderService ...
 func GetProviderService(name string) common.RPCService {
 	return proServices[name]
 }
 
+// GetCallback ...
 func GetCallback(name string) func(response common.CallbackResponse) {
 	service := GetConsumerService(name)
 	if sv, ok := service.(common.AsyncCallbackService); ok {
diff --git a/config/service_config.go b/config/service_config.go
index c17846322e20120bfdf00f1afe24bd20efe7510b..2111838395d507ebac4f72883c99dd2bb1615850 100644
--- a/config/service_config.go
+++ b/config/service_config.go
@@ -42,6 +42,7 @@ import (
 	"github.com/apache/dubbo-go/protocol/protocolwrapper"
 )
 
+// ServiceConfig ...
 type ServiceConfig struct {
 	context                     context.Context
 	id                          string
@@ -66,6 +67,8 @@ type ServiceConfig struct {
 	TpsLimitRejectedHandler     string            `yaml:"tps.limit.rejected.handler" json:"tps.limit.rejected.handler,omitempty" property:"tps.limit.rejected.handler"`
 	ExecuteLimit                string            `yaml:"execute.limit" json:"execute.limit,omitempty" property:"execute.limit"`
 	ExecuteLimitRejectedHandler string            `yaml:"execute.limit.rejected.handler" json:"execute.limit.rejected.handler,omitempty" property:"execute.limit.rejected.handler"`
+	Auth                        string            `yaml:"auth" json:"auth,omitempty" property:"auth"`
+	ParamSign                   string            `yaml:"param.sign" json:"param.sign,omitempty" property:"param.sign"`
 
 	unexported    *atomic.Bool
 	exported      *atomic.Bool
@@ -74,10 +77,12 @@ type ServiceConfig struct {
 	cacheMutex    sync.Mutex
 }
 
+// Prefix ...
 func (c *ServiceConfig) Prefix() string {
 	return constant.ServiceConfigPrefix + c.InterfaceName + "."
 }
 
+// UnmarshalYAML ...
 func (c *ServiceConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
@@ -89,7 +94,7 @@ func (c *ServiceConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	return nil
 }
 
-// The only way to get a new ServiceConfig
+// NewServiceConfig The only way to get a new ServiceConfig
 func NewServiceConfig(id string, context context.Context) *ServiceConfig {
 
 	return &ServiceConfig{
@@ -101,63 +106,69 @@ func NewServiceConfig(id string, context context.Context) *ServiceConfig {
 
 }
 
-func (srvconfig *ServiceConfig) Export() error {
+// Export ...
+func (c *ServiceConfig) Export() error {
 	// TODO: config center start here
 
 	// TODO:delay export
-	if srvconfig.unexported != nil && srvconfig.unexported.Load() {
-		err := perrors.Errorf("The service %v has already unexported! ", srvconfig.InterfaceName)
+	if c.unexported != nil && c.unexported.Load() {
+		err := perrors.Errorf("The service %v has already unexported! ", c.InterfaceName)
 		logger.Errorf(err.Error())
 		return err
 	}
-	if srvconfig.unexported != nil && srvconfig.exported.Load() {
-		logger.Warnf("The service %v has already exported! ", srvconfig.InterfaceName)
+	if c.unexported != nil && c.exported.Load() {
+		logger.Warnf("The service %v has already exported! ", c.InterfaceName)
 		return nil
 	}
 
-	regUrls := loadRegistries(srvconfig.Registry, providerConfig.Registries, common.PROVIDER)
-	urlMap := srvconfig.getUrlMap()
-
-	for _, proto := range loadProtocol(srvconfig.Protocol, providerConfig.Protocols) {
+	regUrls := loadRegistries(c.Registry, providerConfig.Registries, common.PROVIDER)
+	urlMap := c.getUrlMap()
+	protocolConfigs := loadProtocol(c.Protocol, providerConfig.Protocols)
+	if len(protocolConfigs) == 0 {
+		logger.Warnf("The service %v's '%v' protocols don't has right protocolConfigs ", c.InterfaceName, c.Protocol)
+		return nil
+	}
+	for _, proto := range protocolConfigs {
 		// registry the service reflect
-		methods, err := common.ServiceMap.Register(proto.Name, srvconfig.rpcService)
+		methods, err := common.ServiceMap.Register(proto.Name, c.rpcService)
 		if err != nil {
-			err := perrors.Errorf("The service %v  export the protocol %v error! Error message is %v .", srvconfig.InterfaceName, proto.Name, err.Error())
+			err := perrors.Errorf("The service %v  export the protocol %v error! Error message is %v .", c.InterfaceName, proto.Name, err.Error())
 			logger.Errorf(err.Error())
 			return err
 		}
-		url := common.NewURLWithOptions(common.WithPath(srvconfig.id),
+		ivkURL := common.NewURLWithOptions(
+			common.WithPath(c.id),
 			common.WithProtocol(proto.Name),
 			common.WithIp(proto.Ip),
 			common.WithPort(proto.Port),
 			common.WithParams(urlMap),
-			common.WithParamsValue(constant.BEAN_NAME_KEY, srvconfig.id),
+			common.WithParamsValue(constant.BEAN_NAME_KEY, c.id),
 			common.WithMethods(strings.Split(methods, ",")),
-			common.WithToken(srvconfig.Token),
+			common.WithToken(c.Token),
 		)
 
 		if len(regUrls) > 0 {
 			for _, regUrl := range regUrls {
-				regUrl.SubURL = url
+				regUrl.SubURL = ivkURL
 
-				srvconfig.cacheMutex.Lock()
-				if srvconfig.cacheProtocol == nil {
-					logger.Infof(fmt.Sprintf("First load the registry protocol , url is {%v}!", url))
-					srvconfig.cacheProtocol = extension.GetProtocol("registry")
+				c.cacheMutex.Lock()
+				if c.cacheProtocol == nil {
+					logger.Infof(fmt.Sprintf("First load the registry protocol , url is {%v}!", ivkURL))
+					c.cacheProtocol = extension.GetProtocol("registry")
 				}
-				srvconfig.cacheMutex.Unlock()
+				c.cacheMutex.Unlock()
 
 				invoker := extension.GetProxyFactory(providerConfig.ProxyFactory).GetInvoker(*regUrl)
-				exporter := srvconfig.cacheProtocol.Export(invoker)
+				exporter := c.cacheProtocol.Export(invoker)
 				if exporter == nil {
-					panic(perrors.New(fmt.Sprintf("Registry protocol new exporter error,registry is {%v},url is {%v}", regUrl, url)))
+					panic(perrors.New(fmt.Sprintf("Registry protocol new exporter error,registry is {%v},url is {%v}", regUrl, ivkURL)))
 				}
 			}
 		} else {
-			invoker := extension.GetProxyFactory(providerConfig.ProxyFactory).GetInvoker(*url)
+			invoker := extension.GetProxyFactory(providerConfig.ProxyFactory).GetInvoker(*ivkURL)
 			exporter := extension.GetProtocol(protocolwrapper.FILTER).Export(invoker)
 			if exporter == nil {
-				panic(perrors.New(fmt.Sprintf("Filter protocol without registry new exporter error,url is {%v}", url)))
+				panic(perrors.New(fmt.Sprintf("Filter protocol without registry new exporter error,url is {%v}", ivkURL)))
 			}
 		}
 
@@ -166,24 +177,25 @@ func (srvconfig *ServiceConfig) Export() error {
 
 }
 
-func (srvconfig *ServiceConfig) Implement(s common.RPCService) {
-	srvconfig.rpcService = s
+// Implement ...
+func (c *ServiceConfig) Implement(s common.RPCService) {
+	c.rpcService = s
 }
 
-func (srvconfig *ServiceConfig) getUrlMap() url.Values {
+func (c *ServiceConfig) getUrlMap() url.Values {
 	urlMap := url.Values{}
 	// first set user params
-	for k, v := range srvconfig.Params {
+	for k, v := range c.Params {
 		urlMap.Set(k, v)
 	}
-	urlMap.Set(constant.INTERFACE_KEY, srvconfig.InterfaceName)
+	urlMap.Set(constant.INTERFACE_KEY, c.InterfaceName)
 	urlMap.Set(constant.TIMESTAMP_KEY, strconv.FormatInt(time.Now().Unix(), 10))
-	urlMap.Set(constant.CLUSTER_KEY, srvconfig.Cluster)
-	urlMap.Set(constant.LOADBALANCE_KEY, srvconfig.Loadbalance)
-	urlMap.Set(constant.WARMUP_KEY, srvconfig.Warmup)
-	urlMap.Set(constant.RETRIES_KEY, srvconfig.Retries)
-	urlMap.Set(constant.GROUP_KEY, srvconfig.Group)
-	urlMap.Set(constant.VERSION_KEY, srvconfig.Version)
+	urlMap.Set(constant.CLUSTER_KEY, c.Cluster)
+	urlMap.Set(constant.LOADBALANCE_KEY, c.Loadbalance)
+	urlMap.Set(constant.WARMUP_KEY, c.Warmup)
+	urlMap.Set(constant.RETRIES_KEY, c.Retries)
+	urlMap.Set(constant.GROUP_KEY, c.Group)
+	urlMap.Set(constant.VERSION_KEY, c.Version)
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
 	// application info
 	urlMap.Set(constant.APPLICATION_KEY, providerConfig.ApplicationConfig.Name)
@@ -195,22 +207,26 @@ func (srvconfig *ServiceConfig) getUrlMap() url.Values {
 	urlMap.Set(constant.ENVIRONMENT_KEY, providerConfig.ApplicationConfig.Environment)
 
 	// filter
-	urlMap.Set(constant.SERVICE_FILTER_KEY, mergeValue(providerConfig.Filter, srvconfig.Filter, constant.DEFAULT_SERVICE_FILTERS))
+	urlMap.Set(constant.SERVICE_FILTER_KEY, mergeValue(providerConfig.Filter, c.Filter, constant.DEFAULT_SERVICE_FILTERS))
 
 	// filter special config
-	urlMap.Set(constant.ACCESS_LOG_KEY, srvconfig.AccessLog)
+	urlMap.Set(constant.ACCESS_LOG_KEY, c.AccessLog)
 	// tps limiter
-	urlMap.Set(constant.TPS_LIMIT_STRATEGY_KEY, srvconfig.TpsLimitStrategy)
-	urlMap.Set(constant.TPS_LIMIT_INTERVAL_KEY, srvconfig.TpsLimitInterval)
-	urlMap.Set(constant.TPS_LIMIT_RATE_KEY, srvconfig.TpsLimitRate)
-	urlMap.Set(constant.TPS_LIMITER_KEY, srvconfig.TpsLimiter)
-	urlMap.Set(constant.TPS_REJECTED_EXECUTION_HANDLER_KEY, srvconfig.TpsLimitRejectedHandler)
+	urlMap.Set(constant.TPS_LIMIT_STRATEGY_KEY, c.TpsLimitStrategy)
+	urlMap.Set(constant.TPS_LIMIT_INTERVAL_KEY, c.TpsLimitInterval)
+	urlMap.Set(constant.TPS_LIMIT_RATE_KEY, c.TpsLimitRate)
+	urlMap.Set(constant.TPS_LIMITER_KEY, c.TpsLimiter)
+	urlMap.Set(constant.TPS_REJECTED_EXECUTION_HANDLER_KEY, c.TpsLimitRejectedHandler)
 
 	// execute limit filter
-	urlMap.Set(constant.EXECUTE_LIMIT_KEY, srvconfig.ExecuteLimit)
-	urlMap.Set(constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY, srvconfig.ExecuteLimitRejectedHandler)
+	urlMap.Set(constant.EXECUTE_LIMIT_KEY, c.ExecuteLimit)
+	urlMap.Set(constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY, c.ExecuteLimitRejectedHandler)
+
+	// auth filter
+	urlMap.Set(constant.SERVICE_AUTH_KEY, c.Auth)
+	urlMap.Set(constant.PARAMTER_SIGNATURE_ENABLE_KEY, c.ParamSign)
 
-	for _, v := range srvconfig.Methods {
+	for _, v := range c.Methods {
 		prefix := "methods." + v.Name + "."
 		urlMap.Set(prefix+constant.LOADBALANCE_KEY, v.Loadbalance)
 		urlMap.Set(prefix+constant.RETRIES_KEY, v.Retries)
diff --git a/config/service_config_test.go b/config/service_config_test.go
index 8ae67533bd1cdd1f9170efd762de51d371d0ad38..6f3230890348e77ea26c9c0eaf9165090c8cd09f 100644
--- a/config/service_config_test.go
+++ b/config/service_config_test.go
@@ -93,6 +93,30 @@ func doInitProvider() {
 					},
 				},
 			},
+			"MockServiceNoRightProtocol": {
+				InterfaceName: "com.MockService",
+				Protocol:      "mock1",
+				Registry:      "shanghai_reg1,shanghai_reg2,hangzhou_reg1,hangzhou_reg2",
+				Cluster:       "failover",
+				Loadbalance:   "random",
+				Retries:       "3",
+				Group:         "huadong_idc",
+				Version:       "1.0.0",
+				Methods: []*MethodConfig{
+					{
+						Name:        "GetUser",
+						Retries:     "2",
+						Loadbalance: "random",
+						Weight:      200,
+					},
+					{
+						Name:        "GetUser1",
+						Retries:     "2",
+						Loadbalance: "random",
+						Weight:      200,
+					},
+				},
+			},
 		},
 		Protocols: map[string]*ProtocolConfig{
 			"mock": {
diff --git a/config/testdata/consumer_config.yml b/config/testdata/consumer_config.yml
index f44ea449fd16235050f6a7ba7823a87e24791780..2034186c0fa0ccf21c3f6fb9df0f5cfd69315113 100644
--- a/config/testdata/consumer_config.yml
+++ b/config/testdata/consumer_config.yml
@@ -41,9 +41,11 @@ references:
     interface : "com.ikurento.user.UserProvider"
     url: "dubbo://127.0.0.1:20000/UserProvider"
     cluster: "failover"
+    timeout: "3s"
     methods :
       - name: "GetUser"
         retries: "3"
+        timeout: "5s"
     params:
       "serviceid":
         "soa.com.ikurento.user.UserProvider"
@@ -54,12 +56,21 @@ shutdown_conf:
   step_timeout: 10s
 
 protocol_conf:
+  # when you choose the Dubbo protocol, the following configuration takes effect
   dubbo:
     reconnect_interval: 0
+    # reconnect_interval is the actual number of connections a session can use
     connection_number: 2
-    heartbeat_period: "5s"
-    session_timeout: "20s"
-    pool_size: 64
+    # heartbeat_period is heartbeat interval between server and client connection.
+    # Effective by client configuration
+    heartbeat_period: "30s"
+    # when the session is inactive for more than session_timeout, the session may be closed
+    session_timeout: "30s"
+    # a reference has the size of the session connection pool
+    # that is the maximum number of sessions it may have
+    pool_size: 4
+    # dubbo-go uses getty as the network connection library.
+    # The following is the relevant configuration of getty
     pool_ttl: 600
     # gr_pool_size is recommended to be set to [cpu core number] * 100
     gr_pool_size: 1200
@@ -67,6 +78,8 @@ protocol_conf:
     queue_len: 64
     # queue_number is recommended to be set to gr_pool_size / 20
     queue_number: 60
+    # dubbo-go uses getty as the network connection library.
+    # The following is the relevant configuration of getty
     getty_session_param:
       compress_encoding: false
       tcp_no_delay: true
@@ -78,5 +91,7 @@ protocol_conf:
       tcp_read_timeout: "1s"
       tcp_write_timeout: "5s"
       wait_timeout: "1s"
-      max_msg_len: 1024
+      # maximum len of data per request
+      # this refers to the total amount of data requested or returned
+      max_msg_len: 102400
       session_name: "client"
diff --git a/config_center/apollo/factory.go b/config_center/apollo/factory.go
index 47011be4a3e0e421ca7a314620a3547d665111c8..a5a69e121598bea4194398423775a99f04b61ced 100644
--- a/config_center/apollo/factory.go
+++ b/config_center/apollo/factory.go
@@ -20,7 +20,7 @@ package apollo
 import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/extension"
-	. "github.com/apache/dubbo-go/config_center"
+	"github.com/apache/dubbo-go/config_center"
 	"github.com/apache/dubbo-go/config_center/parser"
 )
 
@@ -28,13 +28,13 @@ func init() {
 	extension.SetConfigCenterFactory("apollo", createDynamicConfigurationFactory)
 }
 
-func createDynamicConfigurationFactory() DynamicConfigurationFactory {
+func createDynamicConfigurationFactory() config_center.DynamicConfigurationFactory {
 	return &apolloConfigurationFactory{}
 }
 
 type apolloConfigurationFactory struct{}
 
-func (f *apolloConfigurationFactory) GetDynamicConfiguration(url *common.URL) (DynamicConfiguration, error) {
+func (f *apolloConfigurationFactory) GetDynamicConfiguration(url *common.URL) (config_center.DynamicConfiguration, error) {
 	dynamicConfiguration, err := newApolloConfiguration(url)
 	if err != nil {
 		return nil, err
diff --git a/config_center/apollo/impl.go b/config_center/apollo/impl.go
index ed46d4f9635d4d480a21d09fce0ec4ec84d47a66..85dff14a1ec9ba3905890bf37dc1e1827d59d80f 100644
--- a/config_center/apollo/impl.go
+++ b/config_center/apollo/impl.go
@@ -32,7 +32,7 @@ import (
 import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
-	. "github.com/apache/dubbo-go/config_center"
+	cc "github.com/apache/dubbo-go/config_center"
 	"github.com/apache/dubbo-go/config_center/parser"
 	"github.com/apache/dubbo-go/remoting"
 )
@@ -58,7 +58,7 @@ func newApolloConfiguration(url *common.URL) (*apolloConfiguration, error) {
 	configCluster := url.GetParam(constant.CONFIG_CLUSTER_KEY, "")
 
 	appId := url.GetParam(constant.CONFIG_APP_ID_KEY, "")
-	namespaces := url.GetParam(constant.CONFIG_NAMESPACE_KEY, getProperties(DEFAULT_GROUP))
+	namespaces := getProperties(url.GetParam(constant.CONFIG_NAMESPACE_KEY, cc.DEFAULT_GROUP))
 	c.appConf = &agollo.AppConfig{
 		AppId:         appId,
 		Cluster:       configCluster,
@@ -84,8 +84,8 @@ func getChangeType(change agollo.ConfigChangeType) remoting.EventType {
 	}
 }
 
-func (c *apolloConfiguration) AddListener(key string, listener ConfigurationListener, opts ...Option) {
-	k := &Options{}
+func (c *apolloConfiguration) AddListener(key string, listener cc.ConfigurationListener, opts ...cc.Option) {
+	k := &cc.Options{}
 	for _, opt := range opts {
 		opt(k)
 	}
@@ -95,8 +95,8 @@ func (c *apolloConfiguration) AddListener(key string, listener ConfigurationList
 	l.(*apolloListener).AddListener(listener)
 }
 
-func (c *apolloConfiguration) RemoveListener(key string, listener ConfigurationListener, opts ...Option) {
-	k := &Options{}
+func (c *apolloConfiguration) RemoveListener(key string, listener cc.ConfigurationListener, opts ...cc.Option) {
+	k := &cc.Options{}
 	for _, opt := range opts {
 		opt(k)
 	}
@@ -116,7 +116,7 @@ func getNamespaceName(namespace string, configFileFormat agollo.ConfigFileFormat
 	return fmt.Sprintf(apolloConfigFormat, namespace, configFileFormat)
 }
 
-func (c *apolloConfiguration) GetInternalProperty(key string, opts ...Option) (string, error) {
+func (c *apolloConfiguration) GetInternalProperty(key string, opts ...cc.Option) (string, error) {
 	config := agollo.GetConfig(c.appConf.NamespaceName)
 	if config == nil {
 		return "", errors.New(fmt.Sprintf("nothing in namespace:%s ", key))
@@ -124,11 +124,11 @@ func (c *apolloConfiguration) GetInternalProperty(key string, opts ...Option) (s
 	return config.GetStringValue(key, ""), nil
 }
 
-func (c *apolloConfiguration) GetRule(key string, opts ...Option) (string, error) {
+func (c *apolloConfiguration) GetRule(key string, opts ...cc.Option) (string, error) {
 	return c.GetInternalProperty(key, opts...)
 }
 
-func (c *apolloConfiguration) GetProperties(key string, opts ...Option) (string, error) {
+func (c *apolloConfiguration) GetProperties(key string, opts ...cc.Option) (string, error) {
 	/**
 	 * when group is not null, we are getting startup configs(config file) from Config Center, for example:
 	 * key=dubbo.propertie
diff --git a/config_center/apollo/impl_test.go b/config_center/apollo/impl_test.go
index e898be91ee356180f5967f9dd5a02df0dbcfb311..a95524b41b887313993aad4e774ed6d96b24c08f 100644
--- a/config_center/apollo/impl_test.go
+++ b/config_center/apollo/impl_test.go
@@ -17,13 +17,14 @@
 package apollo
 
 import (
-	"context"
 	"fmt"
 	"net/http"
 	"net/http/httptest"
+	"os"
 	"strings"
 	"sync"
 	"testing"
+	"time"
 )
 
 import (
@@ -139,7 +140,7 @@ func serviceConfigResponse(rw http.ResponseWriter, req *http.Request) {
 	fmt.Fprintf(rw, "%s", result)
 }
 
-//run mock config server
+// run mock config server
 func runMockConfigServer(handlerMap map[string]func(http.ResponseWriter, *http.Request),
 	notifyHandler func(http.ResponseWriter, *http.Request)) *httptest.Server {
 	uriHandlerMap := make(map[string]func(http.ResponseWriter, *http.Request), 0)
@@ -171,6 +172,7 @@ func Test_GetConfig(t *testing.T) {
 	mapContent, err := configuration.Parser().Parse(configs)
 	assert.NoError(t, err)
 	assert.Equal(t, "ikurento.com", mapContent["application.organization"])
+	deleteMockJson(t)
 }
 
 func Test_GetConfigItem(t *testing.T) {
@@ -180,6 +182,7 @@ func Test_GetConfigItem(t *testing.T) {
 	configuration.SetParser(&parser.DefaultConfigurationParser{})
 	assert.NoError(t, err)
 	assert.Equal(t, "ikurento.com", configs)
+	deleteMockJson(t)
 }
 
 func initMockApollo(t *testing.T) *apolloConfiguration {
@@ -188,11 +191,11 @@ func initMockApollo(t *testing.T) *apolloConfiguration {
 		Address:   "106.12.25.204:8080",
 		AppId:     "testApplication_yang",
 		Cluster:   "dev",
-		Namespace: "mockDubbog.properties",
+		Namespace: "mockDubbog",
 	}}
 	apollo := initApollo()
 	apolloUrl := strings.ReplaceAll(apollo.URL, "http", "apollo")
-	url, err := common.NewURL(context.TODO(), apolloUrl, common.WithParams(c.ConfigCenterConfig.GetUrlMap()))
+	url, err := common.NewURL(apolloUrl, common.WithParams(c.ConfigCenterConfig.GetUrlMap()))
 	assert.NoError(t, err)
 	configuration, err := newApolloConfiguration(&url)
 	assert.NoError(t, err)
@@ -216,6 +219,7 @@ func TestAddListener(t *testing.T) {
 	listener.wg.Wait()
 	assert.Equal(t, "registries.hangzhouzk.username", listener.event)
 	assert.Greater(t, listener.count, 0)
+	deleteMockJson(t)
 }
 
 func TestRemoveListener(t *testing.T) {
@@ -244,6 +248,7 @@ func TestRemoveListener(t *testing.T) {
 	})
 	assert.Equal(t, listenerCount, 0)
 	assert.Equal(t, listener.count, 0)
+	deleteMockJson(t)
 }
 
 type apolloDataListener struct {
@@ -260,3 +265,10 @@ func (l *apolloDataListener) Process(configType *config_center.ConfigChangeEvent
 	l.count++
 	l.event = configType.Key
 }
+
+func deleteMockJson(t *testing.T) {
+	// because the file write in another goroutine,so have a break ...
+	time.Sleep(100 * time.Millisecond)
+	remove := os.Remove("mockDubbog.properties.json")
+	t.Log("remove result:", remove)
+}
diff --git a/config_center/apollo/listener.go b/config_center/apollo/listener.go
index d81e1cbf34e405f7d2974e29558414029308b36b..820d02fb48e2204c3f1eb74fd5624132a63d367e 100644
--- a/config_center/apollo/listener.go
+++ b/config_center/apollo/listener.go
@@ -29,6 +29,14 @@ type apolloListener struct {
 	listeners map[config_center.ConfigurationListener]struct{}
 }
 
+// NewApolloListener ...
+func NewApolloListener() *apolloListener {
+	return &apolloListener{
+		listeners: make(map[config_center.ConfigurationListener]struct{}, 0),
+	}
+}
+
+// OnChange ...
 func (a *apolloListener) OnChange(changeEvent *agollo.ChangeEvent) {
 	for key, change := range changeEvent.Changes {
 		for listener := range a.listeners {
@@ -41,19 +49,15 @@ func (a *apolloListener) OnChange(changeEvent *agollo.ChangeEvent) {
 	}
 }
 
-func NewApolloListener() *apolloListener {
-	return &apolloListener{
-		listeners: make(map[config_center.ConfigurationListener]struct{}, 0),
-	}
-}
-
-func (al *apolloListener) AddListener(l config_center.ConfigurationListener) {
-	if _, ok := al.listeners[l]; !ok {
-		al.listeners[l] = struct{}{}
-		agollo.AddChangeListener(al)
+// AddListener ...
+func (a *apolloListener) AddListener(l config_center.ConfigurationListener) {
+	if _, ok := a.listeners[l]; !ok {
+		a.listeners[l] = struct{}{}
+		agollo.AddChangeListener(a)
 	}
 }
 
-func (al *apolloListener) RemoveListener(l config_center.ConfigurationListener) {
-	delete(al.listeners, l)
+// RemoveListener ...
+func (a *apolloListener) RemoveListener(l config_center.ConfigurationListener) {
+	delete(a.listeners, l)
 }
diff --git a/config_center/configuration_listener.go b/config_center/configuration_listener.go
index 1419bcdd0ce10ec15d0c24c2439bb02747ce5391..e70e4f68075c51c33f1110ef44a7b703e36fb78d 100644
--- a/config_center/configuration_listener.go
+++ b/config_center/configuration_listener.go
@@ -25,10 +25,12 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
+// ConfigurationListener ...
 type ConfigurationListener interface {
 	Process(*ConfigChangeEvent)
 }
 
+// ConfigChangeEvent ...
 type ConfigChangeEvent struct {
 	Key        string
 	Value      interface{}
diff --git a/config_center/configurator.go b/config_center/configurator.go
index 3ba293ec60302b76becce357f49b2baa543f69cd..ffa9034e05c4c3d4cc254886e2ed19576f155dec 100644
--- a/config_center/configurator.go
+++ b/config_center/configurator.go
@@ -21,6 +21,7 @@ import (
 	"github.com/apache/dubbo-go/common"
 )
 
+// Configurator ...
 type Configurator interface {
 	GetUrl() *common.URL
 	Configure(url *common.URL)
diff --git a/config_center/configurator/mock.go b/config_center/configurator/mock.go
index 1f03d107c8f588cfd4c23c9086bb0fbe42e05fff..d294b9195db9cfe60056bc29ec26816f740ea396 100644
--- a/config_center/configurator/mock.go
+++ b/config_center/configurator/mock.go
@@ -14,6 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package configurator
 
 import (
@@ -22,6 +23,7 @@ import (
 	"github.com/apache/dubbo-go/config_center"
 )
 
+// NewMockConfigurator ...
 func NewMockConfigurator(url *common.URL) config_center.Configurator {
 	return &mockConfigurator{configuratorUrl: url}
 }
@@ -30,10 +32,12 @@ type mockConfigurator struct {
 	configuratorUrl *common.URL
 }
 
+// GetUrl ...
 func (c *mockConfigurator) GetUrl() *common.URL {
 	return c.configuratorUrl
 }
 
+// Configure ...
 func (c *mockConfigurator) Configure(url *common.URL) {
 	if cluster := c.GetUrl().GetParam(constant.CLUSTER_KEY, ""); cluster != "" {
 		url.SetParam(constant.CLUSTER_KEY, cluster)
diff --git a/config_center/configurator/override.go b/config_center/configurator/override.go
index e85b4d3ec9d5e6f9f7163cefce3f328f8dcc225a..d0b23ef2f20d065135547536c2cebcec3eec0ce1 100644
--- a/config_center/configurator/override.go
+++ b/config_center/configurator/override.go
@@ -14,6 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package configurator
 
 import (
@@ -21,7 +22,7 @@ import (
 )
 
 import (
-	"github.com/dubbogo/gost/container/gxset"
+	gxset "github.com/dubbogo/gost/container/set"
 	gxnet "github.com/dubbogo/gost/net"
 )
 
diff --git a/config_center/configurator/override_test.go b/config_center/configurator/override_test.go
index a585f4217f81a5d600ec9a48c12b3b47ff2d5322..329c598efe8ef79d7fc1b79ae182c59b238283ac 100644
--- a/config_center/configurator/override_test.go
+++ b/config_center/configurator/override_test.go
@@ -17,7 +17,6 @@
 package configurator
 
 import (
-	"context"
 	"testing"
 )
 
@@ -32,45 +31,49 @@ import (
 )
 
 func Test_configureVerison2p6(t *testing.T) {
-	url, err := common.NewURL(context.Background(), "override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService")
+	url, err := common.NewURL("override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService")
 	assert.NoError(t, err)
 	configurator := extension.GetConfigurator("default", &url)
 	assert.Equal(t, "override", configurator.GetUrl().Protocol)
 
-	providerUrl, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
+	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
+	assert.NoError(t, err)
 	configurator.Configure(&providerUrl)
 	assert.Equal(t, "failfast", providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 
 }
 func Test_configureVerisonOverrideAddr(t *testing.T) {
-	url, err := common.NewURL(context.Background(), "override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&providerAddresses=127.0.0.2:20001|127.0.0.3:20001")
+	url, err := common.NewURL("override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&providerAddresses=127.0.0.2:20001|127.0.0.3:20001")
 	assert.NoError(t, err)
 	configurator := extension.GetConfigurator("default", &url)
 	assert.Equal(t, "override", configurator.GetUrl().Protocol)
 
-	providerUrl, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
+	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
+	assert.NoError(t, err)
 	configurator.Configure(&providerUrl)
 	assert.Equal(t, "failover", providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 
 }
 func Test_configureVerison2p6WithIp(t *testing.T) {
-	url, err := common.NewURL(context.Background(), "override://127.0.0.1:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService")
+	url, err := common.NewURL("override://127.0.0.1:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService")
 	assert.NoError(t, err)
 	configurator := extension.GetConfigurator("default", &url)
 	assert.Equal(t, "override", configurator.GetUrl().Protocol)
 
-	providerUrl, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
+	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
+	assert.NoError(t, err)
 	configurator.Configure(&providerUrl)
 	assert.Equal(t, "failfast", providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 
 }
 
 func Test_configureVerison2p7(t *testing.T) {
-	url, err := common.NewURL(context.Background(), "jsonrpc://0.0.0.0:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&configVersion=1.0&side=provider")
+	url, err := common.NewURL("jsonrpc://0.0.0.0:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&configVersion=1.0&side=provider")
 	assert.NoError(t, err)
 	configurator := extension.GetConfigurator("default", &url)
 
-	providerUrl, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
+	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
+	assert.NoError(t, err)
 	configurator.Configure(&providerUrl)
 	assert.Equal(t, "failfast", providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 
diff --git a/config_center/dynamic_configuration.go b/config_center/dynamic_configuration.go
index 0546d39732deaa83ace948275a0d4448b1b24cf8..90cd3bbb1d502a0e9ceb8fed5c94a4091bc0578e 100644
--- a/config_center/dynamic_configuration.go
+++ b/config_center/dynamic_configuration.go
@@ -28,9 +28,14 @@ import (
 //////////////////////////////////////////
 // DynamicConfiguration
 //////////////////////////////////////////
-const DEFAULT_GROUP = "dubbo"
-const DEFAULT_CONFIG_TIMEOUT = "10s"
+const (
+	// DEFAULT_GROUP: default group
+	DEFAULT_GROUP = "dubbo"
+	// DEFAULT_CONFIG_TIMEOUT: default config timeout
+	DEFAULT_CONFIG_TIMEOUT = "10s"
+)
 
+// DynamicConfiguration ...
 type DynamicConfiguration interface {
 	Parser() parser.ConfigurationParser
 	SetParser(parser.ConfigurationParser)
@@ -46,19 +51,23 @@ type DynamicConfiguration interface {
 	GetInternalProperty(string, ...Option) (string, error)
 }
 
+// Options ...
 type Options struct {
 	Group   string
 	Timeout time.Duration
 }
 
+// Option ...
 type Option func(*Options)
 
+// WithGroup ...
 func WithGroup(group string) Option {
 	return func(opt *Options) {
 		opt.Group = group
 	}
 }
 
+// WithTimeout ...
 func WithTimeout(time time.Duration) Option {
 	return func(opt *Options) {
 		opt.Timeout = time
diff --git a/config_center/dynamic_configuration_factory.go b/config_center/dynamic_configuration_factory.go
index 0720896fb615f8639c20a46d2078c3dfcd112c32..9f9b13227f6623a02b0261c46d8d1e43624005f8 100644
--- a/config_center/dynamic_configuration_factory.go
+++ b/config_center/dynamic_configuration_factory.go
@@ -21,6 +21,7 @@ import (
 	"github.com/apache/dubbo-go/common"
 )
 
+// DynamicConfigurationFactory ...
 type DynamicConfigurationFactory interface {
 	GetDynamicConfiguration(*common.URL) (DynamicConfiguration, error)
 }
diff --git a/config_center/mock_dynamic_config.go b/config_center/mock_dynamic_config.go
index 79c7c171945400a52563e0b66ef29c2896db0b99..4d972b629abb7abd7cc0d0018026e4ccc04a1e4f 100644
--- a/config_center/mock_dynamic_config.go
+++ b/config_center/mock_dynamic_config.go
@@ -32,6 +32,7 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
+// MockDynamicConfigurationFactory ...
 type MockDynamicConfigurationFactory struct {
 	Content string
 }
@@ -41,7 +42,8 @@ var (
 	dynamicConfiguration *MockDynamicConfiguration
 )
 
-func (f *MockDynamicConfigurationFactory) GetDynamicConfiguration(url *common.URL) (DynamicConfiguration, error) {
+// GetDynamicConfiguration ...
+func (f *MockDynamicConfigurationFactory) GetDynamicConfiguration(_ *common.URL) (DynamicConfiguration, error) {
 	var err error
 	once.Do(func() {
 		dynamicConfiguration = &MockDynamicConfiguration{listener: map[string]ConfigurationListener{}}
@@ -79,48 +81,59 @@ func (f *MockDynamicConfigurationFactory) GetDynamicConfiguration(url *common.UR
 
 }
 
+// MockDynamicConfiguration ...
 type MockDynamicConfiguration struct {
 	parser   parser.ConfigurationParser
 	content  string
 	listener map[string]ConfigurationListener
 }
 
-func (c *MockDynamicConfiguration) AddListener(key string, listener ConfigurationListener, opions ...Option) {
+// AddListener ...
+func (c *MockDynamicConfiguration) AddListener(key string, listener ConfigurationListener, _ ...Option) {
 	c.listener[key] = listener
 }
 
-func (c *MockDynamicConfiguration) RemoveListener(key string, listener ConfigurationListener, opions ...Option) {
+// RemoveListener ...
+func (c *MockDynamicConfiguration) RemoveListener(_ string, _ ConfigurationListener, _ ...Option) {
 }
 
-func (c *MockDynamicConfiguration) GetConfig(key string, opts ...Option) (string, error) {
+// GetConfig ...
+func (c *MockDynamicConfiguration) GetConfig(_ string, _ ...Option) (string, error) {
 
 	return c.content, nil
 }
 
-//For zookeeper, getConfig and getConfigs have the same meaning.
+// GetConfigs For zookeeper, getConfig and getConfigs have the same meaning.
 func (c *MockDynamicConfiguration) GetConfigs(key string, opts ...Option) (string, error) {
 	return c.GetConfig(key, opts...)
 }
 
+// Parser ...
 func (c *MockDynamicConfiguration) Parser() parser.ConfigurationParser {
 	return c.parser
 }
+
+// SetParser ...
 func (c *MockDynamicConfiguration) SetParser(p parser.ConfigurationParser) {
 	c.parser = p
 }
-func (c *MockDynamicConfiguration) GetProperties(key string, opts ...Option) (string, error) {
+
+// GetProperties ...
+func (c *MockDynamicConfiguration) GetProperties(_ string, _ ...Option) (string, error) {
 	return c.content, nil
 }
 
-//For zookeeper, getConfig and getConfigs have the same meaning.
+// GetInternalProperty For zookeeper, getConfig and getConfigs have the same meaning.
 func (c *MockDynamicConfiguration) GetInternalProperty(key string, opts ...Option) (string, error) {
 	return c.GetProperties(key, opts...)
 }
 
+// GetRule ...
 func (c *MockDynamicConfiguration) GetRule(key string, opts ...Option) (string, error) {
 	return c.GetProperties(key, opts...)
 }
 
+// MockServiceConfigEvent ...
 func (c *MockDynamicConfiguration) MockServiceConfigEvent() {
 	config := &parser.ConfiguratorConfig{
 		ConfigVersion: "2.7.1",
@@ -142,6 +155,7 @@ func (c *MockDynamicConfiguration) MockServiceConfigEvent() {
 	c.listener[key].Process(&ConfigChangeEvent{Key: key, Value: string(value), ConfigType: remoting.EventTypeAdd})
 }
 
+// MockApplicationConfigEvent ...
 func (c *MockDynamicConfiguration) MockApplicationConfigEvent() {
 	config := &parser.ConfiguratorConfig{
 		ConfigVersion: "2.7.1",
diff --git a/config_center/parser/configuration_parser.go b/config_center/parser/configuration_parser.go
index 85033ce97f3e9038d57b6156e6dc68139363e8c3..58fcdb49dad2c53270894a65bf4ebd9595dc420e 100644
--- a/config_center/parser/configuration_parser.go
+++ b/config_center/parser/configuration_parser.go
@@ -18,7 +18,6 @@
 package parser
 
 import (
-	"context"
 	"strconv"
 	"strings"
 )
@@ -36,18 +35,22 @@ import (
 )
 
 const (
+	// ScopeApplication ...
 	ScopeApplication = "application"
-	GeneralType      = "general"
+	// GeneralType ...
+	GeneralType = "general"
 )
 
+// ConfigurationParser ...
 type ConfigurationParser interface {
 	Parse(string) (map[string]string, error)
 	ParseToUrls(content string) ([]*common.URL, error)
 }
 
-//for support properties file in config center
+// DefaultConfigurationParser for support properties file in config center
 type DefaultConfigurationParser struct{}
 
+// ConfiguratorConfig ...
 type ConfiguratorConfig struct {
 	ConfigVersion string       `yaml:"configVersion"`
 	Scope         string       `yaml:"scope"`
@@ -56,6 +59,7 @@ type ConfiguratorConfig struct {
 	Configs       []ConfigItem `yaml:"configs"`
 }
 
+// ConfigItem ...
 type ConfigItem struct {
 	Type              string            `yaml:"type"`
 	Enabled           bool              `yaml:"enabled"`
@@ -67,15 +71,17 @@ type ConfigItem struct {
 	Side              string            `yaml:"side"`
 }
 
+// Parse ...
 func (parser *DefaultConfigurationParser) Parse(content string) (map[string]string, error) {
-	properties, err := properties.LoadString(content)
+	pps, err := properties.LoadString(content)
 	if err != nil {
 		logger.Errorf("Parse the content {%v} in DefaultConfigurationParser error ,error message is {%v}", content, err)
 		return nil, err
 	}
-	return properties.Map(), nil
+	return pps.Map(), nil
 }
 
+// ParseToUrls ...
 func (parser *DefaultConfigurationParser) ParseToUrls(content string) ([]*common.URL, error) {
 	config := ConfiguratorConfig{}
 	if err := yaml.Unmarshal([]byte(content), &config); err != nil {
@@ -132,14 +138,14 @@ func serviceItemToUrls(item ConfigItem, config ConfiguratorConfig) ([]*common.UR
 				newUrlStr := urlStr
 				newUrlStr = newUrlStr + "&application"
 				newUrlStr = newUrlStr + v
-				url, err := common.NewURL(context.Background(), newUrlStr)
+				url, err := common.NewURL(newUrlStr)
 				if err != nil {
 					return nil, perrors.WithStack(err)
 				}
 				urls = append(urls, &url)
 			}
 		} else {
-			url, err := common.NewURL(context.Background(), urlStr)
+			url, err := common.NewURL(urlStr)
 			if err != nil {
 				return nil, perrors.WithStack(err)
 			}
@@ -178,7 +184,7 @@ func appItemToUrls(item ConfigItem, config ConfiguratorConfig) ([]*common.URL, e
 			urlStr = urlStr + constant.APP_DYNAMIC_CONFIGURATORS_CATEGORY
 			urlStr = urlStr + "&configVersion="
 			urlStr = urlStr + config.ConfigVersion
-			url, err := common.NewURL(context.Background(), urlStr)
+			url, err := common.NewURL(urlStr)
 			if err != nil {
 				return nil, perrors.WithStack(err)
 			}
diff --git a/config_center/zookeeper/impl.go b/config_center/zookeeper/impl.go
index 504d4910581aff52afa74b13fdfce61c9170ca48..70fb196a1eedb994eae38576de35d36deb450aaa 100644
--- a/config_center/zookeeper/impl.go
+++ b/config_center/zookeeper/impl.go
@@ -24,8 +24,8 @@ import (
 )
 
 import (
+	"github.com/dubbogo/go-zookeeper/zk"
 	perrors "github.com/pkg/errors"
-	"github.com/samuel/go-zookeeper/zk"
 )
 
 import (
@@ -37,7 +37,11 @@ import (
 	"github.com/apache/dubbo-go/remoting/zookeeper"
 )
 
-const ZkClient = "zk config_center"
+const (
+	// ZkClient
+	//zookeeper client name
+	ZkClient = "zk config_center"
+)
 
 type zookeeperDynamicConfiguration struct {
 	url      *common.URL
@@ -134,10 +138,9 @@ func (c *zookeeperDynamicConfiguration) GetProperties(key string, opts ...config
 	content, _, err := c.client.GetContent(c.rootPath + "/" + key)
 	if err != nil {
 		return "", perrors.WithStack(err)
-	} else {
-		return string(content), nil
 	}
 
+	return string(content), nil
 }
 
 //For zookeeper, getConfig and getConfigs have the same meaning.
@@ -156,57 +159,57 @@ func (c *zookeeperDynamicConfiguration) SetParser(p parser.ConfigurationParser)
 	c.parser = p
 }
 
-func (r *zookeeperDynamicConfiguration) ZkClient() *zookeeper.ZookeeperClient {
-	return r.client
+func (c *zookeeperDynamicConfiguration) ZkClient() *zookeeper.ZookeeperClient {
+	return c.client
 }
 
-func (r *zookeeperDynamicConfiguration) SetZkClient(client *zookeeper.ZookeeperClient) {
-	r.client = client
+func (c *zookeeperDynamicConfiguration) SetZkClient(client *zookeeper.ZookeeperClient) {
+	c.client = client
 }
 
-func (r *zookeeperDynamicConfiguration) ZkClientLock() *sync.Mutex {
-	return &r.cltLock
+func (c *zookeeperDynamicConfiguration) ZkClientLock() *sync.Mutex {
+	return &c.cltLock
 }
 
-func (r *zookeeperDynamicConfiguration) WaitGroup() *sync.WaitGroup {
-	return &r.wg
+func (c *zookeeperDynamicConfiguration) WaitGroup() *sync.WaitGroup {
+	return &c.wg
 }
 
-func (r *zookeeperDynamicConfiguration) GetDone() chan struct{} {
-	return r.done
+func (c *zookeeperDynamicConfiguration) Done() chan struct{} {
+	return c.done
 }
 
-func (r *zookeeperDynamicConfiguration) GetUrl() common.URL {
-	return *r.url
+func (c *zookeeperDynamicConfiguration) GetUrl() common.URL {
+	return *c.url
 }
 
-func (r *zookeeperDynamicConfiguration) Destroy() {
-	if r.listener != nil {
-		r.listener.Close()
+func (c *zookeeperDynamicConfiguration) Destroy() {
+	if c.listener != nil {
+		c.listener.Close()
 	}
-	close(r.done)
-	r.wg.Wait()
-	r.closeConfigs()
+	close(c.done)
+	c.wg.Wait()
+	c.closeConfigs()
 }
 
-func (r *zookeeperDynamicConfiguration) IsAvailable() bool {
+func (c *zookeeperDynamicConfiguration) IsAvailable() bool {
 	select {
-	case <-r.done:
+	case <-c.done:
 		return false
 	default:
 		return true
 	}
 }
 
-func (r *zookeeperDynamicConfiguration) closeConfigs() {
-	r.cltLock.Lock()
-	defer r.cltLock.Unlock()
+func (c *zookeeperDynamicConfiguration) closeConfigs() {
+	c.cltLock.Lock()
+	defer c.cltLock.Unlock()
 	logger.Infof("begin to close provider zk client")
 	// Close the old client first to close the tmp node
-	r.client.Close()
-	r.client = nil
+	c.client.Close()
+	c.client = nil
 }
 
-func (r *zookeeperDynamicConfiguration) RestartCallBack() bool {
+func (c *zookeeperDynamicConfiguration) RestartCallBack() bool {
 	return true
 }
diff --git a/config_center/zookeeper/impl_test.go b/config_center/zookeeper/impl_test.go
index e614009faa5b32873c6245dea5c85cc2747e19ea..1d62f3df86f5706823cab7c9ed0bc1a7d9b380f3 100644
--- a/config_center/zookeeper/impl_test.go
+++ b/config_center/zookeeper/impl_test.go
@@ -17,14 +17,13 @@
 package zookeeper
 
 import (
-	"context"
 	"fmt"
 	"sync"
 	"testing"
 )
 
 import (
-	"github.com/samuel/go-zookeeper/zk"
+	"github.com/dubbogo/go-zookeeper/zk"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -35,7 +34,7 @@ import (
 )
 
 func initZkData(group string, t *testing.T) (*zk.TestCluster, *zookeeperDynamicConfiguration) {
-	regurl, _ := common.NewURL(context.TODO(), "registry://127.0.0.1:1111")
+	regurl, _ := common.NewURL("registry://127.0.0.1:1111")
 	ts, reg, err := newMockZookeeperDynamicConfiguration(&regurl)
 	reg.SetParser(&parser.DefaultConfigurationParser{})
 
diff --git a/config_center/zookeeper/listener.go b/config_center/zookeeper/listener.go
index 7128b6f5a39e243840a1076f9fc506d94c7ed2ed..122dfaf4f268a706151de6acdaa78bb46e59f8fb 100644
--- a/config_center/zookeeper/listener.go
+++ b/config_center/zookeeper/listener.go
@@ -27,25 +27,30 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
+// CacheListener ...
 type CacheListener struct {
 	keyListeners sync.Map
 	rootPath     string
 }
 
+// NewCacheListener ...
 func NewCacheListener(rootPath string) *CacheListener {
 	return &CacheListener{rootPath: rootPath}
 }
+
+// AddListener ...
 func (l *CacheListener) AddListener(key string, listener config_center.ConfigurationListener) {
 
 	// reference from https://stackoverflow.com/questions/34018908/golang-why-dont-we-have-a-set-datastructure
 	// make a map[your type]struct{} like set in java
-	listeners, loaded := l.keyListeners.LoadOrStore(key, map[config_center.ConfigurationListener]struct{}{listener: struct{}{}})
+	listeners, loaded := l.keyListeners.LoadOrStore(key, map[config_center.ConfigurationListener]struct{}{listener: {}})
 	if loaded {
 		listeners.(map[config_center.ConfigurationListener]struct{})[listener] = struct{}{}
 		l.keyListeners.Store(key, listeners)
 	}
 }
 
+// RemoveListener ...
 func (l *CacheListener) RemoveListener(key string, listener config_center.ConfigurationListener) {
 	listeners, loaded := l.keyListeners.Load(key)
 	if loaded {
@@ -53,6 +58,7 @@ func (l *CacheListener) RemoveListener(key string, listener config_center.Config
 	}
 }
 
+// DataChange ...
 func (l *CacheListener) DataChange(event remoting.Event) bool {
 	if event.Content == "" {
 		//meanings new node
diff --git a/contributing.md b/contributing.md
index b1265c2351789d4929d81556d72234806aed6afa..9ee2dae32fad6caaf9e19c5e98e8b99b61c26a51 100644
--- a/contributing.md
+++ b/contributing.md
@@ -28,4 +28,14 @@ The title format of the pull request `MUST` follow the following rules:
 
 ### 3.1 log
 
-> 1 when logging the function's input parameter, you should add '@' before input parameter name.
+>- 1 when logging the function's input parameter, you should add '@' before input parameter name.
+
+### 3.2 naming
+
+>- 1 do not use an underscore in package name, such as `filter_impl`.
+>- 2 do not use an underscore in constants, such as `DUBBO_PROTOCOL`. use 'DubboProtocol' instead.
+
+### 3.3 comment
+
+>- 1 there should be comment for every export func/var.
+>- 2 the comment should begin with function name/var name.
\ No newline at end of file
diff --git a/filter/access_key.go b/filter/access_key.go
new file mode 100644
index 0000000000000000000000000000000000000000..c9bdd4ff8993d51e4d5002a1216225e2da074df5
--- /dev/null
+++ b/filter/access_key.go
@@ -0,0 +1,22 @@
+package filter
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+type AccessKeyPair struct {
+	AccessKey    string `yaml:"accessKey"   json:"accessKey,omitempty" property:"accessKey"`
+	SecretKey    string `yaml:"secretKey"   json:"secretKey,omitempty" property:"secretKey"`
+	ConsumerSide string `yaml:"consumerSide"   json:"ConsumerSide,consumerSide" property:"consumerSide"`
+	ProviderSide string `yaml:"providerSide"   json:"providerSide,omitempty" property:"providerSide"`
+	Creator      string `yaml:"creator"   json:"creator,omitempty" property:"creator"`
+	Options      string `yaml:"options"   json:"options,omitempty" property:"options"`
+}
+
+// AccessKeyStorage
+// This SPI Extension support us to store our AccessKeyPair or load AccessKeyPair from other
+// storage, such as filesystem.
+type AccessKeyStorage interface {
+	GetAccessKeyPair(protocol.Invocation, *common.URL) *AccessKeyPair
+}
diff --git a/filter/authenticator.go b/filter/authenticator.go
new file mode 100644
index 0000000000000000000000000000000000000000..ce0547b36b03b7078784a6c05c08cd3f89611ca4
--- /dev/null
+++ b/filter/authenticator.go
@@ -0,0 +1,18 @@
+package filter
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+// Authenticator
+type Authenticator interface {
+
+	// Sign
+	// give a sign to request
+	Sign(protocol.Invocation, *common.URL) error
+
+	// Authenticate
+	// verify the signature of the request is valid or not
+	Authenticate(protocol.Invocation, *common.URL) error
+}
diff --git a/filter/filter.go b/filter/filter.go
index 5bd78998a76a1b0e8af99b0b3f0d7e6c103bb794..c069510498c7ac68b2bb2169dfe7132a4ef63229 100644
--- a/filter/filter.go
+++ b/filter/filter.go
@@ -17,12 +17,16 @@
 
 package filter
 
+import (
+	"context"
+)
 import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// Filter
 // Extension - Filter
 type Filter interface {
-	Invoke(protocol.Invoker, protocol.Invocation) protocol.Result
-	OnResponse(protocol.Result, protocol.Invoker, protocol.Invocation) protocol.Result
+	Invoke(context.Context, protocol.Invoker, protocol.Invocation) protocol.Result
+	OnResponse(context.Context, protocol.Result, protocol.Invoker, protocol.Invocation) protocol.Result
 }
diff --git a/filter/impl/access_log_filter.go b/filter/filter_impl/access_log_filter.go
similarity index 89%
rename from filter/impl/access_log_filter.go
rename to filter/filter_impl/access_log_filter.go
index 89fa34952f99057f1d8bb35794a57f9905f5f169..fbfe7565170c7df468f755a4bd1aadde166a79c1 100644
--- a/filter/impl/access_log_filter.go
+++ b/filter/filter_impl/access_log_filter.go
@@ -15,9 +15,10 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
 import (
+	"context"
 	"os"
 	"reflect"
 	"strings"
@@ -34,13 +35,21 @@ import (
 
 const (
 	//used in URL.
-	FileDateFormat    = "2006-01-02"
+
+	// FileDateFormat ...
+	FileDateFormat = "2006-01-02"
+	// MessageDateLayout ...
 	MessageDateLayout = "2006-01-02 15:04:05"
-	LogMaxBuffer      = 5000
-	LogFileMode       = 0600
+	// LogMaxBuffer ...
+	LogMaxBuffer = 5000
+	// LogFileMode ...
+	LogFileMode = 0600
 
 	// those fields are the data collected by this filter
-	Types     = "types"
+
+	// Types ...
+	Types = "types"
+	// Arguments ...
 	Arguments = "arguments"
 )
 
@@ -49,6 +58,7 @@ func init() {
 }
 
 /*
+ * AccessLogFilter
  * Although the access log filter is a default filter,
  * you should config "accesslog" in service's config to tell the filter where store the access log.
  * for example:
@@ -66,13 +76,14 @@ type AccessLogFilter struct {
 	logChan chan AccessLogData
 }
 
-func (ef *AccessLogFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// Invoke ...
+func (ef *AccessLogFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	accessLog := invoker.GetUrl().GetParam(constant.ACCESS_LOG_KEY, "")
 	if len(accessLog) > 0 {
 		accessLogData := AccessLogData{data: ef.buildAccessLogData(invoker, invocation), accessLog: accessLog}
 		ef.logIntoChannel(accessLogData)
 	}
-	return invoker.Invoke(invocation)
+	return invoker.Invoke(ctx, invocation)
 }
 
 // it won't block the invocation
@@ -86,7 +97,7 @@ func (ef *AccessLogFilter) logIntoChannel(accessLogData AccessLogData) {
 	}
 }
 
-func (ef *AccessLogFilter) buildAccessLogData(invoker protocol.Invoker, invocation protocol.Invocation) map[string]string {
+func (ef *AccessLogFilter) buildAccessLogData(_ protocol.Invoker, invocation protocol.Invocation) map[string]string {
 	dataMap := make(map[string]string, 16)
 	attachments := invocation.Attachments()
 	dataMap[constant.INTERFACE_KEY] = attachments[constant.INTERFACE_KEY]
@@ -119,7 +130,8 @@ func (ef *AccessLogFilter) buildAccessLogData(invoker protocol.Invoker, invocati
 	return dataMap
 }
 
-func (ef *AccessLogFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// OnResponse ...
+func (ef *AccessLogFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker, _ protocol.Invocation) protocol.Result {
 	return result
 }
 
@@ -172,6 +184,7 @@ func isDefault(accessLog string) bool {
 	return strings.EqualFold("true", accessLog) || strings.EqualFold("default", accessLog)
 }
 
+// GetAccessLogFilter ...
 func GetAccessLogFilter() filter.Filter {
 	accessLogFilter := &AccessLogFilter{logChan: make(chan AccessLogData, LogMaxBuffer)}
 	go func() {
@@ -182,6 +195,7 @@ func GetAccessLogFilter() filter.Filter {
 	return accessLogFilter
 }
 
+// AccessLogData ...
 type AccessLogData struct {
 	accessLog string
 	data      map[string]string
diff --git a/filter/impl/access_log_filter_test.go b/filter/filter_impl/access_log_filter_test.go
similarity index 84%
rename from filter/impl/access_log_filter_test.go
rename to filter/filter_impl/access_log_filter_test.go
index 834d531f05f952c41abfe8e1c56c20c0285926b8..f0de24d2a89f35876a32763eeb75495e8919ecd9 100644
--- a/filter/impl/access_log_filter_test.go
+++ b/filter/filter_impl/access_log_filter_test.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
 import (
 	"context"
@@ -37,11 +37,11 @@ import (
 func TestAccessLogFilter_Invoke_Not_Config(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	url, _ := common.NewURL(context.Background(),
-		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+
-			"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+
-			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+
-			"BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&"+
+	url, _ := common.NewURL(
+		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" +
+			"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." +
+			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" +
+			"BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&" +
 			"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
 	invoker := protocol.NewBaseInvoker(url)
 
@@ -49,18 +49,18 @@ func TestAccessLogFilter_Invoke_Not_Config(t *testing.T) {
 	inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach)
 
 	accessLogFilter := GetAccessLogFilter()
-	result := accessLogFilter.Invoke(invoker, inv)
+	result := accessLogFilter.Invoke(context.Background(), invoker, inv)
 	assert.Nil(t, result.Error())
 }
 
 func TestAccessLogFilter_Invoke_Default_Config(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	url, _ := common.NewURL(context.Background(),
-		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+
-			"&cluster=failover&accesslog=true&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+
-			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+
-			"BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&"+
+	url, _ := common.NewURL(
+		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" +
+			"&cluster=failover&accesslog=true&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." +
+			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" +
+			"BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&" +
 			"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
 	invoker := protocol.NewBaseInvoker(url)
 
@@ -70,13 +70,13 @@ func TestAccessLogFilter_Invoke_Default_Config(t *testing.T) {
 	inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach)
 
 	accessLogFilter := GetAccessLogFilter()
-	result := accessLogFilter.Invoke(invoker, inv)
+	result := accessLogFilter.Invoke(context.Background(), invoker, inv)
 	assert.Nil(t, result.Error())
 }
 
 func TestAccessLogFilter_OnResponse(t *testing.T) {
 	result := &protocol.RPCResult{}
 	accessLogFilter := GetAccessLogFilter()
-	response := accessLogFilter.OnResponse(result, nil, nil)
+	response := accessLogFilter.OnResponse(nil, result, nil, nil)
 	assert.Equal(t, result, response)
 }
diff --git a/filter/impl/active_filter.go b/filter/filter_impl/active_filter.go
similarity index 53%
rename from filter/impl/active_filter.go
rename to filter/filter_impl/active_filter.go
index 36a4e1a767ab7170ce8e5bebf2cfa4403f6ad4ff..23f2c8e25609dff89392107251715fe6f5175f09 100644
--- a/filter/impl/active_filter.go
+++ b/filter/filter_impl/active_filter.go
@@ -15,37 +15,56 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
+
+import (
+	"context"
+	"strconv"
+)
 
 import (
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/filter"
 	"github.com/apache/dubbo-go/protocol"
+	invocation2 "github.com/apache/dubbo-go/protocol/invocation"
 )
 
-const active = "active"
+const (
+	active               = "active"
+	dubboInvokeStartTime = "dubboInvokeStartTime"
+)
 
 func init() {
 	extension.SetFilter(active, GetActiveFilter)
 }
 
+// ActiveFilter ...
 type ActiveFilter struct {
 }
 
-func (ef *ActiveFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// Invoke ...
+func (ef *ActiveFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	logger.Infof("invoking active filter. %v,%v", invocation.MethodName(), len(invocation.Arguments()))
-
+	invocation.(*invocation2.RPCInvocation).SetAttachments(dubboInvokeStartTime, strconv.FormatInt(protocol.CurrentTimeMillis(), 10))
 	protocol.BeginCount(invoker.GetUrl(), invocation.MethodName())
-	return invoker.Invoke(invocation)
+	return invoker.Invoke(ctx, invocation)
 }
 
-func (ef *ActiveFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
-
-	protocol.EndCount(invoker.GetUrl(), invocation.MethodName())
+// OnResponse ...
+func (ef *ActiveFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	startTime, err := strconv.ParseInt(invocation.(*invocation2.RPCInvocation).AttachmentsByKey(dubboInvokeStartTime, "0"), 10, 64)
+	if err != nil {
+		result.SetError(err)
+		logger.Errorf("parse dubbo_invoke_start_time to int64 failed")
+		return result
+	}
+	elapsed := protocol.CurrentTimeMillis() - startTime
+	protocol.EndCount(invoker.GetUrl(), invocation.MethodName(), elapsed, result.Error() == nil)
 	return result
 }
 
+// GetActiveFilter ...
 func GetActiveFilter() filter.Filter {
 	return &ActiveFilter{}
 }
diff --git a/filter/filter_impl/active_filter_test.go b/filter/filter_impl/active_filter_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8917e9141cad4f22ea201a9a07c2873b584c1f92
--- /dev/null
+++ b/filter/filter_impl/active_filter_test.go
@@ -0,0 +1,66 @@
+package filter_impl
+
+import (
+	"context"
+	"errors"
+	"strconv"
+	"testing"
+)
+
+import (
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/protocol/mock"
+)
+
+func TestActiveFilter_Invoke(t *testing.T) {
+	invoc := invocation.NewRPCInvocation("test", []interface{}{"OK"}, make(map[string]string, 0))
+	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	filter := ActiveFilter{}
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	invoker := mock.NewMockInvoker(ctrl)
+	invoker.EXPECT().Invoke(gomock.Any()).Return(nil)
+	invoker.EXPECT().GetUrl().Return(url).Times(1)
+	filter.Invoke(context.Background(), invoker, invoc)
+	assert.True(t, invoc.AttachmentsByKey(dubboInvokeStartTime, "") != "")
+
+}
+
+func TestActiveFilter_OnResponse(t *testing.T) {
+	c := protocol.CurrentTimeMillis()
+	elapsed := 100
+	invoc := invocation.NewRPCInvocation("test", []interface{}{"OK"}, map[string]string{
+		dubboInvokeStartTime: strconv.FormatInt(c-int64(elapsed), 10),
+	})
+	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	filter := ActiveFilter{}
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	invoker := mock.NewMockInvoker(ctrl)
+	invoker.EXPECT().GetUrl().Return(url).Times(1)
+	result := &protocol.RPCResult{
+		Err: errors.New("test"),
+	}
+	filter.OnResponse(nil, result, invoker, invoc)
+	methodStatus := protocol.GetMethodStatus(url, "test")
+	urlStatus := protocol.GetURLStatus(url)
+
+	assert.Equal(t, int32(1), methodStatus.GetTotal())
+	assert.Equal(t, int32(1), urlStatus.GetTotal())
+	assert.Equal(t, int32(1), methodStatus.GetFailed())
+	assert.Equal(t, int32(1), urlStatus.GetFailed())
+	assert.Equal(t, int32(1), methodStatus.GetSuccessiveRequestFailureCount())
+	assert.Equal(t, int32(1), urlStatus.GetSuccessiveRequestFailureCount())
+	assert.True(t, methodStatus.GetFailedElapsed() >= int64(elapsed))
+	assert.True(t, urlStatus.GetFailedElapsed() >= int64(elapsed))
+	assert.True(t, urlStatus.GetLastRequestFailedTimestamp() != int64(0))
+	assert.True(t, methodStatus.GetLastRequestFailedTimestamp() != int64(0))
+
+}
diff --git a/filter/filter_impl/auth/accesskey_storage.go b/filter/filter_impl/auth/accesskey_storage.go
new file mode 100644
index 0000000000000000000000000000000000000000..0a2bf47cbd377899ba8a0edf4a67026dd827d41f
--- /dev/null
+++ b/filter/filter_impl/auth/accesskey_storage.go
@@ -0,0 +1,31 @@
+package auth
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/filter"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+// DefaultAccesskeyStorage
+// The default implementation of AccesskeyStorage
+type DefaultAccesskeyStorage struct {
+}
+
+// GetAccessKeyPair
+// get AccessKeyPair from url by the key "accessKeyId" and "secretAccessKey"
+func (storage *DefaultAccesskeyStorage) GetAccessKeyPair(invocation protocol.Invocation, url *common.URL) *filter.AccessKeyPair {
+	return &filter.AccessKeyPair{
+		AccessKey: url.GetParam(constant.ACCESS_KEY_ID_KEY, ""),
+		SecretKey: url.GetParam(constant.SECRET_ACCESS_KEY_KEY, ""),
+	}
+}
+
+func init() {
+	extension.SetAccesskeyStorages(constant.DEFAULT_ACCESS_KEY_STORAGE, GetDefaultAccesskeyStorage)
+}
+
+func GetDefaultAccesskeyStorage() filter.AccessKeyStorage {
+	return &DefaultAccesskeyStorage{}
+}
diff --git a/filter/filter_impl/auth/accesskey_storage_test.go b/filter/filter_impl/auth/accesskey_storage_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6ab861a8673b191be0a8063980e1dc53e4e70f60
--- /dev/null
+++ b/filter/filter_impl/auth/accesskey_storage_test.go
@@ -0,0 +1,28 @@
+package auth
+
+import (
+	"net/url"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	invocation2 "github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestDefaultAccesskeyStorage_GetAccesskeyPair(t *testing.T) {
+	url := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.SECRET_ACCESS_KEY_KEY, "skey"),
+		common.WithParamsValue(constant.ACCESS_KEY_ID_KEY, "akey"))
+	invocation := &invocation2.RPCInvocation{}
+	storage := GetDefaultAccesskeyStorage()
+	accesskeyPair := storage.GetAccessKeyPair(invocation, url)
+	assert.Equal(t, "skey", accesskeyPair.SecretKey)
+	assert.Equal(t, "akey", accesskeyPair.AccessKey)
+}
diff --git a/filter/filter_impl/auth/consumer_sign.go b/filter/filter_impl/auth/consumer_sign.go
new file mode 100644
index 0000000000000000000000000000000000000000..be86b5c74bb9fd02b96483edb18571d47d205ee7
--- /dev/null
+++ b/filter/filter_impl/auth/consumer_sign.go
@@ -0,0 +1,43 @@
+package auth
+
+import (
+	"context"
+	"fmt"
+)
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/filter"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+// ConsumerSignFilter
+// This filter is working for signing the request on consumer side
+type ConsumerSignFilter struct {
+}
+
+func init() {
+	extension.SetFilter(constant.CONSUMER_SIGN_FILTER, getConsumerSignFilter)
+}
+
+func (csf *ConsumerSignFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	logger.Infof("invoking ConsumerSign filter.")
+	url := invoker.GetUrl()
+
+	err := doAuthWork(&url, func(authenticator filter.Authenticator) error {
+		return authenticator.Sign(invocation, &url)
+	})
+	if err != nil {
+		panic(fmt.Sprintf("Sign for invocation %s # %s failed", url.ServiceKey(), invocation.MethodName()))
+
+	}
+	return invoker.Invoke(ctx, invocation)
+}
+
+func (csf *ConsumerSignFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	return result
+}
+func getConsumerSignFilter() filter.Filter {
+	return &ConsumerSignFilter{}
+}
diff --git a/filter/filter_impl/auth/consumer_sign_test.go b/filter/filter_impl/auth/consumer_sign_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..9a90970b898b75f3c3f1b195062538e62505a082
--- /dev/null
+++ b/filter/filter_impl/auth/consumer_sign_test.go
@@ -0,0 +1,37 @@
+package auth
+
+import (
+	"context"
+	"testing"
+)
+
+import (
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/protocol/mock"
+)
+
+func TestConsumerSignFilter_Invoke(t *testing.T) {
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0")
+	url.SetParam(constant.SECRET_ACCESS_KEY_KEY, "sk")
+	url.SetParam(constant.ACCESS_KEY_ID_KEY, "ak")
+	inv := invocation.NewRPCInvocation("test", []interface{}{"OK"}, nil)
+	filter := &ConsumerSignFilter{}
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	invoker := mock.NewMockInvoker(ctrl)
+	result := &protocol.RPCResult{}
+	invoker.EXPECT().Invoke(inv).Return(result).Times(2)
+	invoker.EXPECT().GetUrl().Return(url).Times(2)
+	assert.Equal(t, result, filter.Invoke(context.Background(), invoker, inv))
+
+	url.SetParam(constant.SERVICE_AUTH_KEY, "true")
+	assert.Equal(t, result, filter.Invoke(context.Background(), invoker, inv))
+}
diff --git a/filter/filter_impl/auth/default_authenticator.go b/filter/filter_impl/auth/default_authenticator.go
new file mode 100644
index 0000000000000000000000000000000000000000..73eb9cddc0e1b7b4747da4b0f3e883075e349226
--- /dev/null
+++ b/filter/filter_impl/auth/default_authenticator.go
@@ -0,0 +1,120 @@
+package auth
+
+import (
+	"errors"
+	"fmt"
+	"github.com/apache/dubbo-go/filter"
+	"strconv"
+	"time"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/protocol"
+	invocation_impl "github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func init() {
+	extension.SetAuthenticator(constant.DEFAULT_AUTHENTICATOR, GetDefaultAuthenticator)
+}
+
+// DefaultAuthenticator
+// The default implemetation of Authenticator
+type DefaultAuthenticator struct {
+}
+
+// Sign
+// add the signature for the invocation
+func (authenticator *DefaultAuthenticator) Sign(invocation protocol.Invocation, url *common.URL) error {
+	currentTimeMillis := strconv.Itoa(int(time.Now().Unix() * 1000))
+
+	consumer := url.GetParam(constant.APPLICATION_KEY, "")
+	accessKeyPair, err := getAccessKeyPair(invocation, url)
+	if err != nil {
+		return errors.New("get accesskey pair failed, cause: " + err.Error())
+	}
+	inv := invocation.(*invocation_impl.RPCInvocation)
+	signature, err := getSignature(url, invocation, accessKeyPair.SecretKey, currentTimeMillis)
+	if err != nil {
+		return err
+	}
+	inv.SetAttachments(constant.REQUEST_SIGNATURE_KEY, signature)
+	inv.SetAttachments(constant.REQUEST_TIMESTAMP_KEY, currentTimeMillis)
+	inv.SetAttachments(constant.AK_KEY, accessKeyPair.AccessKey)
+	inv.SetAttachments(constant.CONSUMER, consumer)
+	return nil
+}
+
+// getSignature
+// get signature by the metadata and params of the invocation
+func getSignature(url *common.URL, invocation protocol.Invocation, secrectKey string, currentTime string) (string, error) {
+
+	requestString := fmt.Sprintf(constant.SIGNATURE_STRING_FORMAT,
+		url.ColonSeparatedKey(), invocation.MethodName(), secrectKey, currentTime)
+	var signature string
+	if parameterEncrypt := url.GetParamBool(constant.PARAMTER_SIGNATURE_ENABLE_KEY, false); parameterEncrypt {
+		var err error
+		if signature, err = SignWithParams(invocation.Arguments(), requestString, secrectKey); err != nil {
+			// TODO
+			return "", errors.New("sign the request with params failed, cause:" + err.Error())
+		}
+	} else {
+		signature = Sign(requestString, secrectKey)
+	}
+
+	return signature, nil
+}
+
+// Authenticate
+// This method verifies whether the signature sent by the requester is correct
+func (authenticator *DefaultAuthenticator) Authenticate(invocation protocol.Invocation, url *common.URL) error {
+	accessKeyId := invocation.AttachmentsByKey(constant.AK_KEY, "")
+
+	requestTimestamp := invocation.AttachmentsByKey(constant.REQUEST_TIMESTAMP_KEY, "")
+	originSignature := invocation.AttachmentsByKey(constant.REQUEST_SIGNATURE_KEY, "")
+	consumer := invocation.AttachmentsByKey(constant.CONSUMER, "")
+	if IsEmpty(accessKeyId, false) || IsEmpty(consumer, false) ||
+		IsEmpty(requestTimestamp, false) || IsEmpty(originSignature, false) {
+		return errors.New("failed to authenticate your ak/sk, maybe the consumer has not enabled the auth")
+	}
+
+	accessKeyPair, err := getAccessKeyPair(invocation, url)
+	if err != nil {
+		return errors.New("failed to authenticate , can't load the accessKeyPair")
+	}
+
+	computeSignature, err := getSignature(url, invocation, accessKeyPair.SecretKey, requestTimestamp)
+	if err != nil {
+		return err
+	}
+	if success := computeSignature == originSignature; !success {
+		return errors.New("failed to authenticate, signature is not correct")
+	}
+	return nil
+}
+
+func getAccessKeyPair(invocation protocol.Invocation, url *common.URL) (*filter.AccessKeyPair, error) {
+	accesskeyStorage := extension.GetAccesskeyStorages(url.GetParam(constant.ACCESS_KEY_STORAGE_KEY, constant.DEFAULT_ACCESS_KEY_STORAGE))
+	accessKeyPair := accesskeyStorage.GetAccessKeyPair(invocation, url)
+	if accessKeyPair == nil || IsEmpty(accessKeyPair.AccessKey, false) || IsEmpty(accessKeyPair.SecretKey, true) {
+		return nil, errors.New("accessKeyId or secretAccessKey not found")
+	} else {
+		return accessKeyPair, nil
+	}
+}
+
+func GetDefaultAuthenticator() filter.Authenticator {
+	return &DefaultAuthenticator{}
+}
+
+func doAuthWork(url *common.URL, do func(filter.Authenticator) error) error {
+
+	shouldAuth := url.GetParamBool(constant.SERVICE_AUTH_KEY, false)
+	if shouldAuth {
+		authenticator := extension.GetAuthenticator(url.GetParam(constant.AUTHENTICATOR_KEY, constant.DEFAULT_AUTHENTICATOR))
+		return do(authenticator)
+	}
+	return nil
+}
diff --git a/filter/filter_impl/auth/default_authenticator_test.go b/filter/filter_impl/auth/default_authenticator_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..72220eec99533b73cc2c9159e3443d6f566471fa
--- /dev/null
+++ b/filter/filter_impl/auth/default_authenticator_test.go
@@ -0,0 +1,130 @@
+package auth
+
+import (
+	"fmt"
+	"net/url"
+	"strconv"
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestDefaultAuthenticator_Authenticate(t *testing.T) {
+	secret := "dubbo-sk"
+	access := "dubbo-ak"
+	testurl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0")
+	testurl.SetParam(constant.PARAMTER_SIGNATURE_ENABLE_KEY, "true")
+	testurl.SetParam(constant.ACCESS_KEY_ID_KEY, access)
+	testurl.SetParam(constant.SECRET_ACCESS_KEY_KEY, secret)
+	parmas := []interface{}{"OK", struct {
+		Name string
+		Id   int64
+	}{"YUYU", 1}}
+	inv := invocation.NewRPCInvocation("test", parmas, nil)
+	requestTime := strconv.Itoa(int(time.Now().Unix() * 1000))
+	signature, _ := getSignature(&testurl, inv, secret, requestTime)
+
+	var authenticator = &DefaultAuthenticator{}
+
+	invcation := invocation.NewRPCInvocation("test", parmas, map[string]string{
+		constant.REQUEST_SIGNATURE_KEY: signature,
+		constant.CONSUMER:              "test",
+		constant.REQUEST_TIMESTAMP_KEY: requestTime,
+		constant.AK_KEY:                access,
+	})
+	err := authenticator.Authenticate(invcation, &testurl)
+	assert.Nil(t, err)
+	// modify the params
+	invcation = invocation.NewRPCInvocation("test", parmas[:1], map[string]string{
+		constant.REQUEST_SIGNATURE_KEY: signature,
+		constant.CONSUMER:              "test",
+		constant.REQUEST_TIMESTAMP_KEY: requestTime,
+		constant.AK_KEY:                access,
+	})
+	err = authenticator.Authenticate(invcation, &testurl)
+	assert.NotNil(t, err)
+
+}
+
+func TestDefaultAuthenticator_Sign(t *testing.T) {
+	authenticator := &DefaultAuthenticator{}
+	testurl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?application=test&interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0")
+	testurl.SetParam(constant.ACCESS_KEY_ID_KEY, "akey")
+	testurl.SetParam(constant.SECRET_ACCESS_KEY_KEY, "skey")
+	testurl.SetParam(constant.PARAMTER_SIGNATURE_ENABLE_KEY, "false")
+	inv := invocation.NewRPCInvocation("test", []interface{}{"OK"}, nil)
+	_ = authenticator.Sign(inv, &testurl)
+	assert.NotEqual(t, inv.AttachmentsByKey(constant.REQUEST_SIGNATURE_KEY, ""), "")
+	assert.NotEqual(t, inv.AttachmentsByKey(constant.CONSUMER, ""), "")
+	assert.NotEqual(t, inv.AttachmentsByKey(constant.REQUEST_TIMESTAMP_KEY, ""), "")
+	assert.Equal(t, inv.AttachmentsByKey(constant.AK_KEY, ""), "akey")
+
+}
+
+func Test_getAccessKeyPairSuccess(t *testing.T) {
+	testurl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.SECRET_ACCESS_KEY_KEY, "skey"),
+		common.WithParamsValue(constant.ACCESS_KEY_ID_KEY, "akey"))
+	invcation := invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, nil)
+	_, e := getAccessKeyPair(invcation, testurl)
+	assert.Nil(t, e)
+}
+
+func Test_getAccessKeyPairFailed(t *testing.T) {
+	defer func() {
+		e := recover()
+		assert.NotNil(t, e)
+	}()
+	testurl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.ACCESS_KEY_ID_KEY, "akey"))
+	invcation := invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, nil)
+	_, e := getAccessKeyPair(invcation, testurl)
+	assert.NotNil(t, e)
+	testurl = common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.SECRET_ACCESS_KEY_KEY, "skey"),
+		common.WithParamsValue(constant.ACCESS_KEY_ID_KEY, "akey"), common.WithParamsValue(constant.ACCESS_KEY_STORAGE_KEY, "dubbo"))
+	_, e = getAccessKeyPair(invcation, testurl)
+
+}
+
+func Test_getSignatureWithinParams(t *testing.T) {
+	testurl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0")
+	testurl.SetParam(constant.PARAMTER_SIGNATURE_ENABLE_KEY, "true")
+	inv := invocation.NewRPCInvocation("test", []interface{}{"OK"}, map[string]string{
+		"": "",
+	})
+	secret := "dubbo"
+	current := strconv.Itoa(int(time.Now().Unix() * 1000))
+	signature, _ := getSignature(&testurl, inv, secret, current)
+	requestString := fmt.Sprintf(constant.SIGNATURE_STRING_FORMAT,
+		testurl.ColonSeparatedKey(), inv.MethodName(), secret, current)
+	s, _ := SignWithParams(inv.Arguments(), requestString, secret)
+	assert.False(t, IsEmpty(signature, false))
+	assert.Equal(t, s, signature)
+}
+
+func Test_getSignature(t *testing.T) {
+	testurl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0")
+	testurl.SetParam(constant.PARAMTER_SIGNATURE_ENABLE_KEY, "false")
+	inv := invocation.NewRPCInvocation("test", []interface{}{"OK"}, nil)
+	secret := "dubbo"
+	current := strconv.Itoa(int(time.Now().Unix() * 1000))
+	signature, _ := getSignature(&testurl, inv, secret, current)
+	requestString := fmt.Sprintf(constant.SIGNATURE_STRING_FORMAT,
+		testurl.ColonSeparatedKey(), inv.MethodName(), secret, current)
+	s := Sign(requestString, secret)
+	assert.False(t, IsEmpty(signature, false))
+	assert.Equal(t, s, signature)
+}
diff --git a/filter/filter_impl/auth/provider_auth.go b/filter/filter_impl/auth/provider_auth.go
new file mode 100644
index 0000000000000000000000000000000000000000..90804934f6b01a61f021f61f4ee549d744ccee72
--- /dev/null
+++ b/filter/filter_impl/auth/provider_auth.go
@@ -0,0 +1,43 @@
+package auth
+
+import (
+	"context"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/filter"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+// ProviderAuthFilter
+// This filter is used to verify the correctness of the signature on provider side
+type ProviderAuthFilter struct {
+}
+
+func init() {
+	extension.SetFilter(constant.PROVIDER_AUTH_FILTER, getProviderAuthFilter)
+}
+
+func (paf *ProviderAuthFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	logger.Infof("invoking providerAuth filter.")
+	url := invoker.GetUrl()
+
+	err := doAuthWork(&url, func(authenticator filter.Authenticator) error {
+		return authenticator.Authenticate(invocation, &url)
+	})
+	if err != nil {
+		logger.Infof("auth the request: %v occur exception, cause: %s", invocation, err.Error())
+		return &protocol.RPCResult{
+			Err: err,
+		}
+	}
+
+	return invoker.Invoke(ctx, invocation)
+}
+
+func (paf *ProviderAuthFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	return result
+}
+func getProviderAuthFilter() filter.Filter {
+	return &ProviderAuthFilter{}
+}
diff --git a/filter/filter_impl/auth/provider_auth_test.go b/filter/filter_impl/auth/provider_auth_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..88d6423458d5534f18da4316ffe1bca0b374e43c
--- /dev/null
+++ b/filter/filter_impl/auth/provider_auth_test.go
@@ -0,0 +1,57 @@
+package auth
+
+import (
+	"context"
+	"strconv"
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/protocol/mock"
+)
+
+func TestProviderAuthFilter_Invoke(t *testing.T) {
+	secret := "dubbo-sk"
+	access := "dubbo-ak"
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0")
+	url.SetParam(constant.ACCESS_KEY_ID_KEY, access)
+	url.SetParam(constant.SECRET_ACCESS_KEY_KEY, secret)
+	parmas := []interface{}{
+		"OK",
+		struct {
+			Name string
+			Id   int64
+		}{"YUYU", 1},
+	}
+	inv := invocation.NewRPCInvocation("test", parmas, nil)
+	requestTime := strconv.Itoa(int(time.Now().Unix() * 1000))
+	signature, _ := getSignature(&url, inv, secret, requestTime)
+
+	inv = invocation.NewRPCInvocation("test", []interface{}{"OK"}, map[string]string{
+		constant.REQUEST_SIGNATURE_KEY: signature,
+		constant.CONSUMER:              "test",
+		constant.REQUEST_TIMESTAMP_KEY: requestTime,
+		constant.AK_KEY:                access,
+	})
+	ctrl := gomock.NewController(t)
+	filter := &ProviderAuthFilter{}
+	defer ctrl.Finish()
+	invoker := mock.NewMockInvoker(ctrl)
+	result := &protocol.RPCResult{}
+	invoker.EXPECT().Invoke(inv).Return(result).Times(2)
+	invoker.EXPECT().GetUrl().Return(url).Times(2)
+	assert.Equal(t, result, filter.Invoke(context.Background(), invoker, inv))
+	url.SetParam(constant.SERVICE_AUTH_KEY, "true")
+	assert.Equal(t, result, filter.Invoke(context.Background(), invoker, inv))
+
+}
diff --git a/filter/filter_impl/auth/sign_util.go b/filter/filter_impl/auth/sign_util.go
new file mode 100644
index 0000000000000000000000000000000000000000..60698439c5abc1ff0cc555b2ceec77bf2e0e53d5
--- /dev/null
+++ b/filter/filter_impl/auth/sign_util.go
@@ -0,0 +1,55 @@
+package auth
+
+import (
+	"crypto/hmac"
+	"crypto/sha256"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"strings"
+)
+
+// Sign
+// get a signature string with given information, such as metadata or parameters
+func Sign(metadata, key string) string {
+	return doSign([]byte(metadata), key)
+}
+
+func SignWithParams(params []interface{}, metadata, key string) (string, error) {
+	if params == nil || len(params) == 0 {
+		return Sign(metadata, key), nil
+	}
+
+	data := append(params, metadata)
+	if bytes, err := toBytes(data); err != nil {
+		// TODO
+		return "", errors.New("data convert to bytes failed")
+	} else {
+		return doSign(bytes, key), nil
+	}
+}
+
+func toBytes(data []interface{}) ([]byte, error) {
+	if bytes, err := json.Marshal(data); err != nil {
+		return nil, errors.New("")
+	} else {
+		return bytes, nil
+	}
+}
+
+func doSign(bytes []byte, key string) string {
+	mac := hmac.New(sha256.New, []byte(key))
+	mac.Write(bytes)
+	signature := mac.Sum(nil)
+	return base64.URLEncoding.EncodeToString(signature)
+}
+
+func IsEmpty(s string, allowSpace bool) bool {
+	if len(s) == 0 {
+		return true
+	}
+	if !allowSpace {
+		return strings.TrimSpace(s) == ""
+	}
+	return false
+}
diff --git a/filter/filter_impl/auth/sign_util_test.go b/filter/filter_impl/auth/sign_util_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..de6154e8854af99f8e862d94ee45aefcbf26b12b
--- /dev/null
+++ b/filter/filter_impl/auth/sign_util_test.go
@@ -0,0 +1,84 @@
+package auth
+
+import (
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+func TestIsEmpty(t *testing.T) {
+	type args struct {
+		s          string
+		allowSpace bool
+	}
+	tests := []struct {
+		name string
+		args args
+		want bool
+	}{
+		// TODO: Add test cases.
+		{"test1", args{s: "   ", allowSpace: false}, true},
+		{"test2", args{s: "   ", allowSpace: true}, false},
+		{"test3", args{s: "hello,dubbo", allowSpace: false}, false},
+		{"test4", args{s: "hello,dubbo", allowSpace: true}, false},
+		{"test5", args{s: "", allowSpace: true}, true},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := IsEmpty(tt.args.s, tt.args.allowSpace); got != tt.want {
+				t.Errorf("IsEmpty() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestSign(t *testing.T) {
+	metadata := "com.ikurento.user.UserProvider::sayHi"
+	key := "key"
+	signature := Sign(metadata, key)
+	assert.NotNil(t, signature)
+
+}
+
+func TestSignWithParams(t *testing.T) {
+	metadata := "com.ikurento.user.UserProvider::sayHi"
+	key := "key"
+	params := []interface{}{
+		"a", 1, struct {
+			Name string
+			Id   int64
+		}{"YuYu", 1},
+	}
+	signature, _ := SignWithParams(params, metadata, key)
+	assert.False(t, IsEmpty(signature, false))
+}
+
+func Test_doSign(t *testing.T) {
+	sign := doSign([]byte("DubboGo"), "key")
+	sign1 := doSign([]byte("DubboGo"), "key")
+	sign2 := doSign([]byte("DubboGo"), "key2")
+	assert.NotNil(t, sign)
+	assert.Equal(t, sign1, sign)
+	assert.NotEqual(t, sign1, sign2)
+}
+
+func Test_toBytes(t *testing.T) {
+	params := []interface{}{
+		"a", 1, struct {
+			Name string
+			Id   int64
+		}{"YuYu", 1},
+	}
+	params2 := []interface{}{
+		"a", 1, struct {
+			Name string
+			Id   int64
+		}{"YuYu", 1},
+	}
+	jsonBytes, _ := toBytes(params)
+	jsonBytes2, _ := toBytes(params2)
+	assert.NotNil(t, jsonBytes)
+	assert.Equal(t, jsonBytes, jsonBytes2)
+}
diff --git a/filter/impl/echo_filter.go b/filter/filter_impl/echo_filter.go
similarity index 79%
rename from filter/impl/echo_filter.go
rename to filter/filter_impl/echo_filter.go
index 18e42c8cb2b15acb27573c5e24f11a8b69e0d496..a12800a21a8ebe4545b4a8b5bd0f8a30c1462105 100644
--- a/filter/impl/echo_filter.go
+++ b/filter/filter_impl/echo_filter.go
@@ -15,7 +15,11 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
+
+import (
+	"context"
+)
 
 import (
 	"github.com/apache/dubbo-go/common/constant"
@@ -26,6 +30,7 @@ import (
 )
 
 const (
+	// ECHO echo module name
 	ECHO = "echo"
 )
 
@@ -33,12 +38,14 @@ func init() {
 	extension.SetFilter(ECHO, GetFilter)
 }
 
+// EchoFilter
 // RPCService need a Echo method in consumer, if you want to use EchoFilter
 // eg:
 //		Echo func(ctx context.Context, arg interface{}, rsp *Xxx) error
 type EchoFilter struct{}
 
-func (ef *EchoFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// Invoke ...
+func (ef *EchoFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	logger.Infof("invoking echo filter.")
 	logger.Debugf("%v,%v", invocation.MethodName(), len(invocation.Arguments()))
 	if invocation.MethodName() == constant.ECHO && len(invocation.Arguments()) == 1 {
@@ -48,13 +55,17 @@ func (ef *EchoFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invoc
 		}
 	}
 
-	return invoker.Invoke(invocation)
+	return invoker.Invoke(ctx, invocation)
 }
 
-func (ef *EchoFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// OnResponse ...
+func (ef *EchoFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker,
+	_ protocol.Invocation) protocol.Result {
+
 	return result
 }
 
+// GetFilter ...
 func GetFilter() filter.Filter {
 	return &EchoFilter{}
 }
diff --git a/filter/impl/echo_filter_test.go b/filter/filter_impl/echo_filter_test.go
similarity index 77%
rename from filter/impl/echo_filter_test.go
rename to filter/filter_impl/echo_filter_test.go
index e2e592974701ad18c5b01e884485c022ee2320b8..fc09bdce696c6be3c9e11d0ac864b187d1d85cde 100644
--- a/filter/impl/echo_filter_test.go
+++ b/filter/filter_impl/echo_filter_test.go
@@ -15,9 +15,10 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
 import (
+	"context"
 	"testing"
 )
 
@@ -33,12 +34,10 @@ import (
 
 func TestEchoFilter_Invoke(t *testing.T) {
 	filter := GetFilter()
-	result := filter.Invoke(protocol.NewBaseInvoker(common.URL{}),
-		invocation.NewRPCInvocation("$echo", []interface{}{"OK"}, nil))
+	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(common.URL{}), invocation.NewRPCInvocation("$echo", []interface{}{"OK"}, nil))
 	assert.Equal(t, "OK", result.Result())
 
-	result = filter.Invoke(protocol.NewBaseInvoker(common.URL{}),
-		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, nil))
+	result = filter.Invoke(context.Background(), protocol.NewBaseInvoker(common.URL{}), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, nil))
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 }
diff --git a/filter/impl/execute_limit_filter.go b/filter/filter_impl/execute_limit_filter.go
similarity index 78%
rename from filter/impl/execute_limit_filter.go
rename to filter/filter_impl/execute_limit_filter.go
index 156af1b140283dd76c4867ca26e9b42ce8eb25c0..434c378045456eb13317e0a48630ebd33f244c05 100644
--- a/filter/impl/execute_limit_filter.go
+++ b/filter/filter_impl/execute_limit_filter.go
@@ -15,9 +15,10 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
 import (
+	"context"
 	"strconv"
 	"sync"
 	"sync/atomic"
@@ -32,17 +33,20 @@ import (
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/filter"
-	_ "github.com/apache/dubbo-go/filter/common/impl"
+	_ "github.com/apache/dubbo-go/filter/handler"
 	"github.com/apache/dubbo-go/protocol"
 )
 
-const name = "execute"
+const (
+	name = "execute"
+)
 
 func init() {
 	extension.SetFilter(name, GetExecuteLimitFilter)
 }
 
 /**
+ * ExecuteLimitFilter
  * The filter will limit the number of in-progress request and it's thread-safe.
  * example:
  * "UserProvider":
@@ -71,23 +75,25 @@ type ExecuteLimitFilter struct {
 	executeState *concurrent.Map
 }
 
+// ExecuteState ...
 type ExecuteState struct {
 	concurrentCount int64
 }
 
-func (ef *ExecuteLimitFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// Invoke ...
+func (ef *ExecuteLimitFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	methodConfigPrefix := "methods." + invocation.MethodName() + "."
-	url := invoker.GetUrl()
-	limitTarget := url.ServiceKey()
+	ivkURL := invoker.GetUrl()
+	limitTarget := ivkURL.ServiceKey()
 	limitRateConfig := constant.DEFAULT_EXECUTE_LIMIT
 
-	methodLevelConfig := url.GetParam(methodConfigPrefix+constant.EXECUTE_LIMIT_KEY, "")
+	methodLevelConfig := ivkURL.GetParam(methodConfigPrefix+constant.EXECUTE_LIMIT_KEY, "")
 	if len(methodLevelConfig) > 0 {
 		// we have the method-level configuration
 		limitTarget = limitTarget + "#" + invocation.MethodName()
 		limitRateConfig = methodLevelConfig
 	} else {
-		limitRateConfig = url.GetParam(constant.EXECUTE_LIMIT_KEY, constant.DEFAULT_EXECUTE_LIMIT)
+		limitRateConfig = ivkURL.GetParam(constant.EXECUTE_LIMIT_KEY, constant.DEFAULT_EXECUTE_LIMIT)
 	}
 
 	limitRate, err := strconv.ParseInt(limitRateConfig, 0, 0)
@@ -97,7 +103,7 @@ func (ef *ExecuteLimitFilter) Invoke(invoker protocol.Invoker, invocation protoc
 	}
 
 	if limitRate < 0 {
-		return invoker.Invoke(invocation)
+		return invoker.Invoke(ctx, invocation)
 	}
 
 	state, _ := ef.executeState.LoadOrStore(limitTarget, &ExecuteState{
@@ -107,16 +113,17 @@ func (ef *ExecuteLimitFilter) Invoke(invoker protocol.Invoker, invocation protoc
 	concurrentCount := state.(*ExecuteState).increase()
 	defer state.(*ExecuteState).decrease()
 	if concurrentCount > limitRate {
-		logger.Errorf("The invocation was rejected due to over the execute limitation, url: %s ", url.String())
-		rejectedHandlerConfig := url.GetParam(methodConfigPrefix+constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY,
-			url.GetParam(constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY, constant.DEFAULT_KEY))
-		return extension.GetRejectedExecutionHandler(rejectedHandlerConfig).RejectedExecution(url, invocation)
+		logger.Errorf("The invocation was rejected due to over the execute limitation, url: %s ", ivkURL.String())
+		rejectedHandlerConfig := ivkURL.GetParam(methodConfigPrefix+constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY,
+			ivkURL.GetParam(constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY, constant.DEFAULT_KEY))
+		return extension.GetRejectedExecutionHandler(rejectedHandlerConfig).RejectedExecution(ivkURL, invocation)
 	}
 
-	return invoker.Invoke(invocation)
+	return invoker.Invoke(ctx, invocation)
 }
 
-func (ef *ExecuteLimitFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// OnResponse ...
+func (ef *ExecuteLimitFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker, _ protocol.Invocation) protocol.Result {
 	return result
 }
 
@@ -131,6 +138,7 @@ func (state *ExecuteState) decrease() {
 var executeLimitOnce sync.Once
 var executeLimitFilter *ExecuteLimitFilter
 
+// GetExecuteLimitFilter ...
 func GetExecuteLimitFilter() filter.Filter {
 	executeLimitOnce.Do(func() {
 		executeLimitFilter = &ExecuteLimitFilter{
diff --git a/filter/impl/execute_limit_filter_test.go b/filter/filter_impl/execute_limit_filter_test.go
similarity index 88%
rename from filter/impl/execute_limit_filter_test.go
rename to filter/filter_impl/execute_limit_filter_test.go
index 5d729c0e6a1205902856eccfa6aa96b0bee0e790..ae8641f2db0b98b59f9939cfc85f3ad096b1bc7f 100644
--- a/filter/impl/execute_limit_filter_test.go
+++ b/filter/filter_impl/execute_limit_filter_test.go
@@ -15,9 +15,10 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
 import (
+	"context"
 	"net/url"
 	"testing"
 )
@@ -43,7 +44,7 @@ func TestExecuteLimitFilter_Invoke_Ignored(t *testing.T) {
 
 	limitFilter := GetExecuteLimitFilter()
 
-	result := limitFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), invoc)
+	result := limitFilter.Invoke(context.Background(), protocol.NewBaseInvoker(*invokeUrl), invoc)
 	assert.NotNil(t, result)
 	assert.Nil(t, result.Error())
 }
@@ -60,7 +61,7 @@ func TestExecuteLimitFilter_Invoke_Configure_Error(t *testing.T) {
 
 	limitFilter := GetExecuteLimitFilter()
 
-	result := limitFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), invoc)
+	result := limitFilter.Invoke(context.Background(), protocol.NewBaseInvoker(*invokeUrl), invoc)
 	assert.NotNil(t, result)
 	assert.Nil(t, result.Error())
 }
@@ -77,7 +78,7 @@ func TestExecuteLimitFilter_Invoke(t *testing.T) {
 
 	limitFilter := GetExecuteLimitFilter()
 
-	result := limitFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), invoc)
+	result := limitFilter.Invoke(context.Background(), protocol.NewBaseInvoker(*invokeUrl), invoc)
 	assert.NotNil(t, result)
 	assert.Nil(t, result.Error())
 }
diff --git a/filter/impl/generic_filter.go b/filter/filter_impl/generic_filter.go
similarity index 80%
rename from filter/impl/generic_filter.go
rename to filter/filter_impl/generic_filter.go
index 35aadb11a444bda56109e238b17267f71ec2606b..e8ff2679b0294d6519aecd1cc1fe37bdeab89e46 100644
--- a/filter/impl/generic_filter.go
+++ b/filter/filter_impl/generic_filter.go
@@ -15,15 +15,18 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
 import (
+	"context"
 	"reflect"
 	"strings"
 )
+
 import (
 	hessian "github.com/apache/dubbo-go-hessian2"
 )
+
 import (
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
@@ -33,6 +36,8 @@ import (
 )
 
 const (
+	// GENERIC
+	//generic module name
 	GENERIC = "generic"
 )
 
@@ -42,35 +47,39 @@ func init() {
 
 //  when do a generic invoke, struct need to be map
 
+// GenericFilter ...
 type GenericFilter struct{}
 
-func (ef *GenericFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// Invoke ...
+func (ef *GenericFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 {
 		oldArguments := invocation.Arguments()
-		var newParams []hessian.Object
+
 		if oldParams, ok := oldArguments[2].([]interface{}); ok {
+			newParams := make([]hessian.Object, 0, len(oldParams))
 			for i := range oldParams {
 				newParams = append(newParams, hessian.Object(struct2MapAll(oldParams[i])))
 			}
-		} else {
-			return invoker.Invoke(invocation)
-		}
-		newArguments := []interface{}{
-			oldArguments[0],
-			oldArguments[1],
-			newParams,
+			newArguments := []interface{}{
+				oldArguments[0],
+				oldArguments[1],
+				newParams,
+			}
+			newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments())
+			newInvocation.SetReply(invocation.Reply())
+			return invoker.Invoke(ctx, newInvocation)
 		}
-		newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments())
-		newInvocation.SetReply(invocation.Reply())
-		return invoker.Invoke(newInvocation)
 	}
-	return invoker.Invoke(invocation)
+	return invoker.Invoke(ctx, invocation)
 }
 
-func (ef *GenericFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// OnResponse ...
+func (ef *GenericFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker,
+	_ protocol.Invocation) protocol.Result {
 	return result
 }
 
+// GetGenericFilter ...
 func GetGenericFilter() filter.Filter {
 	return &GenericFilter{}
 }
diff --git a/filter/impl/generic_filter_test.go b/filter/filter_impl/generic_filter_test.go
similarity index 99%
rename from filter/impl/generic_filter_test.go
rename to filter/filter_impl/generic_filter_test.go
index 9797c40df1f57017241675013620a53320e475ad..22948353fc16a99696a85489ce5df7dc9b18a7ba 100644
--- a/filter/impl/generic_filter_test.go
+++ b/filter/filter_impl/generic_filter_test.go
@@ -15,12 +15,13 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
 import (
 	"reflect"
 	"testing"
 )
+
 import (
 	"github.com/stretchr/testify/assert"
 )
diff --git a/filter/filter_impl/generic_service_filter.go b/filter/filter_impl/generic_service_filter.go
new file mode 100644
index 0000000000000000000000000000000000000000..6272df6b39b0c18a77721f3a8c9e92618133aa6c
--- /dev/null
+++ b/filter/filter_impl/generic_service_filter.go
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package filter_impl
+
+import (
+	"context"
+	"reflect"
+	"strings"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+	"github.com/mitchellh/mapstructure"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/filter"
+	"github.com/apache/dubbo-go/protocol"
+	invocation2 "github.com/apache/dubbo-go/protocol/invocation"
+)
+
+const (
+	// GENERIC_SERVICE ...
+	GENERIC_SERVICE = "generic_service"
+	// GENERIC_SERIALIZATION_DEFAULT ...
+	GENERIC_SERIALIZATION_DEFAULT = "true"
+)
+
+func init() {
+	extension.SetFilter(GENERIC_SERVICE, GetGenericServiceFilter)
+}
+
+// GenericServiceFilter ...
+type GenericServiceFilter struct{}
+
+// Invoke ...
+func (ef *GenericServiceFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	logger.Infof("invoking generic service filter.")
+	logger.Debugf("generic service filter methodName:%v,args:%v", invocation.MethodName(), len(invocation.Arguments()))
+
+	if invocation.MethodName() != constant.GENERIC || len(invocation.Arguments()) != 3 {
+		return invoker.Invoke(ctx, invocation)
+	}
+
+	var (
+		ok         bool
+		err        error
+		methodName string
+		newParams  []interface{}
+		genericKey string
+		argsType   []reflect.Type
+		oldParams  []hessian.Object
+	)
+
+	url := invoker.GetUrl()
+	methodName = invocation.Arguments()[0].(string)
+	// get service
+	svc := common.ServiceMap.GetService(url.Protocol, strings.TrimPrefix(url.Path, "/"))
+	// get method
+	method := svc.Method()[methodName]
+	if method == nil {
+		logger.Errorf("[Generic Service Filter] Don't have this method: %s", methodName)
+		return &protocol.RPCResult{}
+	}
+	argsType = method.ArgsType()
+	genericKey = invocation.AttachmentsByKey(constant.GENERIC_KEY, GENERIC_SERIALIZATION_DEFAULT)
+	if genericKey == GENERIC_SERIALIZATION_DEFAULT {
+		oldParams, ok = invocation.Arguments()[2].([]hessian.Object)
+	} else {
+		logger.Errorf("[Generic Service Filter] Don't support this generic: %s", genericKey)
+		return &protocol.RPCResult{}
+	}
+	if !ok {
+		logger.Errorf("[Generic Service Filter] wrong serialization")
+		return &protocol.RPCResult{}
+	}
+	if len(oldParams) != len(argsType) {
+		logger.Errorf("[Generic Service Filter] method:%s invocation arguments number was wrong", methodName)
+		return &protocol.RPCResult{}
+	}
+	// oldParams convert to newParams
+	newParams = make([]interface{}, len(oldParams))
+	for i := range argsType {
+		newParam := reflect.New(argsType[i]).Interface()
+		err = mapstructure.Decode(oldParams[i], newParam)
+		newParam = reflect.ValueOf(newParam).Elem().Interface()
+		if err != nil {
+			logger.Errorf("[Generic Service Filter] decode arguments map to struct wrong: error{%v}", perrors.WithStack(err))
+			return &protocol.RPCResult{}
+		}
+		newParams[i] = newParam
+	}
+	newInvocation := invocation2.NewRPCInvocation(methodName, newParams, invocation.Attachments())
+	newInvocation.SetReply(invocation.Reply())
+	return invoker.Invoke(ctx, newInvocation)
+}
+
+// OnResponse ...
+func (ef *GenericServiceFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 && result.Result() != nil {
+		v := reflect.ValueOf(result.Result())
+		if v.Kind() == reflect.Ptr {
+			v = v.Elem()
+		}
+		result.SetResult(struct2MapAll(v.Interface()))
+	}
+	return result
+}
+
+// GetGenericServiceFilter ...
+func GetGenericServiceFilter() filter.Filter {
+	return &GenericServiceFilter{}
+}
diff --git a/filter/filter_impl/generic_service_filter_test.go b/filter/filter_impl/generic_service_filter_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..37c6af7450a75449fce51182684be2f619eda9d8
--- /dev/null
+++ b/filter/filter_impl/generic_service_filter_test.go
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package filter_impl
+
+import (
+	"context"
+	"errors"
+	"reflect"
+	"testing"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/proxy/proxy_factory"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+type TestStruct struct {
+	AaAa string
+	BaBa string `m:"baBa"`
+	XxYy struct {
+		xxXx string `m:"xxXx"`
+		Xx   string `m:"xx"`
+	} `m:"xxYy"`
+}
+
+func (c *TestStruct) JavaClassName() string {
+	return "com.test.testStruct"
+}
+
+type TestService struct{}
+
+// MethodOne ...
+func (ts *TestService) MethodOne(_ context.Context, test1 *TestStruct, test2 []TestStruct,
+	test3 interface{}, test4 []interface{}, test5 *string) (*TestStruct, error) {
+	if test1 == nil {
+		return nil, errors.New("param test1 is nil")
+	}
+	if test2 == nil {
+		return nil, errors.New("param test2 is nil")
+	}
+	if test3 == nil {
+		return nil, errors.New("param test3 is nil")
+	}
+	if test4 == nil {
+		return nil, errors.New("param test4 is nil")
+	}
+	if test5 == nil {
+		return nil, errors.New("param test5 is nil")
+	}
+	return &TestStruct{}, nil
+}
+
+// Reference ...
+func (*TestService) Reference() string {
+	return "com.test.Path"
+}
+
+func TestGenericServiceFilter_Invoke(t *testing.T) {
+	hessian.RegisterPOJO(&TestStruct{})
+	methodName := "$invoke"
+	m := make(map[string]interface{})
+	m["AaAa"] = "nihao"
+	x := make(map[string]interface{})
+	x["xxXX"] = "nihaoxxx"
+	m["XxYy"] = x
+	aurguments := []interface{}{
+		"MethodOne",
+		nil,
+		[]hessian.Object{
+			hessian.Object(m),
+			hessian.Object(append(make([]map[string]interface{}, 1), m)),
+			hessian.Object("111"),
+			hessian.Object(append(make([]map[string]interface{}, 1), m)),
+			hessian.Object("222")},
+	}
+	s := &TestService{}
+	_, _ = common.ServiceMap.Register("testprotocol", s)
+	rpcInvocation := invocation.NewRPCInvocation(methodName, aurguments, nil)
+	filter := GetGenericServiceFilter()
+	url, _ := common.NewURL("testprotocol://127.0.0.1:20000/com.test.Path")
+	result := filter.Invoke(context.Background(), &proxy_factory.ProxyInvoker{BaseInvoker: *protocol.NewBaseInvoker(url)}, rpcInvocation)
+	assert.NotNil(t, result)
+	assert.Nil(t, result.Error())
+}
+
+func TestGenericServiceFilter_ResponseTestStruct(t *testing.T) {
+	ts := &TestStruct{
+		AaAa: "aaa",
+		BaBa: "bbb",
+		XxYy: struct {
+			xxXx string `m:"xxXx"`
+			Xx   string `m:"xx"`
+		}{},
+	}
+	result := &protocol.RPCResult{
+		Rest: ts,
+	}
+	aurguments := []interface{}{
+		"MethodOne",
+		nil,
+		[]hessian.Object{nil},
+	}
+	filter := GetGenericServiceFilter()
+	methodName := "$invoke"
+	rpcInvocation := invocation.NewRPCInvocation(methodName, aurguments, nil)
+	r := filter.OnResponse(nil, result, nil, rpcInvocation)
+	assert.NotNil(t, r.Result())
+	assert.Equal(t, reflect.ValueOf(r.Result()).Kind(), reflect.Map)
+}
+
+func TestGenericServiceFilter_ResponseString(t *testing.T) {
+	str := "111"
+	result := &protocol.RPCResult{
+		Rest: str,
+	}
+	aurguments := []interface{}{
+		"MethodOne",
+		nil,
+		[]hessian.Object{nil},
+	}
+	filter := GetGenericServiceFilter()
+	methodName := "$invoke"
+	rpcInvocation := invocation.NewRPCInvocation(methodName, aurguments, nil)
+	r := filter.OnResponse(nil, result, nil, rpcInvocation)
+	assert.NotNil(t, r.Result())
+	assert.Equal(t, reflect.ValueOf(r.Result()).Kind(), reflect.String)
+}
diff --git a/filter/impl/graceful_shutdown_filter.go b/filter/filter_impl/graceful_shutdown_filter.go
similarity index 85%
rename from filter/impl/graceful_shutdown_filter.go
rename to filter/filter_impl/graceful_shutdown_filter.go
index b912ea88e4ba4741b7d7fe36b8bbd3ba158abe63..95e625b2d56895a4d57823e4e0e2e7d1d5e90a08 100644
--- a/filter/impl/graceful_shutdown_filter.go
+++ b/filter/filter_impl/graceful_shutdown_filter.go
@@ -15,9 +15,10 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
 import (
+	"context"
 	"sync/atomic"
 )
 
@@ -27,7 +28,6 @@ import (
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/config"
 	"github.com/apache/dubbo-go/filter"
-	"github.com/apache/dubbo-go/filter/common"
 	"github.com/apache/dubbo-go/protocol"
 )
 
@@ -53,16 +53,16 @@ type gracefulShutdownFilter struct {
 	shutdownConfig *config.ShutdownConfig
 }
 
-func (gf *gracefulShutdownFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+func (gf *gracefulShutdownFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	if gf.rejectNewRequest() {
 		logger.Info("The application is closing, new request will be rejected.")
 		return gf.getRejectHandler().RejectedExecution(invoker.GetUrl(), invocation)
 	}
 	atomic.AddInt32(&gf.activeCount, 1)
-	return invoker.Invoke(invocation)
+	return invoker.Invoke(ctx, invocation)
 }
 
-func (gf *gracefulShutdownFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+func (gf *gracefulShutdownFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	atomic.AddInt32(&gf.activeCount, -1)
 	// although this isn't thread safe, it won't be a problem if the gf.rejectNewRequest() is true.
 	if gf.shutdownConfig != nil && gf.activeCount <= 0 {
@@ -78,7 +78,7 @@ func (gf *gracefulShutdownFilter) rejectNewRequest() bool {
 	return gf.shutdownConfig.RejectRequest
 }
 
-func (gf *gracefulShutdownFilter) getRejectHandler() common.RejectedExecutionHandler {
+func (gf *gracefulShutdownFilter) getRejectHandler() filter.RejectedExecutionHandler {
 	handler := constant.DEFAULT_KEY
 	if gf.shutdownConfig != nil && len(gf.shutdownConfig.RejectRequestHandler) > 0 {
 		handler = gf.shutdownConfig.RejectRequestHandler
diff --git a/filter/impl/graceful_shutdown_filter_test.go b/filter/filter_impl/graceful_shutdown_filter_test.go
similarity index 82%
rename from filter/impl/graceful_shutdown_filter_test.go
rename to filter/filter_impl/graceful_shutdown_filter_test.go
index 21da167ea0f201ea357c51cab0ecb4f8ebec0957..4c670933e3dcec29ad9ae7bfef250b4236ae7c54 100644
--- a/filter/impl/graceful_shutdown_filter_test.go
+++ b/filter/filter_impl/graceful_shutdown_filter_test.go
@@ -15,9 +15,10 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
 import (
+	"context"
 	"net/url"
 	"testing"
 )
@@ -31,8 +32,8 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/config"
-	filterCommon "github.com/apache/dubbo-go/filter/common"
-	"github.com/apache/dubbo-go/filter/common/impl"
+	"github.com/apache/dubbo-go/filter"
+	common2 "github.com/apache/dubbo-go/filter/handler"
 	"github.com/apache/dubbo-go/protocol"
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
@@ -53,7 +54,7 @@ func TestGenericFilter_Invoke(t *testing.T) {
 	assert.Equal(t, extension.GetRejectedExecutionHandler(constant.DEFAULT_KEY),
 		shutdownFilter.getRejectHandler())
 
-	result := shutdownFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), invoc)
+	result := shutdownFilter.Invoke(context.Background(), protocol.NewBaseInvoker(*invokeUrl), invoc)
 	assert.NotNil(t, result)
 	assert.Nil(t, result.Error())
 
@@ -64,10 +65,10 @@ func TestGenericFilter_Invoke(t *testing.T) {
 	shutdownFilter.shutdownConfig = providerConfig.ShutdownConfig
 
 	assert.True(t, shutdownFilter.rejectNewRequest())
-	result = shutdownFilter.OnResponse(nil, protocol.NewBaseInvoker(*invokeUrl), invoc)
+	result = shutdownFilter.OnResponse(nil, nil, protocol.NewBaseInvoker(*invokeUrl), invoc)
 
-	rejectHandler := &impl.OnlyLogRejectedExecutionHandler{}
-	extension.SetRejectedExecutionHandler("mock", func() filterCommon.RejectedExecutionHandler {
+	rejectHandler := &common2.OnlyLogRejectedExecutionHandler{}
+	extension.SetRejectedExecutionHandler("mock", func() filter.RejectedExecutionHandler {
 		return rejectHandler
 	})
 	assert.True(t, providerConfig.ShutdownConfig.RequestsFinished)
diff --git a/filter/impl/hystrix_filter.go b/filter/filter_impl/hystrix_filter.go
similarity index 91%
rename from filter/impl/hystrix_filter.go
rename to filter/filter_impl/hystrix_filter.go
index 3fd9f87168616b69d5ec72460767890d6956c154..9fd97b57b677c9aa8ec492151df9aace6dc78b62 100644
--- a/filter/impl/hystrix_filter.go
+++ b/filter/filter_impl/hystrix_filter.go
@@ -14,9 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package impl
+
+package filter_impl
 
 import (
+	"context"
 	"fmt"
 	"regexp"
 	"sync"
@@ -35,9 +37,12 @@ import (
 )
 
 const (
+	// HYSTRIX_CONSUMER ...
 	HYSTRIX_CONSUMER = "hystrix_consumer"
+	// HYSTRIX_PROVIDER ...
 	HYSTRIX_PROVIDER = "hystrix_provider"
-	HYSTRIX          = "hystrix"
+	// HYSTRIX ...
+	HYSTRIX = "hystrix"
 )
 
 var (
@@ -57,6 +62,7 @@ func init() {
 	extension.SetFilter(HYSTRIX_PROVIDER, GetHystrixFilterProvider)
 }
 
+// HystrixFilterError ...
 type HystrixFilterError struct {
 	err           error
 	failByHystrix bool
@@ -66,9 +72,12 @@ func (hfError *HystrixFilterError) Error() string {
 	return hfError.err.Error()
 }
 
+// FailByHystrix ...
 func (hfError *HystrixFilterError) FailByHystrix() bool {
 	return hfError.failByHystrix
 }
+
+// NewHystrixFilterError ...
 func NewHystrixFilterError(err error, failByHystrix bool) error {
 	return &HystrixFilterError{
 		err:           err,
@@ -76,14 +85,15 @@ func NewHystrixFilterError(err error, failByHystrix bool) error {
 	}
 }
 
+// HystrixFilter ...
 type HystrixFilter struct {
 	COrP     bool //true for consumer
 	res      map[string][]*regexp.Regexp
 	ifNewMap sync.Map
 }
 
-func (hf *HystrixFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
-
+// Invoke ...
+func (hf *HystrixFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	cmdName := fmt.Sprintf("%s&method=%s", invoker.GetUrl().Key(), invocation.MethodName())
 
 	// Do the configuration if the circuit breaker is created for the first time
@@ -115,12 +125,12 @@ func (hf *HystrixFilter) Invoke(invoker protocol.Invoker, invocation protocol.In
 	configLoadMutex.RUnlock()
 	if err != nil {
 		logger.Errorf("[Hystrix Filter]Errors occurred getting circuit for %s , will invoke without hystrix, error is: ", cmdName, err)
-		return invoker.Invoke(invocation)
+		return invoker.Invoke(ctx, invocation)
 	}
 	logger.Infof("[Hystrix Filter]Using hystrix filter: %s", cmdName)
 	var result protocol.Result
 	_ = hystrix.Do(cmdName, func() error {
-		result = invoker.Invoke(invocation)
+		result = invoker.Invoke(ctx, invocation)
 		err := result.Error()
 		if err != nil {
 			result.SetError(NewHystrixFilterError(err, false))
@@ -144,9 +154,12 @@ func (hf *HystrixFilter) Invoke(invoker protocol.Invoker, invocation protocol.In
 	return result
 }
 
-func (hf *HystrixFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// OnResponse ...
+func (hf *HystrixFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	return result
 }
+
+// GetHystrixFilterConsumer ...
 func GetHystrixFilterConsumer() filter.Filter {
 	//When first called, load the config in
 	consumerConfigOnce.Do(func() {
@@ -157,6 +170,7 @@ func GetHystrixFilterConsumer() filter.Filter {
 	return &HystrixFilter{COrP: true}
 }
 
+// GetHystrixFilterProvider ...
 func GetHystrixFilterProvider() filter.Filter {
 	providerConfigOnce.Do(func() {
 		if err := initHystrixConfigProvider(); err != nil {
@@ -215,6 +229,7 @@ func initHystrixConfigConsumer() error {
 	}
 	return nil
 }
+
 func initHystrixConfigProvider() error {
 	if config.GetProviderConfig().FilterConf == nil {
 		return perrors.Errorf("no config for hystrix")
@@ -241,6 +256,7 @@ func initHystrixConfigProvider() error {
 //	return initHystrixConfig()
 //}
 
+// CommandConfigWithError ...
 type CommandConfigWithError struct {
 	Timeout                int      `yaml:"timeout"`
 	MaxConcurrentRequests  int      `yaml:"max_concurrent_requests"`
@@ -258,11 +274,14 @@ type CommandConfigWithError struct {
 //- ErrorPercentThreshold: it causes circuits to open once the rolling measure of errors exceeds this percent of requests
 //See hystrix doc
 
+// HystrixFilterConfig ...
 type HystrixFilterConfig struct {
 	Configs  map[string]*CommandConfigWithError
 	Default  string
 	Services map[string]ServiceHystrixConfig
 }
+
+// ServiceHystrixConfig ...
 type ServiceHystrixConfig struct {
 	ServiceConfig string `yaml:"service_config"`
 	Methods       map[string]string
diff --git a/filter/impl/hystrix_filter_test.go b/filter/filter_impl/hystrix_filter_test.go
similarity index 90%
rename from filter/impl/hystrix_filter_test.go
rename to filter/filter_impl/hystrix_filter_test.go
index d3a5183ede25d8a325bb1c73020edddd2ffbc638..66c17d920c14e23f1562773c152e99955a48bfb9 100644
--- a/filter/impl/hystrix_filter_test.go
+++ b/filter/filter_impl/hystrix_filter_test.go
@@ -14,17 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package impl
+package filter_impl
 
 import (
+	"context"
 	"regexp"
 	"testing"
 )
+
 import (
 	"github.com/afex/hystrix-go/hystrix"
 	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
+
 import (
 	"github.com/apache/dubbo-go/protocol"
 	"github.com/apache/dubbo-go/protocol/invocation"
@@ -125,9 +128,9 @@ type testMockSuccessInvoker struct {
 	protocol.BaseInvoker
 }
 
-func (iv *testMockSuccessInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (iv *testMockSuccessInvoker) Invoke(_ context.Context, _ protocol.Invocation) protocol.Result {
 	return &protocol.RPCResult{
-		Rest: "Sucess",
+		Rest: "Success",
 		Err:  nil,
 	}
 }
@@ -136,7 +139,7 @@ type testMockFailInvoker struct {
 	protocol.BaseInvoker
 }
 
-func (iv *testMockFailInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (iv *testMockFailInvoker) Invoke(_ context.Context, _ protocol.Invocation) protocol.Result {
 	return &protocol.RPCResult{
 		Err: errors.Errorf("exception"),
 	}
@@ -144,7 +147,7 @@ func (iv *testMockFailInvoker) Invoke(invocation protocol.Invocation) protocol.R
 
 func TestHystrixFilter_Invoke_Success(t *testing.T) {
 	hf := &HystrixFilter{}
-	result := hf.Invoke(&testMockSuccessInvoker{}, &invocation.RPCInvocation{})
+	result := hf.Invoke(context.Background(), &testMockSuccessInvoker{}, &invocation.RPCInvocation{})
 	assert.NotNil(t, result)
 	assert.NoError(t, result.Error())
 	assert.NotNil(t, result.Result())
@@ -152,7 +155,7 @@ func TestHystrixFilter_Invoke_Success(t *testing.T) {
 
 func TestHystrixFilter_Invoke_Fail(t *testing.T) {
 	hf := &HystrixFilter{}
-	result := hf.Invoke(&testMockFailInvoker{}, &invocation.RPCInvocation{})
+	result := hf.Invoke(context.Background(), &testMockFailInvoker{}, &invocation.RPCInvocation{})
 	assert.NotNil(t, result)
 	assert.Error(t, result.Error())
 }
@@ -164,7 +167,7 @@ func TestHystricFilter_Invoke_CircuitBreak(t *testing.T) {
 	resChan := make(chan protocol.Result, 50)
 	for i := 0; i < 50; i++ {
 		go func() {
-			result := hf.Invoke(&testMockFailInvoker{}, &invocation.RPCInvocation{})
+			result := hf.Invoke(context.Background(), &testMockFailInvoker{}, &invocation.RPCInvocation{})
 			resChan <- result
 		}()
 	}
@@ -189,7 +192,7 @@ func TestHystricFilter_Invoke_CircuitBreak_Omit_Exception(t *testing.T) {
 	resChan := make(chan protocol.Result, 50)
 	for i := 0; i < 50; i++ {
 		go func() {
-			result := hf.Invoke(&testMockFailInvoker{}, &invocation.RPCInvocation{})
+			result := hf.Invoke(context.Background(), &testMockFailInvoker{}, &invocation.RPCInvocation{})
 			resChan <- result
 		}()
 	}
diff --git a/filter/filter_impl/metrics_filter.go b/filter/filter_impl/metrics_filter.go
new file mode 100644
index 0000000000000000000000000000000000000000..f4734172b74c8bbcdac5c9a9743acb4df5fcb6b5
--- /dev/null
+++ b/filter/filter_impl/metrics_filter.go
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package filter_impl
+
+import (
+	"context"
+	"time"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/filter"
+	"github.com/apache/dubbo-go/metrics"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+const (
+	metricFilterName = "metrics"
+)
+
+var (
+	metricFilterInstance filter.Filter
+)
+
+// must initialized before using the filter and after loading configuration
+func init() {
+	extension.SetFilter(metricFilterName, newMetricsFilter)
+}
+
+// metricFilter will calculate the invocation's duration and the report to the reporters
+// If you want to use this filter to collect the metrics,
+// Adding this into your configuration file, like:
+// filter: "metrics"
+// metrics:
+//   reporter:
+//     - "your reporter" # here you should specify the reporter, for example 'prometheus'
+// more info please take a look at dubbo-samples projects
+type metricsFilter struct {
+	reporters []metrics.Reporter
+}
+
+// Invoke collect the duration of invocation and then report the duration by using goroutine
+func (p *metricsFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	start := time.Now()
+	res := invoker.Invoke(ctx, invocation)
+	end := time.Now()
+	duration := end.Sub(start)
+	go func() {
+		for _, reporter := range p.reporters {
+			reporter.Report(ctx, invoker, invocation, duration, res)
+		}
+	}()
+	return res
+}
+
+// OnResponse do nothing and return the result
+func (p *metricsFilter) OnResponse(ctx context.Context, res protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	return res
+}
+
+// newMetricsFilter the metricsFilter is singleton.
+// it's lazy initialization
+// make sure that the configuration had been loaded before invoking this method.
+func newMetricsFilter() filter.Filter {
+	if metricFilterInstance == nil {
+		reporterNames := config.GetMetricConfig().Reporters
+		reporters := make([]metrics.Reporter, 0, len(reporterNames))
+		for _, name := range reporterNames {
+			reporters = append(reporters, extension.GetMetricReporter(name))
+		}
+		metricFilterInstance = &metricsFilter{
+			reporters: reporters,
+		}
+	}
+
+	return metricFilterInstance
+}
diff --git a/filter/filter_impl/metrics_filter_test.go b/filter/filter_impl/metrics_filter_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..709404a2af4f4df0dbf625dbbbd673e34975c0db
--- /dev/null
+++ b/filter/filter_impl/metrics_filter_test.go
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package filter_impl
+
+import (
+	"context"
+	"sync"
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/metrics"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestMetricsFilter_Invoke(t *testing.T) {
+
+	// prepare the mock reporter
+	config.GetMetricConfig().Reporters = []string{"mock"}
+	mk := &mockReporter{}
+	extension.SetMetricReporter("mock", func() metrics.Reporter {
+		return mk
+	})
+
+	instance := extension.GetFilter(metricFilterName)
+
+	url, _ := common.NewURL(
+		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" +
+			"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." +
+			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" +
+			"BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&" +
+			"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
+	invoker := protocol.NewBaseInvoker(url)
+
+	attach := make(map[string]string, 10)
+	inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach)
+
+	ctx := context.Background()
+
+	mk.On("Report", ctx, invoker, inv).Return(true, nil)
+
+	mk.wg.Add(1)
+	result := instance.Invoke(ctx, invoker, inv)
+	assert.NotNil(t, result)
+	mk.AssertNotCalled(t, "Report", 1)
+	// it will do nothing
+	result = instance.OnResponse(ctx, nil, invoker, inv)
+	assert.Nil(t, result)
+}
+
+type mockReporter struct {
+	mock.Mock
+	wg sync.WaitGroup
+}
+
+func (m *mockReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) {
+	m.Called(ctx, invoker, invocation)
+	m.wg.Done()
+}
diff --git a/filter/impl/token_filter.go b/filter/filter_impl/token_filter.go
similarity index 76%
rename from filter/impl/token_filter.go
rename to filter/filter_impl/token_filter.go
index d10dff5b761d0fbe40ff3a14a93ee8962d000e02..4605416c40a616361868c313881ae784257e6742 100644
--- a/filter/impl/token_filter.go
+++ b/filter/filter_impl/token_filter.go
@@ -15,9 +15,10 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package impl
+package filter_impl
 
 import (
+	"context"
 	"strings"
 )
 
@@ -33,6 +34,7 @@ import (
 )
 
 const (
+	// TOKEN ...
 	TOKEN = "token"
 )
 
@@ -40,27 +42,31 @@ func init() {
 	extension.SetFilter(TOKEN, GetTokenFilter)
 }
 
+// TokenFilter ...
 type TokenFilter struct{}
 
-func (tf *TokenFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// Invoke ...
+func (tf *TokenFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	invokerTkn := invoker.GetUrl().GetParam(constant.TOKEN_KEY, "")
 	if len(invokerTkn) > 0 {
 		attachs := invocation.Attachments()
 		remoteTkn, exist := attachs[constant.TOKEN_KEY]
 		if exist && strings.EqualFold(invokerTkn, remoteTkn) {
-			return invoker.Invoke(invocation)
+			return invoker.Invoke(ctx, invocation)
 		}
 		return &protocol.RPCResult{Err: perrors.Errorf("Invalid token! Forbid invoke remote service %v method %s ",
 			invoker, invocation.MethodName())}
 	}
 
-	return invoker.Invoke(invocation)
+	return invoker.Invoke(ctx, invocation)
 }
 
-func (tf *TokenFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// OnResponse ...
+func (tf *TokenFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	return result
 }
 
+// GetTokenFilter ...
 func GetTokenFilter() filter.Filter {
 	return &TokenFilter{}
 }
diff --git a/filter/impl/token_filter_test.go b/filter/filter_impl/token_filter_test.go
similarity index 77%
rename from filter/impl/token_filter_test.go
rename to filter/filter_impl/token_filter_test.go
index 1473f274037699260725ff9ebb1b3d1377efb326..672082c729bc371a40573a66d13bc57a7024186b 100644
--- a/filter/impl/token_filter_test.go
+++ b/filter/filter_impl/token_filter_test.go
@@ -15,9 +15,10 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package impl
+package filter_impl
 
 import (
+	"context"
 	"net/url"
 	"testing"
 )
@@ -41,8 +42,10 @@ func TestTokenFilter_Invoke(t *testing.T) {
 		common.WithParamsValue(constant.TOKEN_KEY, "ori_key"))
 	attch := make(map[string]string, 0)
 	attch[constant.TOKEN_KEY] = "ori_key"
-	result := filter.Invoke(protocol.NewBaseInvoker(*url),
-		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := filter.Invoke(context.Background(),
+		protocol.NewBaseInvoker(*url),
+		invocation.NewRPCInvocation("MethodName",
+			[]interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 }
@@ -53,8 +56,7 @@ func TestTokenFilter_InvokeEmptyToken(t *testing.T) {
 	url := common.URL{}
 	attch := make(map[string]string, 0)
 	attch[constant.TOKEN_KEY] = "ori_key"
-	result := filter.Invoke(protocol.NewBaseInvoker(url),
-		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(url), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 }
@@ -66,8 +68,7 @@ func TestTokenFilter_InvokeEmptyAttach(t *testing.T) {
 		common.WithParams(url.Values{}),
 		common.WithParamsValue(constant.TOKEN_KEY, "ori_key"))
 	attch := make(map[string]string, 0)
-	result := filter.Invoke(protocol.NewBaseInvoker(*url),
-		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(*url), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.NotNil(t, result.Error())
 }
 
@@ -79,7 +80,7 @@ func TestTokenFilter_InvokeNotEqual(t *testing.T) {
 		common.WithParamsValue(constant.TOKEN_KEY, "ori_key"))
 	attch := make(map[string]string, 0)
 	attch[constant.TOKEN_KEY] = "err_key"
-	result := filter.Invoke(protocol.NewBaseInvoker(*url),
-		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := filter.Invoke(context.Background(),
+		protocol.NewBaseInvoker(*url), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.NotNil(t, result.Error())
 }
diff --git a/filter/impl/tps/impl/tps_limit_fix_window_strategy.go b/filter/filter_impl/tps/tps_limit_fix_window_strategy.go
similarity index 94%
rename from filter/impl/tps/impl/tps_limit_fix_window_strategy.go
rename to filter/filter_impl/tps/tps_limit_fix_window_strategy.go
index 285ecfa658cf838cc1140ba716bd72e1976b86fe..a9c2ac15a417ffa6ff8f5b8d78d5c6a94877db30 100644
--- a/filter/impl/tps/impl/tps_limit_fix_window_strategy.go
+++ b/filter/filter_impl/tps/tps_limit_fix_window_strategy.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package impl
+package tps
 
 import (
 	"sync/atomic"
@@ -25,10 +25,11 @@ import (
 import (
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
-	"github.com/apache/dubbo-go/filter/impl/tps"
+	"github.com/apache/dubbo-go/filter"
 )
 
 const (
+	// FixedWindowKey ...
 	FixedWindowKey = "fixedWindow"
 )
 
@@ -39,6 +40,7 @@ func init() {
 }
 
 /**
+ * FixedWindowTpsLimitStrategyImpl
  * It's the same as default implementation in Java
  * It's not a thread-safe implementation.
  * It you want to use the thread-safe implementation, please use ThreadSafeFixedWindowTpsLimitStrategyImpl
@@ -63,6 +65,7 @@ type FixedWindowTpsLimitStrategyImpl struct {
 	timestamp int64
 }
 
+// IsAllowable ...
 func (impl *FixedWindowTpsLimitStrategyImpl) IsAllowable() bool {
 
 	current := time.Now().UnixNano()
@@ -79,7 +82,7 @@ func (impl *FixedWindowTpsLimitStrategyImpl) IsAllowable() bool {
 
 type fixedWindowStrategyCreator struct{}
 
-func (creator *fixedWindowStrategyCreator) Create(rate int, interval int) tps.TpsLimitStrategy {
+func (creator *fixedWindowStrategyCreator) Create(rate int, interval int) filter.TpsLimitStrategy {
 	return &FixedWindowTpsLimitStrategyImpl{
 		rate:      int32(rate),
 		interval:  int64(interval) * int64(time.Millisecond), // convert to ns
diff --git a/filter/impl/tps/impl/tps_limit_fix_window_strategy_test.go b/filter/filter_impl/tps/tps_limit_fix_window_strategy_test.go
similarity index 99%
rename from filter/impl/tps/impl/tps_limit_fix_window_strategy_test.go
rename to filter/filter_impl/tps/tps_limit_fix_window_strategy_test.go
index 7ef539ed3b2b93da5c56a05f606e75282226d1ef..5eaf2f707dcc9dd6cf325988242623dd5161c1a8 100644
--- a/filter/impl/tps/impl/tps_limit_fix_window_strategy_test.go
+++ b/filter/filter_impl/tps/tps_limit_fix_window_strategy_test.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package impl
+package tps
 
 import (
 	"testing"
diff --git a/filter/impl/tps/impl/tps_limit_sliding_window_strategy.go b/filter/filter_impl/tps/tps_limit_sliding_window_strategy.go
similarity index 94%
rename from filter/impl/tps/impl/tps_limit_sliding_window_strategy.go
rename to filter/filter_impl/tps/tps_limit_sliding_window_strategy.go
index d1a5db6e259ffa63282065f881f6cc8360c8d25b..a781cc7bfbf297d0b9cf84ca0aa9dcfbbef7e14b 100644
--- a/filter/impl/tps/impl/tps_limit_sliding_window_strategy.go
+++ b/filter/filter_impl/tps/tps_limit_sliding_window_strategy.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package impl
+package tps
 
 import (
 	"container/list"
@@ -25,7 +25,7 @@ import (
 
 import (
 	"github.com/apache/dubbo-go/common/extension"
-	"github.com/apache/dubbo-go/filter/impl/tps"
+	"github.com/apache/dubbo-go/filter"
 )
 
 func init() {
@@ -33,6 +33,7 @@ func init() {
 }
 
 /**
+ * SlidingWindowTpsLimitStrategyImpl
  * it's thread-safe.
  * "UserProvider":
  *   registry: "hangzhouzk"
@@ -53,6 +54,7 @@ type SlidingWindowTpsLimitStrategyImpl struct {
 	queue    *list.List
 }
 
+// IsAllowable ...
 func (impl *SlidingWindowTpsLimitStrategyImpl) IsAllowable() bool {
 	impl.mutex.Lock()
 	defer impl.mutex.Unlock()
@@ -82,7 +84,7 @@ func (impl *SlidingWindowTpsLimitStrategyImpl) IsAllowable() bool {
 
 type slidingWindowStrategyCreator struct{}
 
-func (creator *slidingWindowStrategyCreator) Create(rate int, interval int) tps.TpsLimitStrategy {
+func (creator *slidingWindowStrategyCreator) Create(rate int, interval int) filter.TpsLimitStrategy {
 	return &SlidingWindowTpsLimitStrategyImpl{
 		rate:     rate,
 		interval: int64(interval) * int64(time.Millisecond),
diff --git a/filter/impl/tps/impl/tps_limit_sliding_window_strategy_test.go b/filter/filter_impl/tps/tps_limit_sliding_window_strategy_test.go
similarity index 99%
rename from filter/impl/tps/impl/tps_limit_sliding_window_strategy_test.go
rename to filter/filter_impl/tps/tps_limit_sliding_window_strategy_test.go
index 075f1d9d2be2d18edfee7dc8691b71da65f5da45..57342d1c443993c49c6124f0ef28dae5ebb203e8 100644
--- a/filter/impl/tps/impl/tps_limit_sliding_window_strategy_test.go
+++ b/filter/filter_impl/tps/tps_limit_sliding_window_strategy_test.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package impl
+package tps
 
 import (
 	"testing"
diff --git a/filter/impl/tps/impl/tps_limit_strategy_mock.go b/filter/filter_impl/tps/tps_limit_strategy_mock.go
similarity index 99%
rename from filter/impl/tps/impl/tps_limit_strategy_mock.go
rename to filter/filter_impl/tps/tps_limit_strategy_mock.go
index a653fb287a2d89d8c6151889ca14b4b7b4832505..72c658fb9a5d48b6080900a4645d318dfd2b0c21 100644
--- a/filter/impl/tps/impl/tps_limit_strategy_mock.go
+++ b/filter/filter_impl/tps/tps_limit_strategy_mock.go
@@ -18,7 +18,7 @@
 // Source: tps_limit_strategy.go
 
 // Package filter is a generated GoMock package.
-package impl
+package tps
 
 import (
 	gomock "github.com/golang/mock/gomock"
diff --git a/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy.go b/filter/filter_impl/tps/tps_limit_thread_safe_fix_window_strategy.go
similarity index 93%
rename from filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy.go
rename to filter/filter_impl/tps/tps_limit_thread_safe_fix_window_strategy.go
index 9a1b21a3349845e32cb0fe38b07a7f932ec4f454..16624836e6397df5adda3f2aa5a80966721a97fb 100644
--- a/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy.go
+++ b/filter/filter_impl/tps/tps_limit_thread_safe_fix_window_strategy.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package impl
+package tps
 
 import (
 	"sync"
@@ -23,7 +23,7 @@ import (
 
 import (
 	"github.com/apache/dubbo-go/common/extension"
-	"github.com/apache/dubbo-go/filter/impl/tps"
+	"github.com/apache/dubbo-go/filter"
 )
 
 func init() {
@@ -33,6 +33,7 @@ func init() {
 }
 
 /**
+ * ThreadSafeFixedWindowTpsLimitStrategyImpl
  * it's the thread-safe implementation.
  * Also, it's a thread-safe decorator of FixedWindowTpsLimitStrategyImpl
  * "UserProvider":
@@ -52,6 +53,7 @@ type ThreadSafeFixedWindowTpsLimitStrategyImpl struct {
 	fixedWindow *FixedWindowTpsLimitStrategyImpl
 }
 
+// IsAllowable ...
 func (impl *ThreadSafeFixedWindowTpsLimitStrategyImpl) IsAllowable() bool {
 	impl.mutex.Lock()
 	defer impl.mutex.Unlock()
@@ -62,7 +64,7 @@ type threadSafeFixedWindowStrategyCreator struct {
 	fixedWindowStrategyCreator *fixedWindowStrategyCreator
 }
 
-func (creator *threadSafeFixedWindowStrategyCreator) Create(rate int, interval int) tps.TpsLimitStrategy {
+func (creator *threadSafeFixedWindowStrategyCreator) Create(rate int, interval int) filter.TpsLimitStrategy {
 	fixedWindowStrategy := creator.fixedWindowStrategyCreator.Create(rate, interval).(*FixedWindowTpsLimitStrategyImpl)
 	return &ThreadSafeFixedWindowTpsLimitStrategyImpl{
 		fixedWindow: fixedWindowStrategy,
diff --git a/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy_test.go b/filter/filter_impl/tps/tps_limit_thread_safe_fix_window_strategy_test.go
similarity index 99%
rename from filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy_test.go
rename to filter/filter_impl/tps/tps_limit_thread_safe_fix_window_strategy_test.go
index 129493962403e0028b09f9646054fda236c99ff7..90cd15201cd71aafcc50a1dfb801ece7a5dee26a 100644
--- a/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy_test.go
+++ b/filter/filter_impl/tps/tps_limit_thread_safe_fix_window_strategy_test.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package impl
+package tps
 
 import (
 	"testing"
diff --git a/filter/impl/tps/impl/tps_limiter_method_service.go b/filter/filter_impl/tps/tps_limiter_method_service.go
similarity index 94%
rename from filter/impl/tps/impl/tps_limiter_method_service.go
rename to filter/filter_impl/tps/tps_limiter_method_service.go
index 426ae5994867c5a09653641870ebcef531c0d43c..7fe8de9237b82415a09083c2be59df5e232ecaf0 100644
--- a/filter/impl/tps/impl/tps_limiter_method_service.go
+++ b/filter/filter_impl/tps/tps_limiter_method_service.go
@@ -14,7 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package impl
+
+package tps
 
 import (
 	"fmt"
@@ -30,11 +31,13 @@ import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
-	"github.com/apache/dubbo-go/filter/impl/tps"
+	"github.com/apache/dubbo-go/filter"
 	"github.com/apache/dubbo-go/protocol"
 )
 
-const name = "method-service"
+const (
+	name = "method-service"
+)
 
 func init() {
 	extension.SetTpsLimiter(constant.DEFAULT_KEY, GetMethodServiceTpsLimiter)
@@ -42,6 +45,7 @@ func init() {
 }
 
 /**
+ * MethodServiceTpsLimiterImpl
  * This implementation allows developer to config both method-level and service-level tps limiter.
  * for example:
  * "UserProvider":
@@ -111,6 +115,7 @@ type MethodServiceTpsLimiterImpl struct {
 	tpsState *concurrent.Map
 }
 
+// IsAllowable ...
 func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocation protocol.Invocation) bool {
 
 	methodConfigPrefix := "methods." + invocation.MethodName() + "."
@@ -127,7 +132,7 @@ func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocatio
 
 	limitState, found := limiter.tpsState.Load(limitTarget)
 	if found {
-		return limitState.(tps.TpsLimitStrategy).IsAllowable()
+		return limitState.(filter.TpsLimitStrategy).IsAllowable()
 	}
 
 	limitRate := getLimitConfig(methodLimitRateConfig, url, invocation,
@@ -149,7 +154,7 @@ func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocatio
 		url.GetParam(constant.TPS_LIMIT_STRATEGY_KEY, constant.DEFAULT_KEY))
 	limitStateCreator := extension.GetTpsLimitStrategyCreator(limitStrategyConfig)
 	limitState, _ = limiter.tpsState.LoadOrStore(limitTarget, limitStateCreator.Create(int(limitRate), int(limitInterval)))
-	return limitState.(tps.TpsLimitStrategy).IsAllowable()
+	return limitState.(filter.TpsLimitStrategy).IsAllowable()
 }
 
 func getLimitConfig(methodLevelConfig string,
@@ -178,7 +183,8 @@ func getLimitConfig(methodLevelConfig string,
 var methodServiceTpsLimiterInstance *MethodServiceTpsLimiterImpl
 var methodServiceTpsLimiterOnce sync.Once
 
-func GetMethodServiceTpsLimiter() tps.TpsLimiter {
+// GetMethodServiceTpsLimiter ...
+func GetMethodServiceTpsLimiter() filter.TpsLimiter {
 	methodServiceTpsLimiterOnce.Do(func() {
 		methodServiceTpsLimiterInstance = &MethodServiceTpsLimiterImpl{
 			tpsState: concurrent.NewMap(),
diff --git a/filter/impl/tps/impl/tps_limiter_method_service_test.go b/filter/filter_impl/tps/tps_limiter_method_service_test.go
similarity index 97%
rename from filter/impl/tps/impl/tps_limiter_method_service_test.go
rename to filter/filter_impl/tps/tps_limiter_method_service_test.go
index e747d4682d0a8bdee03da6f012fb76b7bd1e02af..441224a3e35147b85c3553871dcaa1fefd09db04 100644
--- a/filter/impl/tps/impl/tps_limiter_method_service_test.go
+++ b/filter/filter_impl/tps/tps_limiter_method_service_test.go
@@ -15,13 +15,14 @@
  * limitations under the License.
  */
 
-package impl
+package tps
 
 import (
 	"net/url"
 	"testing"
 )
 import (
+	"github.com/apache/dubbo-go/filter"
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
 )
@@ -30,7 +31,6 @@ import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
-	"github.com/apache/dubbo-go/filter/impl/tps"
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
@@ -144,10 +144,10 @@ type mockStrategyCreator struct {
 	rate     int
 	interval int
 	t        *testing.T
-	strategy tps.TpsLimitStrategy
+	strategy filter.TpsLimitStrategy
 }
 
-func (creator *mockStrategyCreator) Create(rate int, interval int) tps.TpsLimitStrategy {
+func (creator *mockStrategyCreator) Create(rate int, interval int) filter.TpsLimitStrategy {
 	assert.Equal(creator.t, creator.rate, rate)
 	assert.Equal(creator.t, creator.interval, interval)
 	return creator.strategy
diff --git a/filter/impl/tps/impl/tps_limiter_mock.go b/filter/filter_impl/tps/tps_limiter_mock.go
similarity index 99%
rename from filter/impl/tps/impl/tps_limiter_mock.go
rename to filter/filter_impl/tps/tps_limiter_mock.go
index acd3a15d18baf10838faf57e141afe1711f0aebb..463b0988acbeb17a967c9803337a61c4914bce42 100644
--- a/filter/impl/tps/impl/tps_limiter_mock.go
+++ b/filter/filter_impl/tps/tps_limiter_mock.go
@@ -18,7 +18,7 @@
 // Source: tps_limiter.go
 
 // Package filter is a generated GoMock package.
-package impl
+package tps
 
 import (
 	reflect "reflect"
diff --git a/filter/impl/tps_limit_filter.go b/filter/filter_impl/tps_limit_filter.go
similarity index 80%
rename from filter/impl/tps_limit_filter.go
rename to filter/filter_impl/tps_limit_filter.go
index 3cb7381c8616abd61fe2ac306b59694a92715dda..fa78288f9678d67d0eb0d025a83b75493f7fda80 100644
--- a/filter/impl/tps_limit_filter.go
+++ b/filter/filter_impl/tps_limit_filter.go
@@ -15,19 +15,23 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
+import (
+	"context"
+)
 import (
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/filter"
-	_ "github.com/apache/dubbo-go/filter/common/impl"
-	_ "github.com/apache/dubbo-go/filter/impl/tps/impl"
+	_ "github.com/apache/dubbo-go/filter/filter_impl/tps"
+	_ "github.com/apache/dubbo-go/filter/handler"
 	"github.com/apache/dubbo-go/protocol"
 )
 
 const (
+	// TpsLimitFilterKey key
 	TpsLimitFilterKey = "tps"
 )
 
@@ -36,6 +40,7 @@ func init() {
 }
 
 /**
+ * TpsLimitFilter
  * if you wish to use the TpsLimiter, please add the configuration into your service provider configuration:
  * for example:
  * "UserProvider":
@@ -51,25 +56,29 @@ func init() {
 type TpsLimitFilter struct {
 }
 
-func (t TpsLimitFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// Invoke ...
+func (t TpsLimitFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	url := invoker.GetUrl()
 	tpsLimiter := url.GetParam(constant.TPS_LIMITER_KEY, "")
 	rejectedExeHandler := url.GetParam(constant.TPS_REJECTED_EXECUTION_HANDLER_KEY, constant.DEFAULT_KEY)
 	if len(tpsLimiter) > 0 {
 		allow := extension.GetTpsLimiter(tpsLimiter).IsAllowable(invoker.GetUrl(), invocation)
 		if allow {
-			return invoker.Invoke(invocation)
+			return invoker.Invoke(ctx, invocation)
 		}
 		logger.Errorf("The invocation was rejected due to over the tps limitation, url: %s ", url.String())
 		return extension.GetRejectedExecutionHandler(rejectedExeHandler).RejectedExecution(url, invocation)
 	}
-	return invoker.Invoke(invocation)
+	return invoker.Invoke(ctx, invocation)
 }
 
-func (t TpsLimitFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+// OnResponse ...
+func (t TpsLimitFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker,
+	_ protocol.Invocation) protocol.Result {
 	return result
 }
 
+// GetTpsLimitFilter ...
 func GetTpsLimitFilter() filter.Filter {
 	return &TpsLimitFilter{}
 }
diff --git a/filter/impl/tps_limit_filter_test.go b/filter/filter_impl/tps_limit_filter_test.go
similarity index 73%
rename from filter/impl/tps_limit_filter_test.go
rename to filter/filter_impl/tps_limit_filter_test.go
index debdbd00dec97ed67d789bfc45103993c014ab4a..cc423ae1e5f3589dd60b0c8655f1123c290f0ffc 100644
--- a/filter/impl/tps_limit_filter_test.go
+++ b/filter/filter_impl/tps_limit_filter_test.go
@@ -15,14 +15,18 @@
  * limitations under the License.
  */
 
-package impl
+package filter_impl
 
 import (
+	"context"
 	"net/url"
 	"testing"
 )
 
 import (
+	"github.com/apache/dubbo-go/filter"
+	"github.com/apache/dubbo-go/filter/filter_impl/tps"
+	common2 "github.com/apache/dubbo-go/filter/handler"
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
 )
@@ -31,10 +35,6 @@ import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
-	filterCommon "github.com/apache/dubbo-go/filter/common"
-	filterCommonImpl "github.com/apache/dubbo-go/filter/common/impl"
-	"github.com/apache/dubbo-go/filter/impl/tps"
-	"github.com/apache/dubbo-go/filter/impl/tps/impl"
 	"github.com/apache/dubbo-go/protocol"
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
@@ -46,8 +46,10 @@ func TestTpsLimitFilter_Invoke_With_No_TpsLimiter(t *testing.T) {
 		common.WithParamsValue(constant.TPS_LIMITER_KEY, ""))
 	attch := make(map[string]string, 0)
 
-	result := tpsFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl),
-		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := tpsFilter.Invoke(context.Background(),
+		protocol.NewBaseInvoker(*invokeUrl),
+		invocation.NewRPCInvocation("MethodName",
+			[]interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 
@@ -56,9 +58,9 @@ func TestTpsLimitFilter_Invoke_With_No_TpsLimiter(t *testing.T) {
 func TestGenericFilter_Invoke_With_Default_TpsLimiter(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	mockLimiter := impl.NewMockTpsLimiter(ctrl)
+	mockLimiter := tps.NewMockTpsLimiter(ctrl)
 	mockLimiter.EXPECT().IsAllowable(gomock.Any(), gomock.Any()).Return(true).Times(1)
-	extension.SetTpsLimiter(constant.DEFAULT_KEY, func() tps.TpsLimiter {
+	extension.SetTpsLimiter(constant.DEFAULT_KEY, func() filter.TpsLimiter {
 		return mockLimiter
 	})
 
@@ -68,8 +70,10 @@ func TestGenericFilter_Invoke_With_Default_TpsLimiter(t *testing.T) {
 		common.WithParamsValue(constant.TPS_LIMITER_KEY, constant.DEFAULT_KEY))
 	attch := make(map[string]string, 0)
 
-	result := tpsFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl),
-		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := tpsFilter.Invoke(context.Background(),
+		protocol.NewBaseInvoker(*invokeUrl),
+		invocation.NewRPCInvocation("MethodName",
+			[]interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 }
@@ -77,17 +81,17 @@ func TestGenericFilter_Invoke_With_Default_TpsLimiter(t *testing.T) {
 func TestGenericFilter_Invoke_With_Default_TpsLimiter_Not_Allow(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	mockLimiter := impl.NewMockTpsLimiter(ctrl)
+	mockLimiter := tps.NewMockTpsLimiter(ctrl)
 	mockLimiter.EXPECT().IsAllowable(gomock.Any(), gomock.Any()).Return(false).Times(1)
-	extension.SetTpsLimiter(constant.DEFAULT_KEY, func() tps.TpsLimiter {
+	extension.SetTpsLimiter(constant.DEFAULT_KEY, func() filter.TpsLimiter {
 		return mockLimiter
 	})
 
 	mockResult := &protocol.RPCResult{}
-	mockRejectedHandler := filterCommonImpl.NewMockRejectedExecutionHandler(ctrl)
+	mockRejectedHandler := common2.NewMockRejectedExecutionHandler(ctrl)
 	mockRejectedHandler.EXPECT().RejectedExecution(gomock.Any(), gomock.Any()).Return(mockResult).Times(1)
 
-	extension.SetRejectedExecutionHandler(constant.DEFAULT_KEY, func() filterCommon.RejectedExecutionHandler {
+	extension.SetRejectedExecutionHandler(constant.DEFAULT_KEY, func() filter.RejectedExecutionHandler {
 		return mockRejectedHandler
 	})
 
@@ -97,8 +101,8 @@ func TestGenericFilter_Invoke_With_Default_TpsLimiter_Not_Allow(t *testing.T) {
 		common.WithParamsValue(constant.TPS_LIMITER_KEY, constant.DEFAULT_KEY))
 	attch := make(map[string]string, 0)
 
-	result := tpsFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl),
-		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := tpsFilter.Invoke(context.Background(),
+		protocol.NewBaseInvoker(*invokeUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 }
diff --git a/filter/filter_impl/tracing_filter.go b/filter/filter_impl/tracing_filter.go
new file mode 100644
index 0000000000000000000000000000000000000000..b8058aa601af98b5416da882321546675459c413
--- /dev/null
+++ b/filter/filter_impl/tracing_filter.go
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package filter_impl
+
+import (
+	"context"
+)
+
+import (
+	"github.com/opentracing/opentracing-go"
+	"github.com/opentracing/opentracing-go/log"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/filter"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+const (
+	tracingFilterName = "tracing"
+)
+
+// this should be executed before users set their own Tracer
+func init() {
+	extension.SetFilter(tracingFilterName, newTracingFilter)
+	opentracing.SetGlobalTracer(opentracing.NoopTracer{})
+}
+
+var (
+	errorKey   = "ErrorMsg"
+	successKey = "Success"
+)
+
+// if you wish to using opentracing, please add the this filter into your filter attribute in your configure file.
+// notice that this could be used in both client-side and server-side.
+type tracingFilter struct {
+}
+
+func (tf *tracingFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	var (
+		spanCtx context.Context
+		span    opentracing.Span
+	)
+	operationName := invoker.GetUrl().ServiceKey() + "#" + invocation.MethodName()
+
+	wiredCtx := ctx.Value(constant.TRACING_REMOTE_SPAN_CTX)
+	preSpan := opentracing.SpanFromContext(ctx)
+
+	if preSpan != nil {
+		// it means that someone already create a span to trace, so we use the span to be the parent span
+		span = opentracing.StartSpan(operationName, opentracing.ChildOf(preSpan.Context()))
+		spanCtx = opentracing.ContextWithSpan(ctx, span)
+
+	} else if wiredCtx != nil {
+
+		// it means that there has a remote span, usually from client side. so we use this as the parent
+		span = opentracing.StartSpan(operationName, opentracing.ChildOf(wiredCtx.(opentracing.SpanContext)))
+		spanCtx = opentracing.ContextWithSpan(ctx, span)
+	} else {
+		// it means that there is not any span, so we create a span as the root span.
+		span, spanCtx = opentracing.StartSpanFromContext(ctx, operationName)
+	}
+
+	defer func() {
+		span.Finish()
+	}()
+
+	result := invoker.Invoke(spanCtx, invocation)
+	span.SetTag(successKey, result.Error() != nil)
+	if result.Error() != nil {
+		span.LogFields(log.String(errorKey, result.Error().Error()))
+	}
+	return result
+}
+
+func (tf *tracingFilter) OnResponse(ctx context.Context, result protocol.Result,
+	invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	return result
+}
+
+var (
+	tracingFilterInstance *tracingFilter
+)
+
+func newTracingFilter() filter.Filter {
+	if tracingFilterInstance == nil {
+		tracingFilterInstance = &tracingFilter{}
+	}
+	return tracingFilterInstance
+}
diff --git a/filter/filter_impl/tracing_filter_test.go b/filter/filter_impl/tracing_filter_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..a51692dddcc3400032650f4953eb1e28fb047709
--- /dev/null
+++ b/filter/filter_impl/tracing_filter_test.go
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package filter_impl
+
+import (
+	"context"
+	"testing"
+)
+
+import (
+	"github.com/opentracing/opentracing-go"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestTracingFilter_Invoke(t *testing.T) {
+	url, _ := common.NewURL(
+		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" +
+			"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." +
+			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" +
+			"BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&" +
+			"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
+	invoker := protocol.NewBaseInvoker(url)
+
+	attach := make(map[string]string, 10)
+	inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach)
+	ctx := context.Background()
+	tf := newTracingFilter()
+
+	// do not has any span
+	tf.Invoke(ctx, invoker, inv)
+
+	span, ctx := opentracing.StartSpanFromContext(ctx, "Test-Operation")
+	defer span.Finish()
+
+	// has previous span
+	tf.Invoke(ctx, invoker, inv)
+
+	// has remote ctx
+	ctx = context.WithValue(context.Background(), constant.TRACING_REMOTE_SPAN_CTX, span.Context())
+	tf.Invoke(ctx, invoker, inv)
+}
diff --git a/filter/common/impl/rejected_execution_handler_mock.go b/filter/handler/rejected_execution_handler_mock.go
similarity index 99%
rename from filter/common/impl/rejected_execution_handler_mock.go
rename to filter/handler/rejected_execution_handler_mock.go
index dace1894668d3a4a154a87bfbdbcc860a97a11ec..a5bef63b3729a7b04d911c9844320aa778ac357a 100644
--- a/filter/common/impl/rejected_execution_handler_mock.go
+++ b/filter/handler/rejected_execution_handler_mock.go
@@ -18,7 +18,7 @@
 // Source: rejected_execution_handler.go
 
 // Package filter is a generated GoMock package.
-package impl
+package handler
 
 import (
 	reflect "reflect"
diff --git a/filter/common/impl/rejected_execution_handler_only_log.go b/filter/handler/rejected_execution_handler_only_log.go
similarity index 85%
rename from filter/common/impl/rejected_execution_handler_only_log.go
rename to filter/handler/rejected_execution_handler_only_log.go
index 8943433af1ba908fc834740163df78e3b2b6443a..0f9003c7df2165a2f3a364a5afc47f578db1d243 100644
--- a/filter/common/impl/rejected_execution_handler_only_log.go
+++ b/filter/handler/rejected_execution_handler_only_log.go
@@ -15,9 +15,10 @@
  * limitations under the License.
  */
 
-package impl
+package handler
 
 import (
+	"github.com/apache/dubbo-go/filter"
 	"sync"
 )
 
@@ -26,11 +27,13 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
-	filterCommon "github.com/apache/dubbo-go/filter/common"
 	"github.com/apache/dubbo-go/protocol"
 )
 
-const HandlerName = "log"
+const (
+	// HandlerName handler name
+	HandlerName = "log"
+)
 
 func init() {
 	extension.SetRejectedExecutionHandler(HandlerName, GetOnlyLogRejectedExecutionHandler)
@@ -41,6 +44,7 @@ var onlyLogHandlerInstance *OnlyLogRejectedExecutionHandler
 var onlyLogHandlerOnce sync.Once
 
 /**
+ * OnlyLogRejectedExecutionHandler
  * This implementation only logs the invocation info.
  * it always return en error inside the result.
  * "UserProvider":
@@ -56,12 +60,16 @@ var onlyLogHandlerOnce sync.Once
 type OnlyLogRejectedExecutionHandler struct {
 }
 
-func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result {
+// RejectedExecution ...
+func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL,
+	_ protocol.Invocation) protocol.Result {
+
 	logger.Errorf("The invocation was rejected. url: %s", url.String())
 	return &protocol.RPCResult{}
 }
 
-func GetOnlyLogRejectedExecutionHandler() filterCommon.RejectedExecutionHandler {
+// GetOnlyLogRejectedExecutionHandler ...
+func GetOnlyLogRejectedExecutionHandler() filter.RejectedExecutionHandler {
 	onlyLogHandlerOnce.Do(func() {
 		onlyLogHandlerInstance = &OnlyLogRejectedExecutionHandler{}
 	})
diff --git a/filter/common/impl/rejected_execution_handler_only_log_test.go b/filter/handler/rejected_execution_handler_only_log_test.go
similarity index 98%
rename from filter/common/impl/rejected_execution_handler_only_log_test.go
rename to filter/handler/rejected_execution_handler_only_log_test.go
index da54d8a106338dd4f21f9b01e66b031e3c311e01..409f09f61bd958992749231fca045b54601fc627 100644
--- a/filter/common/impl/rejected_execution_handler_only_log_test.go
+++ b/filter/handler/rejected_execution_handler_only_log_test.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package impl
+package handler
 
 import (
 	"net/url"
diff --git a/filter/common/rejected_execution_handler.go b/filter/rejected_execution_handler.go
similarity index 97%
rename from filter/common/rejected_execution_handler.go
rename to filter/rejected_execution_handler.go
index b993b8444c14c13ce9a8861c113dc02ca5fd335a..caeea1db6631d0968fd58f59f9577ee9272f3ca0 100644
--- a/filter/common/rejected_execution_handler.go
+++ b/filter/rejected_execution_handler.go
@@ -14,7 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package common
+
+package filter
 
 import (
 	"github.com/apache/dubbo-go/common"
@@ -22,6 +23,7 @@ import (
 )
 
 /**
+ * RejectedExecutionHandler
  * If the invocation cannot pass any validation in filter, like ExecuteLimitFilter and TpsLimitFilter,
  * the implementation will be used.
  * The common case is that sometimes you want to return the default value when the request was rejected.
diff --git a/filter/impl/tps/tps_limit_strategy.go b/filter/tps_limit_strategy.go
similarity index 95%
rename from filter/impl/tps/tps_limit_strategy.go
rename to filter/tps_limit_strategy.go
index c55f008a09b3743f728ab0506c6b0095cbfd181c..5edf32ce1912642c7ad0ea0b3f6144b45c267eb4 100644
--- a/filter/impl/tps/tps_limit_strategy.go
+++ b/filter/tps_limit_strategy.go
@@ -15,9 +15,10 @@
  * limitations under the License.
  */
 
-package tps
+package filter
 
 /*
+ * TpsLimitStrategy
  * please register your implementation by invoking SetTpsLimitStrategy
  * "UserProvider":
  *   registry: "hangzhouzk"
@@ -35,6 +36,7 @@ type TpsLimitStrategy interface {
 	IsAllowable() bool
 }
 
+// TpsLimitStrategyCreator ...
 type TpsLimitStrategyCreator interface {
 	Create(rate int, interval int) TpsLimitStrategy
 }
diff --git a/filter/impl/tps/tps_limiter.go b/filter/tps_limiter.go
similarity index 97%
rename from filter/impl/tps/tps_limiter.go
rename to filter/tps_limiter.go
index 0622a957a8ba14fdebb52ff44ecf72da17703163..dbc9f76838a4406b4788e7757453098613253d58 100644
--- a/filter/impl/tps/tps_limiter.go
+++ b/filter/tps_limiter.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package tps
+package filter
 
 import (
 	"github.com/apache/dubbo-go/common"
@@ -23,6 +23,7 @@ import (
 )
 
 /*
+ * TpsLimiter
  * please register your implementation by invoking SetTpsLimiter
  * The usage, for example:
  * "UserProvider":
diff --git a/go.mod b/go.mod
index c2a61f2db1484338bba7dd1bf00a9ff9de2125df..54b39d322e83e05c4c54ffdf166dd4f0aa039249 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ require (
 	github.com/Workiva/go-datastructures v1.0.50
 	github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
 	github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e // indirect
-	github.com/apache/dubbo-go-hessian2 v1.2.5-0.20191029001541-894e45c9aaaa
+	github.com/apache/dubbo-go-hessian2 v1.3.1-0.20200111150223-4ce8c8d0d7ac
 	github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 // indirect
 	github.com/coreos/bbolt v1.3.3 // indirect
 	github.com/coreos/etcd v3.3.13+incompatible
@@ -12,12 +12,14 @@ require (
 	github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
 	github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
 	github.com/creasty/defaults v1.3.0
-	github.com/dubbogo/getty v1.3.1
-	github.com/dubbogo/gost v1.3.0
+	github.com/dubbogo/getty v1.3.2
+	github.com/dubbogo/go-zookeeper v1.0.0
+	github.com/dubbogo/gost v1.5.2
 	github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
 	github.com/go-errors/errors v1.0.1 // indirect
 	github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
 	github.com/golang/mock v1.3.1
+	github.com/golang/protobuf v1.3.2
 	github.com/google/btree v1.0.0 // indirect
 	github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect
 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
@@ -31,11 +33,12 @@ require (
 	github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect
 	github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
 	github.com/magiconair/properties v1.8.1
+	github.com/mitchellh/mapstructure v1.1.2
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
 	github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb
+	github.com/opentracing/opentracing-go v1.1.0
 	github.com/pkg/errors v0.8.1
-	github.com/prometheus/client_golang v1.1.0 // indirect
-	github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec
+	github.com/prometheus/client_golang v1.1.0
 	github.com/satori/go.uuid v1.2.0
 	github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect
 	github.com/soheilhy/cmux v0.1.4 // indirect
diff --git a/go.sum b/go.sum
index 9855250a90f72eca314bf54cd9bea03a619b6a5e..0461f29653568944637306d65a6addbd79df664f 100644
--- a/go.sum
+++ b/go.sum
@@ -35,8 +35,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
 github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e h1:MSuLXx/mveDbpDNhVrcWTMeV4lbYWKcyO4rH+jAxmX0=
 github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
 github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
-github.com/apache/dubbo-go-hessian2 v1.2.5-0.20191029001541-894e45c9aaaa h1:11TO1wiM5bvGAVrmfN5atD8gZqUSPE1TBoIs8sI6Abk=
-github.com/apache/dubbo-go-hessian2 v1.2.5-0.20191029001541-894e45c9aaaa/go.mod h1:LWnndnrFXZmJLAzoyNAPNHSIJ1KOHVkTSsHgC3YYWlo=
+github.com/apache/dubbo-go-hessian2 v1.3.1-0.20200111150223-4ce8c8d0d7ac h1:QKRMidg/RbdI5oaQWMb8Lxo63S+fLmsgMxsFoOCftKw=
+github.com/apache/dubbo-go-hessian2 v1.3.1-0.20200111150223-4ce8c8d0d7ac/go.mod h1:VwEnsOMidkM1usya2uPfGpSLO9XUF//WQcWn3y+jFz8=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -102,12 +102,14 @@ github.com/docker/go-connections v0.3.0 h1:3lOnM9cSzgGwx8VfK/NGOW5fLQ0GjIlCkaktF
 github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
 github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/dubbogo/getty v1.3.1 h1:9fehwTo/D6+z6/+kADMbhbKeMkP80o/3g+XwV5lFLTY=
-github.com/dubbogo/getty v1.3.1/go.mod h1:dtLOEb1v6EMHsQNYRWEACiRLmTWB2kJGUAj1aXayPOg=
-github.com/dubbogo/gost v1.1.1 h1:JCM7vx5edPIjDA5ovJTuzEEXuw2t7xLyrlgi2mi5jHI=
-github.com/dubbogo/gost v1.1.1/go.mod h1:R7wZm1DrmrKGr50mBZVcg6C9ekG8aL5hP+sgWcIDwQg=
-github.com/dubbogo/gost v1.3.0 h1:n90mIUWCPD69BqW8wJ43NDy0RgNxx02aAG4QJcJ785U=
-github.com/dubbogo/gost v1.3.0/go.mod h1:R7wZm1DrmrKGr50mBZVcg6C9ekG8aL5hP+sgWcIDwQg=
+github.com/dubbogo/getty v1.3.2 h1:l1KVSs/1CtTKbIPTrkTtBT6S9ddvmswDGoAnnl2CDpM=
+github.com/dubbogo/getty v1.3.2/go.mod h1:ANbVQ9tbpZ2b0xdR8nRrgS/oXIsZAeRxzvPSOn/7mbk=
+github.com/dubbogo/go-zookeeper v1.0.0 h1:RsYdlGwhDW+iKXM3eIIcvt34P2swLdmQfuIJxsHlGoM=
+github.com/dubbogo/go-zookeeper v1.0.0/go.mod h1:fn6n2CAEer3novYgk9ULLwAjuV8/g4DdC2ENwRb6E+c=
+github.com/dubbogo/gost v1.5.1 h1:oG5dzaWf1KYynBaBoUIOkgT+YD0niHV6xxI0Odq7hDg=
+github.com/dubbogo/gost v1.5.1/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
+github.com/dubbogo/gost v1.5.2 h1:ri/03971hdpnn3QeCU+4UZgnRNGDXLDGDucR/iozZm8=
+github.com/dubbogo/gost v1.5.2/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
 github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74 h1:2MIhn2R6oXQbgW5yHfS+d6YqyMfXiu2L55rFZC4UD/M=
 github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo=
 github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0 h1:ZoRgc53qJCfSLimXqJDrmBhnt5GChDsExMCK7t48o0Y=
@@ -369,6 +371,8 @@ github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVo
 github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
 github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 github.com/ory/dockertest v3.3.4+incompatible h1:VrpM6Gqg7CrPm3bL4Wm1skO+zFWLbh7/Xb5kGEbJRh8=
 github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
 github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c h1:vwpFWvAO8DeIZfFeqASzZfsxuWPno9ncAebBEP0N3uE=
@@ -410,8 +414,6 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735 h1:7YvPJVmEeFHR1Tj9sZEYsmarJEQfMVYpd/Vyy/A8dqE=
 github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
-github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec h1:6ncX5ko6B9LntYM0YBRXkiSaZMmLYeZ/NWcmeB43mMY=
-github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
 github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
@@ -449,6 +451,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
 github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto=
 github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
 github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9/go.mod h1:RHkNRtSLfOK7qBTHaeSX1D6BNpI3qw7NTxsmNr4RvN8=
+github.com/tevid/gohamcrest v1.1.1 h1:ou+xSqlIw1xfGTg1uq1nif/htZ2S3EzRqLm2BP+tYU0=
 github.com/tevid/gohamcrest v1.1.1/go.mod h1:3UvtWlqm8j5JbwYZh80D/PVBt0mJ1eJiYgZMibh0H/k=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
diff --git a/metrics/prometheus/reporter.go b/metrics/prometheus/reporter.go
new file mode 100644
index 0000000000000000000000000000000000000000..1636b14da2fe5ab714853aa662eaa774ddbc1791
--- /dev/null
+++ b/metrics/prometheus/reporter.go
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package prometheus
+
+import (
+	"context"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+import (
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/metrics"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+const (
+	reporterName = "prometheus"
+	serviceKey   = constant.SERVICE_KEY
+	groupKey     = constant.GROUP_KEY
+	versionKey   = constant.VERSION_KEY
+	methodKey    = constant.METHOD_KEY
+	timeoutKey   = constant.TIMEOUT_KEY
+
+	providerKey = "provider"
+	consumerKey = "consumer"
+
+	// to identify the metric's type
+	histogramSuffix = "_histogram"
+	// to identify the metric's type
+	summarySuffix = "_summary"
+)
+
+var (
+	labelNames       = []string{serviceKey, groupKey, versionKey, methodKey, timeoutKey}
+	namespace        = config.GetApplicationConfig().Name
+	reporterInstance *PrometheusReporter
+	reporterInitOnce sync.Once
+)
+
+// should initialize after loading configuration
+func init() {
+
+	extension.SetMetricReporter(reporterName, newPrometheusReporter)
+}
+
+// PrometheusReporter
+// it will collect the data for Prometheus
+// if you want to use this, you should initialize your prometheus.
+// https://prometheus.io/docs/guides/go-application/
+type PrometheusReporter struct {
+
+	// report the consumer-side's summary data
+	consumerSummaryVec *prometheus.SummaryVec
+	// report the provider-side's summary data
+	providerSummaryVec *prometheus.SummaryVec
+
+	// report the provider-side's histogram data
+	providerHistogramVec *prometheus.HistogramVec
+	// report the consumer-side's histogram data
+	consumerHistogramVec *prometheus.HistogramVec
+}
+
+// Report report the duration to Prometheus
+// the role in url must be consumer or provider
+// or it will be ignored
+func (reporter *PrometheusReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) {
+	url := invoker.GetUrl()
+	var sumVec *prometheus.SummaryVec
+	var hisVec *prometheus.HistogramVec
+	if isProvider(url) {
+		sumVec = reporter.providerSummaryVec
+		hisVec = reporter.providerHistogramVec
+	} else if isConsumer(url) {
+		sumVec = reporter.consumerSummaryVec
+		hisVec = reporter.consumerHistogramVec
+	} else {
+		logger.Warnf("The url is not the consumer's or provider's, "+
+			"so the invocation will be ignored. url: %s", url.String())
+		return
+	}
+
+	labels := prometheus.Labels{
+		serviceKey: url.Service(),
+		groupKey:   url.GetParam(groupKey, ""),
+		versionKey: url.GetParam(versionKey, ""),
+		methodKey:  invocation.MethodName(),
+		timeoutKey: url.GetParam(timeoutKey, ""),
+	}
+
+	costMs := float64(cost.Nanoseconds() / constant.MsToNanoRate)
+	sumVec.With(labels).Observe(costMs)
+	hisVec.With(labels).Observe(costMs)
+}
+
+func newHistogramVec(side string) *prometheus.HistogramVec {
+	mc := config.GetMetricConfig()
+	return prometheus.NewHistogramVec(
+		prometheus.HistogramOpts{
+			Namespace: namespace,
+			Subsystem: side,
+			Name:      serviceKey + histogramSuffix,
+			Help:      "This is the dubbo's histogram metrics",
+			Buckets:   mc.GetHistogramBucket(),
+		},
+		labelNames)
+}
+
+// whether this url represents the application received the request as server
+func isProvider(url common.URL) bool {
+	role := url.GetParam(constant.ROLE_KEY, "")
+	return strings.EqualFold(role, strconv.Itoa(common.PROVIDER))
+}
+
+// whether this url represents the application sent then request as client
+func isConsumer(url common.URL) bool {
+	role := url.GetParam(constant.ROLE_KEY, "")
+	return strings.EqualFold(role, strconv.Itoa(common.CONSUMER))
+}
+
+// newSummaryVec create SummaryVec, the Namespace is dubbo
+// the objectives is from my experience.
+func newSummaryVec(side string) *prometheus.SummaryVec {
+	return prometheus.NewSummaryVec(
+		prometheus.SummaryOpts{
+			Namespace: namespace,
+			Help:      "This is the dubbo's summary metrics",
+			Subsystem: side,
+			Name:      serviceKey + summarySuffix,
+			Objectives: map[float64]float64{
+				0.5:   0.01,
+				0.75:  0.01,
+				0.90:  0.005,
+				0.98:  0.002,
+				0.99:  0.001,
+				0.999: 0.0001,
+			},
+		},
+		labelNames,
+	)
+}
+
+// newPrometheusReporter create new prometheusReporter
+// it will register the metrics into prometheus
+func newPrometheusReporter() metrics.Reporter {
+	if reporterInstance == nil {
+		reporterInitOnce.Do(func() {
+			reporterInstance = &PrometheusReporter{
+				consumerSummaryVec: newSummaryVec(consumerKey),
+				providerSummaryVec: newSummaryVec(providerKey),
+
+				consumerHistogramVec: newHistogramVec(consumerKey),
+				providerHistogramVec: newHistogramVec(providerKey),
+			}
+			prometheus.MustRegister(reporterInstance.consumerSummaryVec, reporterInstance.providerSummaryVec,
+				reporterInstance.consumerHistogramVec, reporterInstance.providerHistogramVec)
+		})
+	}
+	return reporterInstance
+}
diff --git a/metrics/prometheus/reporter_test.go b/metrics/prometheus/reporter_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..0cb7d09a2c8e71fb88b54789c8eb3ee2cf967fbf
--- /dev/null
+++ b/metrics/prometheus/reporter_test.go
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package prometheus
+
+import (
+	"context"
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestPrometheusReporter_Report(t *testing.T) {
+	reporter := extension.GetMetricReporter(reporterName)
+	url, _ := common.NewURL(
+		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" +
+			"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." +
+			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" +
+			"BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&" +
+			"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
+	invoker := protocol.NewBaseInvoker(url)
+
+	attach := make(map[string]string, 10)
+	inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach)
+
+	assert.False(t, isConsumer(url))
+	ctx := context.Background()
+	reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil)
+
+	// consumer side
+	url, _ = common.NewURL(
+		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" +
+			"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." +
+			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" +
+			"BDTService&organization=ikurento.com&owner=ZX&registry.role=0&retries=&" +
+			"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
+	invoker = protocol.NewBaseInvoker(url)
+	reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil)
+
+	// invalid role
+	url, _ = common.NewURL(
+		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" +
+			"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." +
+			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" +
+			"BDTService&organization=ikurento.com&owner=ZX&registry.role=9&retries=&" +
+			"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
+	invoker = protocol.NewBaseInvoker(url)
+	reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil)
+}
diff --git a/metrics/reporter.go b/metrics/reporter.go
new file mode 100644
index 0000000000000000000000000000000000000000..85ef1dcdf0dad275edecc1f3a85502c1493c1395
--- /dev/null
+++ b/metrics/reporter.go
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package metrics
+
+import (
+	"context"
+	"time"
+)
+import (
+	"github.com/apache/dubbo-go/protocol"
+)
+
+const (
+	NameSpace = "dubbo"
+)
+
+// it will be use to report the invocation's duration
+type Reporter interface {
+	// report the duration of an invocation
+	Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation,
+		cost time.Duration, res protocol.Result)
+}
diff --git a/protocol/dubbo/client.go b/protocol/dubbo/client.go
index 81f392565f701d990dc1783d5d467814a0fba5bf..3923b7e4e7e543f4c60a89aaebf67f6238916722 100644
--- a/protocol/dubbo/client.go
+++ b/protocol/dubbo/client.go
@@ -85,6 +85,7 @@ func init() {
 	setClientGrpool()
 }
 
+// SetClientConf ...
 func SetClientConf(c ClientConfig) {
 	clientConf = &c
 	err := clientConf.CheckValidity()
@@ -95,6 +96,7 @@ func SetClientConf(c ClientConfig) {
 	setClientGrpool()
 }
 
+// GetClientConf ...
 func GetClientConf() ClientConfig {
 	return *clientConf
 }
@@ -106,6 +108,7 @@ func setClientGrpool() {
 	}
 }
 
+// Options ...
 type Options struct {
 	// connect timeout
 	ConnectTimeout time.Duration
@@ -123,6 +126,7 @@ type AsyncCallbackResponse struct {
 	Reply     interface{}
 }
 
+// Client ...
 type Client struct {
 	opts     Options
 	conf     ClientConfig
@@ -132,6 +136,7 @@ type Client struct {
 	pendingResponses *sync.Map
 }
 
+// NewClient ...
 func NewClient(opt Options) *Client {
 
 	switch {
@@ -152,6 +157,7 @@ func NewClient(opt Options) *Client {
 	return c
 }
 
+// Request ...
 type Request struct {
 	addr   string
 	svcUrl common.URL
@@ -160,6 +166,7 @@ type Request struct {
 	atta   map[string]string
 }
 
+// NewRequest ...
 func NewRequest(addr string, svcUrl common.URL, method string, args interface{}, atta map[string]string) *Request {
 	return &Request{
 		addr:   addr,
@@ -170,11 +177,13 @@ func NewRequest(addr string, svcUrl common.URL, method string, args interface{},
 	}
 }
 
+// Response ...
 type Response struct {
 	reply interface{}
 	atta  map[string]string
 }
 
+// NewResponse ...
 func NewResponse(reply interface{}, atta map[string]string) *Response {
 	return &Response{
 		reply: reply,
@@ -182,13 +191,13 @@ func NewResponse(reply interface{}, atta map[string]string) *Response {
 	}
 }
 
-// call one way
+// CallOneway call one way
 func (c *Client) CallOneway(request *Request) error {
 
 	return perrors.WithStack(c.call(CT_OneWay, request, NewResponse(nil, nil), nil))
 }
 
-// if @response is nil, the transport layer will get the response without notify the invoker.
+// Call if @response is nil, the transport layer will get the response without notify the invoker.
 func (c *Client) Call(request *Request, response *Response) error {
 
 	ct := CT_TwoWay
@@ -199,6 +208,7 @@ func (c *Client) Call(request *Request, response *Response) error {
 	return perrors.WithStack(c.call(ct, request, response, nil))
 }
 
+// AsyncCall ...
 func (c *Client) AsyncCall(request *Request, callback common.AsyncCallback, response *Response) error {
 
 	return perrors.WithStack(c.call(CT_TwoWay, request, response, callback))
@@ -212,7 +222,15 @@ func (c *Client) call(ct CallType, request *Request, response *Response, callbac
 	p.Service.Version = request.svcUrl.GetParam(constant.VERSION_KEY, "")
 	p.Service.Group = request.svcUrl.GetParam(constant.GROUP_KEY, "")
 	p.Service.Method = request.method
+
 	p.Service.Timeout = c.opts.RequestTimeout
+	var timeout = request.svcUrl.GetParam(strings.Join([]string{constant.METHOD_KEYS, request.method + constant.RETRIES_KEY}, "."), "")
+	if len(timeout) != 0 {
+		if t, err := time.ParseDuration(timeout); err == nil {
+			p.Service.Timeout = t
+		}
+	}
+
 	p.Header.SerialID = byte(S_Dubbo)
 	p.Body = hessian.NewRequest(request.args, request.atta)
 
@@ -238,7 +256,13 @@ func (c *Client) call(ct CallType, request *Request, response *Response, callbac
 	if session == nil {
 		return errSessionNotExist
 	}
-	defer c.pool.release(conn, err)
+	defer func() {
+		if err == nil {
+			c.pool.put(conn)
+			return
+		}
+		conn.close()
+	}()
 
 	if err = c.transfer(session, p, rsp); err != nil {
 		return perrors.WithStack(err)
@@ -259,6 +283,7 @@ func (c *Client) call(ct CallType, request *Request, response *Response, callbac
 	return perrors.WithStack(err)
 }
 
+// Close ...
 func (c *Client) Close() {
 	if c.pool != nil {
 		c.pool.close()
diff --git a/protocol/dubbo/client_test.go b/protocol/dubbo/client_test.go
index 3f8a8ee98c3b2d8b87e2d5469a18d1792578d1d6..1e0a73fac1a6cf6d4d102e5f4f6f1ba60fc4102a 100644
--- a/protocol/dubbo/client_test.go
+++ b/protocol/dubbo/client_test.go
@@ -210,10 +210,10 @@ func InitTest(t *testing.T) (protocol.Protocol, common.URL) {
 
 	// Export
 	proto := GetProtocol()
-	url, err := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/UserProvider?anyhost=true&"+
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
+	url, err := common.NewURL("dubbo://127.0.0.1:20000/UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
 		"side=provider&timeout=3000&timestamp=1556509797245&bean.name=UserProvider")
 	assert.NoError(t, err)
 	proto.Export(&proxy_factory.ProxyInvoker{
diff --git a/protocol/dubbo/codec.go b/protocol/dubbo/codec.go
index 758363117f1720a7fe89eb9745b415e506315db8..3e50eb901dbe1e549aea4ea7414d9617851b5363 100644
--- a/protocol/dubbo/codec.go
+++ b/protocol/dubbo/codec.go
@@ -30,28 +30,34 @@ import (
 	perrors "github.com/pkg/errors"
 )
 
-// serial ID
+//SerialID serial ID
 type SerialID byte
 
 const (
+	// S_Dubbo dubbo serial id
 	S_Dubbo SerialID = 2
 )
 
-// call type
+//CallType call type
 type CallType int32
 
 const (
+	// CT_UNKNOWN unknown call type
 	CT_UNKNOWN CallType = 0
-	CT_OneWay  CallType = 1
-	CT_TwoWay  CallType = 2
+	// CT_OneWay call one way
+	CT_OneWay CallType = 1
+	// CT_TwoWay call in request/response
+	CT_TwoWay CallType = 2
 )
 
 ////////////////////////////////////////////
 // dubbo package
 ////////////////////////////////////////////
 
+// SequenceType ...
 type SequenceType int64
 
+// DubboPackage ...
 type DubboPackage struct {
 	Header  hessian.DubboHeader
 	Service hessian.Service
@@ -63,6 +69,7 @@ func (p DubboPackage) String() string {
 	return fmt.Sprintf("DubboPackage: Header-%v, Path-%v, Body-%v", p.Header, p.Service, p.Body)
 }
 
+// Marshal ...
 func (p *DubboPackage) Marshal() (*bytes.Buffer, error) {
 	codec := hessian.NewHessianCodec(nil)
 
@@ -74,6 +81,7 @@ func (p *DubboPackage) Marshal() (*bytes.Buffer, error) {
 	return bytes.NewBuffer(pkg), nil
 }
 
+// Unmarshal ...
 func (p *DubboPackage) Unmarshal(buf *bytes.Buffer, opts ...interface{}) error {
 	codec := hessian.NewHessianCodec(bufio.NewReaderSize(buf, buf.Len()))
 
@@ -89,11 +97,17 @@ func (p *DubboPackage) Unmarshal(buf *bytes.Buffer, opts ...interface{}) error {
 			return perrors.Errorf("opts[0] is not of type *Client")
 		}
 
-		pendingRsp, ok := client.pendingResponses.Load(SequenceType(p.Header.ID))
-		if !ok {
-			return perrors.Errorf("client.GetPendingResponse(%v) = nil", p.Header.ID)
+		if p.Header.Type&hessian.PackageRequest != 0x00 {
+			// size of this array must be '7'
+			// https://github.com/apache/dubbo-go-hessian2/blob/master/request.go#L272
+			p.Body = make([]interface{}, 7)
+		} else {
+			pendingRsp, ok := client.pendingResponses.Load(SequenceType(p.Header.ID))
+			if !ok {
+				return perrors.Errorf("client.GetPendingResponse(%v) = nil", p.Header.ID)
+			}
+			p.Body = &hessian.Response{RspObj: pendingRsp.(*PendingResponse).response.reply}
 		}
-		p.Body = &hessian.Response{RspObj: pendingRsp.(*PendingResponse).response.reply}
 	}
 
 	// read body
@@ -105,6 +119,7 @@ func (p *DubboPackage) Unmarshal(buf *bytes.Buffer, opts ...interface{}) error {
 // PendingResponse
 ////////////////////////////////////////////
 
+// PendingResponse ...
 type PendingResponse struct {
 	seq       uint64
 	err       error
@@ -115,6 +130,7 @@ type PendingResponse struct {
 	done      chan struct{}
 }
 
+// NewPendingResponse ...
 func NewPendingResponse() *PendingResponse {
 	return &PendingResponse{
 		start:    time.Now(),
@@ -123,6 +139,7 @@ func NewPendingResponse() *PendingResponse {
 	}
 }
 
+// GetCallResponse ...
 func (r PendingResponse) GetCallResponse() common.CallbackResponse {
 	return AsyncCallbackResponse{
 		Cause:     r.err,
diff --git a/protocol/dubbo/config.go b/protocol/dubbo/config.go
index 5371c587478ce7d064858108055c3f00f3ff4496..dbc6989c54780afacef717f1d110833d92967f9f 100644
--- a/protocol/dubbo/config.go
+++ b/protocol/dubbo/config.go
@@ -22,10 +22,12 @@ import (
 )
 
 import (
+	"github.com/dubbogo/getty"
 	perrors "github.com/pkg/errors"
 )
 
 type (
+	// GettySessionParam ...
 	GettySessionParam struct {
 		CompressEncoding bool   `default:"false" yaml:"compress_encoding" json:"compress_encoding,omitempty"`
 		TcpNoDelay       bool   `default:"true" yaml:"tcp_no_delay" json:"tcp_no_delay,omitempty"`
@@ -45,7 +47,8 @@ type (
 		SessionName      string `default:"rpc" yaml:"session_name" json:"session_name,omitempty"`
 	}
 
-	// Config holds supported types by the multiconfig package
+	// ServerConfig
+	//Config holds supported types by the multiconfig package
 	ServerConfig struct {
 		// session
 		SessionTimeout string `default:"60s" yaml:"session_timeout" json:"session_timeout,omitempty"`
@@ -61,7 +64,8 @@ type (
 		GettySessionParam GettySessionParam `required:"true" yaml:"getty_session_param" json:"getty_session_param,omitempty"`
 	}
 
-	// Config holds supported types by the multiconfig package
+	// ClientConfig
+	//Config holds supported types by the multiconfig package
 	ClientConfig struct {
 		ReconnectInterval int `default:"0" yaml:"reconnect_interval" json:"reconnect_interval,omitempty"`
 
@@ -90,13 +94,14 @@ type (
 	}
 )
 
+// GetDefaultClientConfig ...
 func GetDefaultClientConfig() ClientConfig {
 	return ClientConfig{
 		ReconnectInterval: 0,
 		ConnectionNum:     16,
-		HeartbeatPeriod:   "5s",
-		SessionTimeout:    "20s",
-		PoolSize:          64,
+		HeartbeatPeriod:   "30s",
+		SessionTimeout:    "180s",
+		PoolSize:          4,
 		PoolTTL:           600,
 		GrPoolSize:        200,
 		QueueLen:          64,
@@ -105,7 +110,7 @@ func GetDefaultClientConfig() ClientConfig {
 			CompressEncoding: false,
 			TcpNoDelay:       true,
 			TcpKeepAlive:     true,
-			KeepAlivePeriod:  "120s",
+			KeepAlivePeriod:  "180s",
 			TcpRBufSize:      262144,
 			TcpWBufSize:      65536,
 			PkgWQSize:        512,
@@ -117,9 +122,10 @@ func GetDefaultClientConfig() ClientConfig {
 		}}
 }
 
+// GetDefaultServerConfig ...
 func GetDefaultServerConfig() ServerConfig {
 	return ServerConfig{
-		SessionTimeout: "20s",
+		SessionTimeout: "180s",
 		SessionNumber:  700,
 		GrPoolSize:     120,
 		QueueNumber:    6,
@@ -128,7 +134,7 @@ func GetDefaultServerConfig() ServerConfig {
 			CompressEncoding: false,
 			TcpNoDelay:       true,
 			TcpKeepAlive:     true,
-			KeepAlivePeriod:  "120s",
+			KeepAlivePeriod:  "180s",
 			TcpRBufSize:      262144,
 			TcpWBufSize:      65536,
 			PkgWQSize:        512,
@@ -141,6 +147,7 @@ func GetDefaultServerConfig() ServerConfig {
 	}
 }
 
+// CheckValidity ...
 func (c *GettySessionParam) CheckValidity() error {
 	var err error
 
@@ -163,6 +170,7 @@ func (c *GettySessionParam) CheckValidity() error {
 	return nil
 }
 
+// CheckValidity ...
 func (c *ClientConfig) CheckValidity() error {
 	var err error
 
@@ -172,6 +180,11 @@ func (c *ClientConfig) CheckValidity() error {
 		return perrors.WithMessagef(err, "time.ParseDuration(HeartbeatPeroid{%#v})", c.HeartbeatPeriod)
 	}
 
+	if c.heartbeatPeriod >= time.Duration(getty.MaxWheelTimeSpan) {
+		return perrors.WithMessagef(err, "heartbeat_period %s should be less than %s",
+			c.HeartbeatPeriod, time.Duration(getty.MaxWheelTimeSpan))
+	}
+
 	if c.sessionTimeout, err = time.ParseDuration(c.SessionTimeout); err != nil {
 		return perrors.WithMessagef(err, "time.ParseDuration(SessionTimeout{%#v})", c.SessionTimeout)
 	}
@@ -179,6 +192,7 @@ func (c *ClientConfig) CheckValidity() error {
 	return perrors.WithStack(c.GettySessionParam.CheckValidity())
 }
 
+// CheckValidity ...
 func (c *ServerConfig) CheckValidity() error {
 	var err error
 
@@ -186,5 +200,10 @@ func (c *ServerConfig) CheckValidity() error {
 		return perrors.WithMessagef(err, "time.ParseDuration(SessionTimeout{%#v})", c.SessionTimeout)
 	}
 
+	if c.sessionTimeout >= time.Duration(getty.MaxWheelTimeSpan) {
+		return perrors.WithMessagef(err, "session_timeout %s should be less than %s",
+			c.SessionTimeout, time.Duration(getty.MaxWheelTimeSpan))
+	}
+
 	return perrors.WithStack(c.GettySessionParam.CheckValidity())
 }
diff --git a/protocol/dubbo/dubbo_exporter.go b/protocol/dubbo/dubbo_exporter.go
index cb06b6b69c9d0873342af5ea49fae054f029608c..f4cd0cc1234f71bdcf6ce746f01ff3618d820fc5 100644
--- a/protocol/dubbo/dubbo_exporter.go
+++ b/protocol/dubbo/dubbo_exporter.go
@@ -28,16 +28,19 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// DubboExporter ...
 type DubboExporter struct {
 	protocol.BaseExporter
 }
 
+// NewDubboExporter ...
 func NewDubboExporter(key string, invoker protocol.Invoker, exporterMap *sync.Map) *DubboExporter {
 	return &DubboExporter{
 		BaseExporter: *protocol.NewBaseExporter(key, invoker, exporterMap),
 	}
 }
 
+// Unexport ...
 func (de *DubboExporter) Unexport() {
 	serviceId := de.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "")
 	de.BaseExporter.Unexport()
diff --git a/protocol/dubbo/dubbo_invoker.go b/protocol/dubbo/dubbo_invoker.go
index 6dcf2568fa8c88a864c567486a501c2ad7feb3f7..67d1d1e7f1710aef71f63063374a848e2981b828 100644
--- a/protocol/dubbo/dubbo_invoker.go
+++ b/protocol/dubbo/dubbo_invoker.go
@@ -18,11 +18,13 @@
 package dubbo
 
 import (
+	"context"
 	"strconv"
 	"sync"
 )
 
 import (
+	"github.com/opentracing/opentracing-go"
 	perrors "github.com/pkg/errors"
 )
 
@@ -34,18 +36,23 @@ import (
 	invocation_impl "github.com/apache/dubbo-go/protocol/invocation"
 )
 
-var Err_No_Reply = perrors.New("request need @response")
+var (
+	// ErrNoReply ...
+	ErrNoReply = perrors.New("request need @response")
+)
 
 var (
 	attachmentKey = []string{constant.INTERFACE_KEY, constant.GROUP_KEY, constant.TOKEN_KEY, constant.TIMEOUT_KEY}
 )
 
+// DubboInvoker ...
 type DubboInvoker struct {
 	protocol.BaseInvoker
 	client   *Client
 	quitOnce sync.Once
 }
 
+// NewDubboInvoker ...
 func NewDubboInvoker(url common.URL, client *Client) *DubboInvoker {
 	return &DubboInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
@@ -53,8 +60,8 @@ func NewDubboInvoker(url common.URL, client *Client) *DubboInvoker {
 	}
 }
 
-func (di *DubboInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
-
+// Invoke ...
+func (di *DubboInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	var (
 		err    error
 		result protocol.RPCResult
@@ -66,6 +73,10 @@ func (di *DubboInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
 			inv.SetAttachments(k, v)
 		}
 	}
+
+	// put the ctx into attachment
+	di.appendCtx(ctx, inv)
+
 	url := di.GetUrl()
 	// async
 	async, err := strconv.ParseBool(inv.AttachmentsByKey(constant.ASYNC_KEY, "false"))
@@ -82,7 +93,7 @@ func (di *DubboInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
 		}
 	} else {
 		if inv.Reply() == nil {
-			result.Err = Err_No_Reply
+			result.Err = ErrNoReply
 		} else {
 			result.Err = di.client.Call(NewRequest(url.Location, url, inv.MethodName(), inv.Arguments(), inv.Attachments()), response)
 		}
@@ -96,6 +107,7 @@ func (di *DubboInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
 	return &result
 }
 
+// Destroy ...
 func (di *DubboInvoker) Destroy() {
 	di.quitOnce.Do(func() {
 		di.BaseInvoker.Destroy()
@@ -105,3 +117,17 @@ func (di *DubboInvoker) Destroy() {
 		}
 	})
 }
+
+// Finally, I made the decision that I don't provide a general way to transfer the whole context
+// because it could be misused. If the context contains to many key-value pairs, the performance will be much lower.
+func (di *DubboInvoker) appendCtx(ctx context.Context, inv *invocation_impl.RPCInvocation) {
+	// inject opentracing ctx
+	currentSpan := opentracing.SpanFromContext(ctx)
+	if currentSpan != nil {
+		carrier := opentracing.TextMapCarrier(inv.Attachments())
+		err := opentracing.GlobalTracer().Inject(currentSpan.Context(), opentracing.TextMap, carrier)
+		if err != nil {
+			logger.Errorf("Could not inject the span context into attachments: %v", err)
+		}
+	}
+}
diff --git a/protocol/dubbo/dubbo_invoker_test.go b/protocol/dubbo/dubbo_invoker_test.go
index 7d60090e2d81bcb750d1e6d79a08059687c7937d..1a64301f8200a4264001284cca1af3f0f1e07814 100644
--- a/protocol/dubbo/dubbo_invoker_test.go
+++ b/protocol/dubbo/dubbo_invoker_test.go
@@ -18,12 +18,14 @@
 package dubbo
 
 import (
+	"context"
 	"sync"
 	"testing"
 	"time"
 )
 
 import (
+	"github.com/opentracing/opentracing-go"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -40,8 +42,8 @@ func TestDubboInvoker_Invoke(t *testing.T) {
 		pendingResponses: new(sync.Map),
 		conf:             *clientConf,
 		opts: Options{
-			ConnectTimeout: 3e9,
-			RequestTimeout: 6e9,
+			ConnectTimeout: 3 * time.Second,
+			RequestTimeout: 6 * time.Second,
 		},
 	}
 	c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL))
@@ -53,14 +55,14 @@ func TestDubboInvoker_Invoke(t *testing.T) {
 		invocation.WithReply(user), invocation.WithAttachments(map[string]string{"test_key": "test_value"}))
 
 	// Call
-	res := invoker.Invoke(inv)
+	res := invoker.Invoke(context.Background(), inv)
 	assert.NoError(t, res.Error())
 	assert.Equal(t, User{Id: "1", Name: "username"}, *res.Result().(*User))
 	assert.Equal(t, "test_value", res.Attachments()["test_key"]) // test attachments for request/response
 
 	// CallOneway
 	inv.SetAttachments(constant.ASYNC_KEY, "true")
-	res = invoker.Invoke(inv)
+	res = invoker.Invoke(context.Background(), inv)
 	assert.NoError(t, res.Error())
 
 	// AsyncCall
@@ -71,15 +73,20 @@ func TestDubboInvoker_Invoke(t *testing.T) {
 		assert.Equal(t, User{Id: "1", Name: "username"}, *r.Reply.(*Response).reply.(*User))
 		lock.Unlock()
 	})
-	res = invoker.Invoke(inv)
+	res = invoker.Invoke(context.Background(), inv)
 	assert.NoError(t, res.Error())
 
 	// Err_No_Reply
 	inv.SetAttachments(constant.ASYNC_KEY, "false")
 	inv.SetReply(nil)
-	res = invoker.Invoke(inv)
+	res = invoker.Invoke(context.Background(), inv)
 	assert.EqualError(t, res.Error(), "request need @response")
 
+	// testing appendCtx
+	span, ctx := opentracing.StartSpanFromContext(context.Background(), "TestOperation")
+	invoker.Invoke(ctx, inv)
+	span.Finish()
+
 	// destroy
 	lock.Lock()
 	proto.Destroy()
diff --git a/protocol/dubbo/dubbo_protocol.go b/protocol/dubbo/dubbo_protocol.go
index 59d1ea05160696754b46dfead5713684aa7a94f7..355dbc802488338ef4dbdd7290166038b312f183 100644
--- a/protocol/dubbo/dubbo_protocol.go
+++ b/protocol/dubbo/dubbo_protocol.go
@@ -19,17 +19,21 @@ package dubbo
 
 import (
 	"sync"
+	"time"
 )
 
 import (
 	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/config"
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// dubbo protocol constant
 const (
+	// DUBBO ...
 	DUBBO = "dubbo"
 )
 
@@ -41,12 +45,14 @@ var (
 	dubboProtocol *DubboProtocol
 )
 
+// DubboProtocol ...
 type DubboProtocol struct {
 	protocol.BaseProtocol
 	serverMap  map[string]*Server
 	serverLock sync.Mutex
 }
 
+// NewDubboProtocol ...
 func NewDubboProtocol() *DubboProtocol {
 	return &DubboProtocol{
 		BaseProtocol: protocol.NewBaseProtocol(),
@@ -54,6 +60,7 @@ func NewDubboProtocol() *DubboProtocol {
 	}
 }
 
+// Export ...
 func (dp *DubboProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	url := invoker.GetUrl()
 	serviceKey := url.ServiceKey()
@@ -66,16 +73,26 @@ func (dp *DubboProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	return exporter
 }
 
+// Refer ...
 func (dp *DubboProtocol) Refer(url common.URL) protocol.Invoker {
+	//default requestTimeout
+	var requestTimeout = config.GetConsumerConfig().RequestTimeout
+
+	requestTimeoutStr := url.GetParam(constant.TIMEOUT_KEY, config.GetConsumerConfig().Request_Timeout)
+	if t, err := time.ParseDuration(requestTimeoutStr); err == nil {
+		requestTimeout = t
+	}
+
 	invoker := NewDubboInvoker(url, NewClient(Options{
 		ConnectTimeout: config.GetConsumerConfig().ConnectTimeout,
-		RequestTimeout: config.GetConsumerConfig().RequestTimeout,
+		RequestTimeout: requestTimeout,
 	}))
 	dp.SetInvokers(invoker)
 	logger.Infof("Refer service: %s", url.String())
 	return invoker
 }
 
+// Destroy ...
 func (dp *DubboProtocol) Destroy() {
 	logger.Infof("DubboProtocol destroy.")
 
@@ -107,6 +124,7 @@ func (dp *DubboProtocol) openServer(url common.URL) {
 	}
 }
 
+// GetProtocol ...
 func GetProtocol() protocol.Protocol {
 	if dubboProtocol == nil {
 		dubboProtocol = NewDubboProtocol()
diff --git a/protocol/dubbo/dubbo_protocol_test.go b/protocol/dubbo/dubbo_protocol_test.go
index a6b0bc1df3cf2eb46e07c9dab149d04f62f78012..14f6868ad4a7f2bf6f549a2fbbce8234cbb4aa12 100644
--- a/protocol/dubbo/dubbo_protocol_test.go
+++ b/protocol/dubbo/dubbo_protocol_test.go
@@ -18,7 +18,6 @@
 package dubbo
 
 import (
-	"context"
 	"testing"
 )
 
@@ -36,10 +35,10 @@ func TestDubboProtocol_Export(t *testing.T) {
 	// Export
 	proto := GetProtocol()
 	srvConf = &ServerConfig{}
-	url, err := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
+	url, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
 		"side=provider&timeout=3000&timestamp=1556509797245")
 	assert.NoError(t, err)
 	exporter := proto.Export(protocol.NewBaseInvoker(url))
@@ -49,7 +48,7 @@ func TestDubboProtocol_Export(t *testing.T) {
 	assert.True(t, eq)
 
 	// second service: the same path and the different version
-	url2, err := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
+	url2, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
 		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
 		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
 		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
@@ -78,10 +77,10 @@ func TestDubboProtocol_Export(t *testing.T) {
 func TestDubboProtocol_Refer(t *testing.T) {
 	// Refer
 	proto := GetProtocol()
-	url, err := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
+	url, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
 		"side=provider&timeout=3000&timestamp=1556509797245")
 	assert.NoError(t, err)
 	clientConf = &ClientConfig{}
diff --git a/protocol/dubbo/listener.go b/protocol/dubbo/listener.go
index df9ab28e0e4b896b11b2345a83cae14401a70759..430c4e49d81d4d5d151a545e1a130fd4ac3fbdc5 100644
--- a/protocol/dubbo/listener.go
+++ b/protocol/dubbo/listener.go
@@ -18,15 +18,18 @@
 package dubbo
 
 import (
+	"context"
 	"fmt"
 	"net/url"
 	"sync"
+	"sync/atomic"
 	"time"
 )
 
 import (
 	"github.com/apache/dubbo-go-hessian2"
 	"github.com/dubbogo/getty"
+	"github.com/opentracing/opentracing-go"
 	perrors "github.com/pkg/errors"
 )
 
@@ -39,7 +42,10 @@ import (
 )
 
 // todo: WritePkg_Timeout will entry *.yml
-const WritePkg_Timeout = 5 * time.Second
+const (
+	// WritePkg_Timeout ...
+	WritePkg_Timeout = 5 * time.Second
+)
 
 var (
 	errTooManySessions = perrors.New("too many sessions")
@@ -50,33 +56,47 @@ type rpcSession struct {
 	reqNum  int32
 }
 
-////////////////////////////////////////////
+func (s *rpcSession) AddReqNum(num int32) {
+	atomic.AddInt32(&s.reqNum, num)
+}
+
+func (s *rpcSession) GetReqNum() int32 {
+	return atomic.LoadInt32(&s.reqNum)
+}
+
+// //////////////////////////////////////////
 // RpcClientHandler
-////////////////////////////////////////////
+// //////////////////////////////////////////
 
+// RpcClientHandler ...
 type RpcClientHandler struct {
 	conn *gettyRPCClient
 }
 
+// NewRpcClientHandler ...
 func NewRpcClientHandler(client *gettyRPCClient) *RpcClientHandler {
 	return &RpcClientHandler{conn: client}
 }
 
+// OnOpen ...
 func (h *RpcClientHandler) OnOpen(session getty.Session) error {
 	h.conn.addSession(session)
 	return nil
 }
 
+// OnError ...
 func (h *RpcClientHandler) OnError(session getty.Session, err error) {
 	logger.Infof("session{%s} got error{%v}, will be closed.", session.Stat(), err)
 	h.conn.removeSession(session)
 }
 
+// OnClose ...
 func (h *RpcClientHandler) OnClose(session getty.Session) {
 	logger.Infof("session{%s} is closing......", session.Stat())
 	h.conn.removeSession(session)
 }
 
+// OnMessage ...
 func (h *RpcClientHandler) OnMessage(session getty.Session, pkg interface{}) {
 	p, ok := pkg.(*DubboPackage)
 	if !ok {
@@ -85,11 +105,17 @@ func (h *RpcClientHandler) OnMessage(session getty.Session, pkg interface{}) {
 	}
 
 	if p.Header.Type&hessian.PackageHeartbeat != 0x00 {
-		logger.Debugf("get rpc heartbeat response{header: %#v, body: %#v}", p.Header, p.Body)
-		if p.Err != nil {
-			logger.Errorf("rpc heartbeat response{error: %#v}", p.Err)
+		if p.Header.Type&hessian.PackageResponse != 0x00 {
+			logger.Debugf("get rpc heartbeat response{header: %#v, body: %#v}", p.Header, p.Body)
+			if p.Err != nil {
+				logger.Errorf("rpc heartbeat response{error: %#v}", p.Err)
+			}
+			h.conn.pool.rpcClient.removePendingResponse(SequenceType(p.Header.ID))
+		} else {
+			logger.Debugf("get rpc heartbeat request{header: %#v, service: %#v, body: %#v}", p.Header, p.Service, p.Body)
+			p.Header.ResponseStatus = hessian.Response_OK
+			reply(session, p, hessian.PackageHeartbeat)
 		}
-		h.conn.pool.rpcClient.removePendingResponse(SequenceType(p.Header.ID))
 		return
 	}
 	logger.Debugf("get rpc response{header: %#v, body: %#v}", p.Header, p.Body)
@@ -114,6 +140,7 @@ func (h *RpcClientHandler) OnMessage(session getty.Session, pkg interface{}) {
 	}
 }
 
+// OnCron ...
 func (h *RpcClientHandler) OnCron(session getty.Session) {
 	rpcSession, err := h.conn.getClientRpcSession(session)
 	if err != nil {
@@ -131,10 +158,11 @@ func (h *RpcClientHandler) OnCron(session getty.Session) {
 	h.conn.pool.rpcClient.heartbeat(session)
 }
 
-////////////////////////////////////////////
+// //////////////////////////////////////////
 // RpcServerHandler
-////////////////////////////////////////////
+// //////////////////////////////////////////
 
+// RpcServerHandler ...
 type RpcServerHandler struct {
 	maxSessionNum  int
 	sessionTimeout time.Duration
@@ -142,6 +170,7 @@ type RpcServerHandler struct {
 	rwlock         sync.RWMutex
 }
 
+// NewRpcServerHandler ...
 func NewRpcServerHandler(maxSessionNum int, sessionTimeout time.Duration) *RpcServerHandler {
 	return &RpcServerHandler{
 		maxSessionNum:  maxSessionNum,
@@ -150,6 +179,7 @@ func NewRpcServerHandler(maxSessionNum int, sessionTimeout time.Duration) *RpcSe
 	}
 }
 
+// OnOpen ...
 func (h *RpcServerHandler) OnOpen(session getty.Session) error {
 	var err error
 	h.rwlock.RLock()
@@ -168,6 +198,7 @@ func (h *RpcServerHandler) OnOpen(session getty.Session) error {
 	return nil
 }
 
+// OnError ...
 func (h *RpcServerHandler) OnError(session getty.Session, err error) {
 	logger.Infof("session{%s} got error{%v}, will be closed.", session.Stat(), err)
 	h.rwlock.Lock()
@@ -175,6 +206,7 @@ func (h *RpcServerHandler) OnError(session getty.Session, err error) {
 	h.rwlock.Unlock()
 }
 
+// OnClose ...
 func (h *RpcServerHandler) OnClose(session getty.Session) {
 	logger.Infof("session{%s} is closing......", session.Stat())
 	h.rwlock.Lock()
@@ -182,6 +214,7 @@ func (h *RpcServerHandler) OnClose(session getty.Session) {
 	h.rwlock.Unlock()
 }
 
+// OnMessage ...
 func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
 	h.rwlock.Lock()
 	if _, ok := h.sessionMap[session]; ok {
@@ -199,7 +232,7 @@ func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
 	// heartbeat
 	if p.Header.Type&hessian.PackageHeartbeat != 0x00 {
 		logger.Debugf("get rpc heartbeat request{header: %#v, service: %#v, body: %#v}", p.Header, p.Service, p.Body)
-		h.reply(session, p, hessian.PackageHeartbeat)
+		reply(session, p, hessian.PackageHeartbeat)
 		return
 	}
 
@@ -226,7 +259,7 @@ func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
 			if !twoway {
 				return
 			}
-			h.reply(session, p, hessian.PackageResponse)
+			reply(session, p, hessian.PackageResponse)
 		}
 
 	}()
@@ -241,7 +274,7 @@ func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
 		logger.Errorf(err.Error())
 		p.Header.ResponseStatus = hessian.Response_OK
 		p.Body = err
-		h.reply(session, p, hessian.PackageResponse)
+		reply(session, p, hessian.PackageResponse)
 		return
 	}
 	invoker := exporter.(protocol.Exporter).GetInvoker()
@@ -252,7 +285,10 @@ func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
 
 		args := p.Body.(map[string]interface{})["args"].([]interface{})
 		inv := invocation.NewRPCInvocation(p.Service.Method, args, attachments)
-		result := invoker.Invoke(inv)
+
+		ctx := rebuildCtx(inv)
+
+		result := invoker.Invoke(ctx, inv)
 		if err := result.Error(); err != nil {
 			p.Header.ResponseStatus = hessian.Response_OK
 			p.Body = hessian.NewResponse(nil, err, result.Attachments())
@@ -266,9 +302,10 @@ func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
 	if !twoway {
 		return
 	}
-	h.reply(session, p, hessian.PackageResponse)
+	reply(session, p, hessian.PackageResponse)
 }
 
+// OnCron ...
 func (h *RpcServerHandler) OnCron(session getty.Session) {
 	var (
 		flag   bool
@@ -294,7 +331,22 @@ func (h *RpcServerHandler) OnCron(session getty.Session) {
 	}
 }
 
-func (h *RpcServerHandler) reply(session getty.Session, req *DubboPackage, tp hessian.PackageType) {
+// rebuildCtx rebuild the context by attachment.
+// Once we decided to transfer more context's key-value, we should change this.
+// now we only support rebuild the tracing context
+func rebuildCtx(inv *invocation.RPCInvocation) context.Context {
+	ctx := context.Background()
+
+	// actually, if user do not use any opentracing framework, the err will not be nil.
+	spanCtx, err := opentracing.GlobalTracer().Extract(opentracing.TextMap,
+		opentracing.TextMapCarrier(inv.Attachments()))
+	if err == nil {
+		ctx = context.WithValue(ctx, constant.TRACING_REMOTE_SPAN_CTX, spanCtx)
+	}
+	return ctx
+}
+
+func reply(session getty.Session, req *DubboPackage, tp hessian.PackageType) {
 	resp := &DubboPackage{
 		Header: hessian.DubboHeader{
 			SerialID:       req.Header.SerialID,
diff --git a/protocol/dubbo/listener_test.go b/protocol/dubbo/listener_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5f809814607558650e09934019db96dbb2ceeeae
--- /dev/null
+++ b/protocol/dubbo/listener_test.go
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dubbo
+
+import (
+	"testing"
+)
+
+import (
+	"github.com/opentracing/opentracing-go"
+	"github.com/opentracing/opentracing-go/mocktracer"
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+// test rebuild the ctx
+func TestRebuildCtx(t *testing.T) {
+	opentracing.SetGlobalTracer(mocktracer.New())
+	attach := make(map[string]string, 10)
+	attach[constant.VERSION_KEY] = "1.0"
+	attach[constant.GROUP_KEY] = "MyGroup"
+	inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach)
+
+	// attachment doesn't contains any tracing key-value pair,
+	ctx := rebuildCtx(inv)
+	assert.NotNil(t, ctx)
+	assert.Nil(t, ctx.Value(constant.TRACING_REMOTE_SPAN_CTX))
+
+	span, ctx := opentracing.StartSpanFromContext(ctx, "Test-Client")
+
+	opentracing.GlobalTracer().Inject(span.Context(), opentracing.TextMap,
+		opentracing.TextMapCarrier(inv.Attachments()))
+	// rebuild the context success
+	inv = invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach)
+	ctx = rebuildCtx(inv)
+	span.Finish()
+	assert.NotNil(t, ctx)
+	assert.NotNil(t, ctx.Value(constant.TRACING_REMOTE_SPAN_CTX))
+}
diff --git a/protocol/dubbo/pool.go b/protocol/dubbo/pool.go
index b5bf040c67c2e0071222466e59db4de67d9e1ca2..9d381585b56ec439f8ebb8938109baf47bb502b2 100644
--- a/protocol/dubbo/pool.go
+++ b/protocol/dubbo/pool.go
@@ -154,11 +154,11 @@ func (c *gettyRPCClient) addSession(session getty.Session) {
 	}
 
 	c.lock.Lock()
+	defer c.lock.Unlock()
 	if c.sessions == nil {
 		c.sessions = make([]*rpcSession, 0, 16)
 	}
 	c.sessions = append(c.sessions, &rpcSession{session: session})
-	c.lock.Unlock()
 }
 
 func (c *gettyRPCClient) removeSession(session getty.Session) {
@@ -166,21 +166,27 @@ func (c *gettyRPCClient) removeSession(session getty.Session) {
 		return
 	}
 
-	c.lock.Lock()
-	defer c.lock.Unlock()
-	if c.sessions == nil {
-		return
-	}
+	var removeFlag bool
+	func() {
+		c.lock.Lock()
+		defer c.lock.Unlock()
+		if c.sessions == nil {
+			return
+		}
 
-	for i, s := range c.sessions {
-		if s.session == session {
-			c.sessions = append(c.sessions[:i], c.sessions[i+1:]...)
-			logger.Debugf("delete session{%s}, its index{%d}", session.Stat(), i)
-			break
+		for i, s := range c.sessions {
+			if s.session == session {
+				c.sessions = append(c.sessions[:i], c.sessions[i+1:]...)
+				logger.Debugf("delete session{%s}, its index{%d}", session.Stat(), i)
+				break
+			}
 		}
-	}
-	logger.Infof("after remove session{%s}, left session number:%d", session.Stat(), len(c.sessions))
-	if len(c.sessions) == 0 {
+		logger.Infof("after remove session{%s}, left session number:%d", session.Stat(), len(c.sessions))
+		if len(c.sessions) == 0 {
+			removeFlag = true
+		}
+	}()
+	if removeFlag {
 		c.pool.safeRemove(c)
 		c.close()
 	}
@@ -190,17 +196,24 @@ func (c *gettyRPCClient) updateSession(session getty.Session) {
 	if session == nil {
 		return
 	}
-	c.lock.Lock()
-	defer c.lock.Unlock()
-	if c.sessions == nil {
-		return
-	}
 
-	for i, s := range c.sessions {
-		if s.session == session {
-			c.sessions[i].reqNum++
-			break
+	var rs *rpcSession
+	func() {
+		c.lock.RLock()
+		defer c.lock.RUnlock()
+		if c.sessions == nil {
+			return
+		}
+
+		for i, s := range c.sessions {
+			if s.session == session {
+				rs = c.sessions[i]
+				break
+			}
 		}
+	}()
+	if rs != nil {
+		rs.AddReqNum(1)
 	}
 }
 
@@ -238,28 +251,42 @@ func (c *gettyRPCClient) isAvailable() bool {
 func (c *gettyRPCClient) close() error {
 	closeErr := perrors.Errorf("close gettyRPCClient{%#v} again", c)
 	c.once.Do(func() {
-		c.gettyClient.Close()
-		c.gettyClient = nil
-		for _, s := range c.sessions {
-			logger.Infof("close client session{%s, last active:%s, request number:%d}",
-				s.session.Stat(), s.session.GetActive().String(), s.reqNum)
-			s.session.Close()
-		}
-		c.sessions = c.sessions[:0]
+		var (
+			gettyClient getty.Client
+			sessions    []*rpcSession
+		)
+		func() {
+			c.lock.Lock()
+			defer c.lock.Unlock()
+
+			gettyClient = c.gettyClient
+			c.gettyClient = nil
+
+			sessions = make([]*rpcSession, 0, len(c.sessions))
+			for _, s := range c.sessions {
+				sessions = append(sessions, s)
+			}
+			c.sessions = c.sessions[:0]
+		}()
 
 		c.updateActive(0)
+
+		go func() {
+			if gettyClient != nil {
+				gettyClient.Close()
+			}
+			for _, s := range sessions {
+				logger.Infof("close client session{%s, last active:%s, request number:%d}",
+					s.session.Stat(), s.session.GetActive().String(), s.GetReqNum())
+				s.session.Close()
+			}
+		}()
+
 		closeErr = nil
 	})
 	return closeErr
 }
 
-func (c *gettyRPCClient) safeClose() error {
-	c.lock.Lock()
-	defer c.lock.Unlock()
-
-	return c.close()
-}
-
 type gettyRPCClientPool struct {
 	rpcClient *Client
 	size      int   // size of []*gettyRPCClient
@@ -284,37 +311,35 @@ func (p *gettyRPCClientPool) close() {
 	p.conns = nil
 	p.Unlock()
 	for _, conn := range conns {
-		conn.safeClose()
+		conn.close()
 	}
 }
 
 func (p *gettyRPCClientPool) getGettyRpcClient(protocol, addr string) (*gettyRPCClient, error) {
-	var (
-		conn *gettyRPCClient
-		err  error
-	)
-	if conn, err = p.selectGettyRpcClient(protocol, addr); err == nil && conn == nil {
+	conn, err := p.get()
+	if err == nil && conn == nil {
 		// create new conn
 		return newGettyRPCClientConn(p, protocol, addr)
 	}
 	return conn, err
 }
-func (p *gettyRPCClientPool) selectGettyRpcClient(protocol, addr string) (*gettyRPCClient, error) {
+
+func (p *gettyRPCClientPool) get() (*gettyRPCClient, error) {
+	now := time.Now().Unix()
+
 	p.Lock()
 	defer p.Unlock()
 	if p.conns == nil {
 		return nil, errClientPoolClosed
 	}
 
-	now := time.Now().Unix()
-
 	for len(p.conns) > 0 {
 		conn := p.conns[len(p.conns)-1]
 		p.conns = p.conns[:len(p.conns)-1]
 
 		if d := now - conn.getActive(); d > p.ttl {
 			p.remove(conn)
-			conn.safeClose()
+			go conn.close()
 			continue
 		}
 		conn.updateActive(now) //update active time
@@ -322,13 +347,9 @@ func (p *gettyRPCClientPool) selectGettyRpcClient(protocol, addr string) (*getty
 	}
 	return nil, nil
 }
-func (p *gettyRPCClientPool) release(conn *gettyRPCClient, err error) {
-	if conn == nil || conn.getActive() == 0 {
-		return
-	}
 
-	if err != nil {
-		conn.safeClose()
+func (p *gettyRPCClientPool) put(conn *gettyRPCClient) {
+	if conn == nil || conn.getActive() == 0 {
 		return
 	}
 
@@ -339,10 +360,17 @@ func (p *gettyRPCClientPool) release(conn *gettyRPCClient, err error) {
 		return
 	}
 
+	// check whether @conn has existed in p.conns or not.
+	for i := range p.conns {
+		if p.conns[i] == conn {
+			return
+		}
+	}
+
 	if len(p.conns) >= p.size {
 		// delete @conn from client pool
-		p.remove(conn)
-		conn.safeClose()
+		// p.remove(conn)
+		conn.close()
 		return
 	}
 	p.conns = append(p.conns, conn)
diff --git a/protocol/dubbo/readwriter.go b/protocol/dubbo/readwriter.go
index 930382cca8bac6955b516a88e93ce26d73e235fe..b5c4f509190dbdc85825ad424656240b234786df 100644
--- a/protocol/dubbo/readwriter.go
+++ b/protocol/dubbo/readwriter.go
@@ -38,10 +38,12 @@ import (
 // RpcClientPackageHandler
 ////////////////////////////////////////////
 
+// RpcClientPackageHandler ...
 type RpcClientPackageHandler struct {
 	client *Client
 }
 
+// NewRpcClientPackageHandler ...
 func NewRpcClientPackageHandler(client *Client) *RpcClientPackageHandler {
 	return &RpcClientPackageHandler{client: client}
 }
@@ -62,8 +64,10 @@ func (p *RpcClientPackageHandler) Read(ss getty.Session, data []byte) (interface
 		return nil, 0, perrors.WithStack(err)
 	}
 
-	pkg.Err = pkg.Body.(*hessian.Response).Exception
-	pkg.Body = NewResponse(pkg.Body.(*hessian.Response).RspObj, pkg.Body.(*hessian.Response).Attachments)
+	if pkg.Header.Type&hessian.PackageRequest == 0x00 {
+		pkg.Err = pkg.Body.(*hessian.Response).Exception
+		pkg.Body = NewResponse(pkg.Body.(*hessian.Response).RspObj, pkg.Body.(*hessian.Response).Attachments)
+	}
 
 	return pkg, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil
 }
@@ -92,6 +96,7 @@ var (
 	rpcServerPkgHandler = &RpcServerPackageHandler{}
 )
 
+// RpcServerPackageHandler ...
 type RpcServerPackageHandler struct{}
 
 func (p *RpcServerPackageHandler) Read(ss getty.Session, data []byte) (interface{}, int, error) {
diff --git a/protocol/dubbo/server.go b/protocol/dubbo/server.go
index 648c9f8aa8d24a321bfda85279a6470c745dbfa1..bd2b37b7a9f055745e183524d19a442af03360f4 100644
--- a/protocol/dubbo/server.go
+++ b/protocol/dubbo/server.go
@@ -74,6 +74,7 @@ func init() {
 	SetServerGrpool()
 }
 
+// SetServerConfig ...
 func SetServerConfig(s ServerConfig) {
 	srvConf = &s
 	err := srvConf.CheckValidity()
@@ -84,10 +85,12 @@ func SetServerConfig(s ServerConfig) {
 	SetServerGrpool()
 }
 
+// GetServerConfig ...
 func GetServerConfig() ServerConfig {
 	return *srvConf
 }
 
+// SetServerGrpool ...
 func SetServerGrpool() {
 	if srvConf.GrPoolSize > 1 {
 		srvGrpool = gxsync.NewTaskPool(gxsync.WithTaskPoolTaskPoolSize(srvConf.GrPoolSize), gxsync.WithTaskPoolTaskQueueLength(srvConf.QueueLen),
@@ -95,12 +98,14 @@ func SetServerGrpool() {
 	}
 }
 
+// Server ...
 type Server struct {
 	conf       ServerConfig
 	tcpServer  getty.Server
 	rpcHandler *RpcServerHandler
 }
 
+// NewServer ...
 func NewServer() *Server {
 
 	s := &Server{
@@ -151,6 +156,7 @@ func (s *Server) newSession(session getty.Session) error {
 	return nil
 }
 
+// Start ...
 func (s *Server) Start(url common.URL) {
 	var (
 		addr      string
@@ -167,6 +173,7 @@ func (s *Server) Start(url common.URL) {
 
 }
 
+// Stop ...
 func (s *Server) Stop() {
 	s.tcpServer.Close()
 }
diff --git a/protocol/grpc/client.go b/protocol/grpc/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..d35a2c770cd8b9bda805715889791ccf53c562db
--- /dev/null
+++ b/protocol/grpc/client.go
@@ -0,0 +1,63 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package grpc
+
+import (
+	"reflect"
+)
+
+import (
+	"google.golang.org/grpc"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/config"
+)
+
+// Client ...
+type Client struct {
+	*grpc.ClientConn
+	invoker reflect.Value
+}
+
+// NewClient ...
+func NewClient(url common.URL) *Client {
+	conn, err := grpc.Dial(url.Location, grpc.WithInsecure(), grpc.WithBlock())
+	if err != nil {
+		panic(err)
+	}
+
+	key := url.GetParam(constant.BEAN_NAME_KEY, "")
+	impl := config.GetConsumerService(key)
+	invoker := getInvoker(impl, conn)
+
+	return &Client{
+		ClientConn: conn,
+		invoker:    reflect.ValueOf(invoker),
+	}
+}
+
+func getInvoker(impl interface{}, conn *grpc.ClientConn) interface{} {
+	in := []reflect.Value{}
+	in = append(in, reflect.ValueOf(conn))
+	method := reflect.ValueOf(impl).MethodByName("GetDubboStub")
+	res := method.Call(in)
+	return res[0].Interface()
+}
diff --git a/protocol/grpc/client_test.go b/protocol/grpc/client_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..56ec766f70da93bcddbcff13667a34c39deffe06
--- /dev/null
+++ b/protocol/grpc/client_test.go
@@ -0,0 +1,53 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package grpc
+
+import (
+	"reflect"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+	"google.golang.org/grpc"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol/grpc/internal"
+)
+
+func TestGetInvoker(t *testing.T) {
+	var conn *grpc.ClientConn
+	var impl *internal.GrpcGreeterImpl
+	invoker := getInvoker(impl, conn)
+
+	i := reflect.TypeOf(invoker)
+	expected := reflect.TypeOf(internal.NewGreeterClient(nil))
+	assert.Equal(t, i, expected)
+}
+
+func TestNewClient(t *testing.T) {
+	go internal.InitGrpcServer()
+	defer internal.ShutdownGrpcServer()
+
+	url, err := common.NewURL("grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown&registry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider&timestamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!")
+	assert.Nil(t, err)
+	cli := NewClient(url)
+	assert.NotNil(t, cli)
+}
diff --git a/protocol/grpc/common_test.go b/protocol/grpc/common_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..3d0823b1061a61cfa391358e270c8b9081e9031c
--- /dev/null
+++ b/protocol/grpc/common_test.go
@@ -0,0 +1,114 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package grpc
+
+import (
+	"context"
+	"fmt"
+)
+
+import (
+	native_grpc "google.golang.org/grpc"
+)
+
+import (
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/grpc/internal"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+// userd grpc-dubbo biz service
+func addService() {
+	config.SetProviderService(newGreeterProvider())
+}
+
+type greeterProvider struct {
+	*greeterProviderBase
+}
+
+func newGreeterProvider() *greeterProvider {
+	return &greeterProvider{
+		greeterProviderBase: &greeterProviderBase{},
+	}
+}
+
+func (g *greeterProvider) SayHello(ctx context.Context, req *internal.HelloRequest) (reply *internal.HelloReply, err error) {
+	fmt.Printf("req: %v", req)
+	return &internal.HelloReply{Message: "this is message from reply"}, nil
+}
+
+func (g *greeterProvider) Reference() string {
+	return "GrpcGreeterImpl"
+}
+
+// code generated by greeter.go
+type greeterProviderBase struct {
+	proxyImpl protocol.Invoker
+}
+
+func (g *greeterProviderBase) SetProxyImpl(impl protocol.Invoker) {
+	g.proxyImpl = impl
+}
+
+func (g *greeterProviderBase) GetProxyImpl() protocol.Invoker {
+	return g.proxyImpl
+}
+
+func (g *greeterProviderBase) ServiceDesc() *native_grpc.ServiceDesc {
+	return &native_grpc.ServiceDesc{
+		ServiceName: "helloworld.Greeter",
+		HandlerType: (*internal.GreeterServer)(nil),
+		Methods: []native_grpc.MethodDesc{
+			{
+				MethodName: "SayHello",
+				Handler:    dubboGreeterSayHelloHandler,
+			},
+		},
+		Streams:  []native_grpc.StreamDesc{},
+		Metadata: "helloworld.proto",
+	}
+}
+
+func dubboGreeterSayHelloHandler(srv interface{}, ctx context.Context,
+	dec func(interface{}) error, interceptor native_grpc.UnaryServerInterceptor) (interface{}, error) {
+
+	in := new(internal.HelloRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	base := srv.(DubboGrpcService)
+
+	args := []interface{}{}
+	args = append(args, in)
+	invo := invocation.NewRPCInvocation("SayHello", args, nil)
+
+	if interceptor == nil {
+		result := base.GetProxyImpl().Invoke(context.Background(), invo)
+		return result.Result(), result.Error()
+	}
+	info := &native_grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/helloworld.Greeter/SayHello",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		result := base.GetProxyImpl().Invoke(context.Background(), invo)
+		return result.Result(), result.Error()
+	}
+	return interceptor(ctx, in, info, handler)
+}
diff --git a/protocol/grpc/grpc_exporter.go b/protocol/grpc/grpc_exporter.go
new file mode 100644
index 0000000000000000000000000000000000000000..3c38ef974ca22a582ce83102718d01a8edd4258f
--- /dev/null
+++ b/protocol/grpc/grpc_exporter.go
@@ -0,0 +1,51 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package grpc
+
+import (
+	"sync"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+// GrpcExporter ...
+type GrpcExporter struct {
+	*protocol.BaseExporter
+}
+
+// NewGrpcExporter ...
+func NewGrpcExporter(key string, invoker protocol.Invoker, exporterMap *sync.Map) *GrpcExporter {
+	return &GrpcExporter{
+		BaseExporter: protocol.NewBaseExporter(key, invoker, exporterMap),
+	}
+}
+
+// Unexport ...
+func (gg *GrpcExporter) Unexport() {
+	serviceId := gg.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "")
+	gg.BaseExporter.Unexport()
+	err := common.ServiceMap.UnRegister(GRPC, serviceId)
+	if err != nil {
+		logger.Errorf("[GrpcExporter.Unexport] error: %v", err)
+	}
+}
diff --git a/protocol/grpc/grpc_invoker.go b/protocol/grpc/grpc_invoker.go
new file mode 100644
index 0000000000000000000000000000000000000000..26bc86f3aa46c8048b16284bd61cb5d9fb4664f9
--- /dev/null
+++ b/protocol/grpc/grpc_invoker.go
@@ -0,0 +1,104 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package grpc
+
+import (
+	"context"
+	"reflect"
+	"sync"
+)
+
+import (
+	"github.com/pkg/errors"
+	"google.golang.org/grpc/connectivity"
+)
+
+import (
+	hessian2 "github.com/apache/dubbo-go-hessian2"
+
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+// ErrNoReply ...
+var ErrNoReply = errors.New("request need @response")
+
+// GrpcInvoker ...
+type GrpcInvoker struct {
+	protocol.BaseInvoker
+	quitOnce sync.Once
+	client   *Client
+}
+
+// NewGrpcInvoker ...
+func NewGrpcInvoker(url common.URL, client *Client) *GrpcInvoker {
+	return &GrpcInvoker{
+		BaseInvoker: *protocol.NewBaseInvoker(url),
+		client:      client,
+	}
+}
+
+// Invoke ...
+func (gi *GrpcInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
+	var (
+		result protocol.RPCResult
+	)
+
+	if invocation.Reply() == nil {
+		result.Err = ErrNoReply
+	}
+
+	in := []reflect.Value{}
+	in = append(in, reflect.ValueOf(context.Background()))
+	in = append(in, invocation.ParameterValues()...)
+
+	methodName := invocation.MethodName()
+	method := gi.client.invoker.MethodByName(methodName)
+	res := method.Call(in)
+
+	result.Rest = res[0]
+	// check err
+	if !res[1].IsNil() {
+		result.Err = res[1].Interface().(error)
+	} else {
+		_ = hessian2.ReflectResponse(res[0], invocation.Reply())
+	}
+
+	return &result
+}
+
+// IsAvailable ...
+func (gi *GrpcInvoker) IsAvailable() bool {
+	return gi.BaseInvoker.IsAvailable() && gi.client.GetState() != connectivity.Shutdown
+}
+
+// IsDestroyed ...
+func (gi *GrpcInvoker) IsDestroyed() bool {
+	return gi.BaseInvoker.IsDestroyed() && gi.client.GetState() == connectivity.Shutdown
+}
+
+// Destroy ...
+func (gi *GrpcInvoker) Destroy() {
+	gi.quitOnce.Do(func() {
+		gi.BaseInvoker.Destroy()
+
+		if gi.client != nil {
+			_ = gi.client.Close()
+		}
+	})
+}
diff --git a/protocol/grpc/grpc_invoker_test.go b/protocol/grpc/grpc_invoker_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..368c1392ec03af310f93e8fc2173b8354975c99e
--- /dev/null
+++ b/protocol/grpc/grpc_invoker_test.go
@@ -0,0 +1,56 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package grpc
+
+import (
+	"context"
+	"reflect"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol/grpc/internal"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestInvoke(t *testing.T) {
+	go internal.InitGrpcServer()
+	defer internal.ShutdownGrpcServer()
+
+	url, err := common.NewURL("grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown&registry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider&timestamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!")
+	assert.Nil(t, err)
+
+	cli := NewClient(url)
+
+	invoker := NewGrpcInvoker(url, cli)
+
+	args := []reflect.Value{}
+	args = append(args, reflect.ValueOf(&internal.HelloRequest{Name: "request name"}))
+	bizReply := &internal.HelloReply{}
+	invo := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("SayHello"),
+		invocation.WithParameterValues(args), invocation.WithReply(bizReply))
+	res := invoker.Invoke(context.Background(), invo)
+	assert.Nil(t, res.Error())
+	assert.NotNil(t, res.Result())
+	assert.Equal(t, "Hello request name", bizReply.Message)
+}
diff --git a/protocol/grpc/grpc_protocol.go b/protocol/grpc/grpc_protocol.go
new file mode 100644
index 0000000000000000000000000000000000000000..0f5625c152cc366289143b8a29d11cafb513b2f2
--- /dev/null
+++ b/protocol/grpc/grpc_protocol.go
@@ -0,0 +1,113 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package grpc
+
+import (
+	"sync"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+const (
+	// GRPC module name
+	GRPC = "grpc"
+)
+
+func init() {
+	extension.SetProtocol(GRPC, GetProtocol)
+}
+
+var grpcProtocol *GrpcProtocol
+
+// GrpcProtocol ...
+type GrpcProtocol struct {
+	protocol.BaseProtocol
+	serverMap  map[string]*Server
+	serverLock sync.Mutex
+}
+
+// NewGRPCProtocol ...
+func NewGRPCProtocol() *GrpcProtocol {
+	return &GrpcProtocol{
+		BaseProtocol: protocol.NewBaseProtocol(),
+		serverMap:    make(map[string]*Server),
+	}
+}
+
+// Export ...
+func (gp *GrpcProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
+	url := invoker.GetUrl()
+	serviceKey := url.ServiceKey()
+	exporter := NewGrpcExporter(serviceKey, invoker, gp.ExporterMap())
+	gp.SetExporterMap(serviceKey, exporter)
+	logger.Infof("Export service: %s", url.String())
+	gp.openServer(url)
+	return exporter
+}
+
+func (gp *GrpcProtocol) openServer(url common.URL) {
+	_, ok := gp.serverMap[url.Location]
+	if !ok {
+		_, ok := gp.ExporterMap().Load(url.ServiceKey())
+		if !ok {
+			panic("[GrpcProtocol]" + url.Key() + "is not existing")
+		}
+
+		gp.serverLock.Lock()
+		_, ok = gp.serverMap[url.Location]
+		if !ok {
+			srv := NewServer()
+			gp.serverMap[url.Location] = srv
+			srv.Start(url)
+		}
+		gp.serverLock.Unlock()
+	}
+}
+
+// Refer ...
+func (gp *GrpcProtocol) Refer(url common.URL) protocol.Invoker {
+	invoker := NewGrpcInvoker(url, NewClient(url))
+	gp.SetInvokers(invoker)
+	logger.Infof("Refer service: %s", url.String())
+	return invoker
+}
+
+// Destroy ...
+func (gp *GrpcProtocol) Destroy() {
+	logger.Infof("GrpcProtocol destroy.")
+
+	gp.BaseProtocol.Destroy()
+
+	for key, server := range gp.serverMap {
+		delete(gp.serverMap, key)
+		server.Stop()
+	}
+}
+
+// GetProtocol ...
+func GetProtocol() protocol.Protocol {
+	if grpcProtocol == nil {
+		grpcProtocol = NewGRPCProtocol()
+	}
+	return grpcProtocol
+}
diff --git a/protocol/grpc/grpc_protocol_test.go b/protocol/grpc/grpc_protocol_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..d0206a0fd953e40a478c26a2298f4889d8f72771
--- /dev/null
+++ b/protocol/grpc/grpc_protocol_test.go
@@ -0,0 +1,84 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package grpc
+
+import (
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/grpc/internal"
+)
+
+func TestGrpcProtocol_Export(t *testing.T) {
+	// Export
+	addService()
+
+	proto := GetProtocol()
+	url, err := common.NewURL("grpc://127.0.0.1:40000/GrpcGreeterImpl?accesslog=&app.version=0.0.1&application=BDTService&bean.name=GrpcGreeterImpl&cluster=failover&environment=dev&execute.limit=&execute.limit.rejected.handler=&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&timestamp=1576923717&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100")
+	assert.NoError(t, err)
+	exporter := proto.Export(protocol.NewBaseInvoker(url))
+	time.Sleep(time.Second)
+
+	// make sure url
+	eq := exporter.GetInvoker().GetUrl().URLEqual(url)
+	assert.True(t, eq)
+
+	// make sure exporterMap after 'Unexport'
+	_, ok := proto.(*GrpcProtocol).ExporterMap().Load(url.ServiceKey())
+	assert.True(t, ok)
+	exporter.Unexport()
+	_, ok = proto.(*GrpcProtocol).ExporterMap().Load(url.ServiceKey())
+	assert.False(t, ok)
+
+	// make sure serverMap after 'Destroy'
+	_, ok = proto.(*GrpcProtocol).serverMap[url.Location]
+	assert.True(t, ok)
+	proto.Destroy()
+	_, ok = proto.(*GrpcProtocol).serverMap[url.Location]
+	assert.False(t, ok)
+}
+
+func TestGrpcProtocol_Refer(t *testing.T) {
+	go internal.InitGrpcServer()
+	defer internal.ShutdownGrpcServer()
+	time.Sleep(time.Second)
+
+	proto := GetProtocol()
+	url, err := common.NewURL("grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown&registry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider&timestamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!")
+	assert.NoError(t, err)
+	invoker := proto.Refer(url)
+
+	// make sure url
+	eq := invoker.GetUrl().URLEqual(url)
+	assert.True(t, eq)
+
+	// make sure invokers after 'Destroy'
+	invokersLen := len(proto.(*GrpcProtocol).Invokers())
+	assert.Equal(t, 1, invokersLen)
+	proto.Destroy()
+	invokersLen = len(proto.(*GrpcProtocol).Invokers())
+	assert.Equal(t, 0, invokersLen)
+}
diff --git a/protocol/grpc/internal/client.go b/protocol/grpc/internal/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..d236e3046a90e9179fba07a0be5edb07f8c2a3e8
--- /dev/null
+++ b/protocol/grpc/internal/client.go
@@ -0,0 +1,50 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package internal
+
+import (
+	"context"
+)
+
+import (
+	"google.golang.org/grpc"
+)
+
+import (
+	"github.com/apache/dubbo-go/config"
+)
+
+func init() {
+	config.SetConsumerService(&GrpcGreeterImpl{})
+}
+
+// GrpcGreeterImpl
+//used for dubbo-grpc biz client
+type GrpcGreeterImpl struct {
+	SayHello func(ctx context.Context, in *HelloRequest, out *HelloReply) error
+}
+
+// Reference ...
+func (u *GrpcGreeterImpl) Reference() string {
+	return "GrpcGreeterImpl"
+}
+
+// GetDubboStub ...
+func (u *GrpcGreeterImpl) GetDubboStub(cc *grpc.ClientConn) GreeterClient {
+	return NewGreeterClient(cc)
+}
diff --git a/protocol/grpc/internal/doc.go b/protocol/grpc/internal/doc.go
new file mode 100644
index 0000000000000000000000000000000000000000..f2ef2ebd5e41980e1e1f1b0071ca7bb3885539f7
--- /dev/null
+++ b/protocol/grpc/internal/doc.go
@@ -0,0 +1,19 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// just for test, never use internal for production.
+package internal
diff --git a/protocol/grpc/internal/helloworld.pb.go b/protocol/grpc/internal/helloworld.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..79b74ac65011208ae74f989cf86e4e6f9f446015
--- /dev/null
+++ b/protocol/grpc/internal/helloworld.pb.go
@@ -0,0 +1,227 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: helloworld.proto
+
+package internal
+
+import (
+	"context"
+	"fmt"
+	"math"
+
+	"github.com/golang/protobuf/proto"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+// The request message containing the user's name.
+type HelloRequest struct {
+	Name                 string   `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *HelloRequest) Reset()         { *m = HelloRequest{} }
+func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
+func (*HelloRequest) ProtoMessage()    {}
+func (*HelloRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_17b8c58d586b62f2, []int{0}
+}
+
+func (m *HelloRequest) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_HelloRequest.Unmarshal(m, b)
+}
+func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic)
+}
+func (m *HelloRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_HelloRequest.Merge(m, src)
+}
+func (m *HelloRequest) XXX_Size() int {
+	return xxx_messageInfo_HelloRequest.Size(m)
+}
+func (m *HelloRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_HelloRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_HelloRequest proto.InternalMessageInfo
+
+func (m *HelloRequest) GetName() string {
+	if m != nil {
+		return m.Name
+	}
+	return ""
+}
+
+// The response message containing the greetings
+type HelloReply struct {
+	Message              string   `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *HelloReply) Reset()         { *m = HelloReply{} }
+func (m *HelloReply) String() string { return proto.CompactTextString(m) }
+func (*HelloReply) ProtoMessage()    {}
+func (*HelloReply) Descriptor() ([]byte, []int) {
+	return fileDescriptor_17b8c58d586b62f2, []int{1}
+}
+
+func (m *HelloReply) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_HelloReply.Unmarshal(m, b)
+}
+func (m *HelloReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_HelloReply.Marshal(b, m, deterministic)
+}
+func (m *HelloReply) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_HelloReply.Merge(m, src)
+}
+func (m *HelloReply) XXX_Size() int {
+	return xxx_messageInfo_HelloReply.Size(m)
+}
+func (m *HelloReply) XXX_DiscardUnknown() {
+	xxx_messageInfo_HelloReply.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_HelloReply proto.InternalMessageInfo
+
+func (m *HelloReply) GetMessage() string {
+	if m != nil {
+		return m.Message
+	}
+	return ""
+}
+
+func init() {
+	proto.RegisterType((*HelloRequest)(nil), "helloworld.HelloRequest")
+	proto.RegisterType((*HelloReply)(nil), "helloworld.HelloReply")
+}
+
+func init() { proto.RegisterFile("helloworld.proto", fileDescriptor_17b8c58d586b62f2) }
+
+var fileDescriptor_17b8c58d586b62f2 = []byte{
+	// 175 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xc8, 0x48, 0xcd, 0xc9,
+	0xc9, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x42, 0x88,
+	0x28, 0x29, 0x71, 0xf1, 0x78, 0x80, 0x78, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x42,
+	0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0xb6, 0x92,
+	0x1a, 0x17, 0x17, 0x54, 0x4d, 0x41, 0x4e, 0xa5, 0x90, 0x04, 0x17, 0x7b, 0x6e, 0x6a, 0x71, 0x71,
+	0x62, 0x3a, 0x4c, 0x11, 0x8c, 0x6b, 0xe4, 0xc9, 0xc5, 0xee, 0x5e, 0x94, 0x9a, 0x5a, 0x92, 0x5a,
+	0x24, 0x64, 0xc7, 0xc5, 0x11, 0x9c, 0x58, 0x09, 0xd6, 0x25, 0x24, 0xa1, 0x87, 0xe4, 0x02, 0x64,
+	0xcb, 0xa4, 0xc4, 0xb0, 0xc8, 0x14, 0xe4, 0x54, 0x2a, 0x31, 0x38, 0x19, 0x70, 0x49, 0x67, 0xe6,
+	0xeb, 0xa5, 0x17, 0x15, 0x24, 0xeb, 0xa5, 0x56, 0x24, 0xe6, 0x16, 0xe4, 0xa4, 0x16, 0x23, 0xa9,
+	0x75, 0xe2, 0x07, 0x2b, 0x0e, 0x07, 0xb1, 0x03, 0x40, 0x5e, 0x0a, 0x60, 0x4c, 0x62, 0x03, 0xfb,
+	0xcd, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x0f, 0xb7, 0xcd, 0xf2, 0xef, 0x00, 0x00, 0x00,
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion4
+
+// GreeterClient is the client API for Greeter service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type GreeterClient interface {
+	// Sends a greeting
+	SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
+}
+
+type greeterClient struct {
+	cc *grpc.ClientConn
+}
+
+func NewGreeterClient(cc *grpc.ClientConn) GreeterClient {
+	return &greeterClient{cc}
+}
+
+func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
+	out := new(HelloReply)
+	err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// GreeterServer is the server API for Greeter service.
+type GreeterServer interface {
+	// Sends a greeting
+	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
+}
+
+// UnimplementedGreeterServer can be embedded to have forward compatible implementations.
+type UnimplementedGreeterServer struct {
+}
+
+func (*UnimplementedGreeterServer) SayHello(ctx context.Context, req *HelloRequest) (*HelloReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
+}
+
+func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
+	s.RegisterService(&_Greeter_serviceDesc, srv)
+}
+
+func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(HelloRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(GreeterServer).SayHello(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/helloworld.Greeter/SayHello",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _Greeter_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "helloworld.Greeter",
+	HandlerType: (*GreeterServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "SayHello",
+			Handler:    _Greeter_SayHello_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "helloworld.proto",
+}
diff --git a/protocol/grpc/internal/server.go b/protocol/grpc/internal/server.go
new file mode 100644
index 0000000000000000000000000000000000000000..a0759f757dc44153e7f09b726db5e66176796c96
--- /dev/null
+++ b/protocol/grpc/internal/server.go
@@ -0,0 +1,66 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package internal
+
+import (
+	"context"
+	"log"
+	"net"
+)
+
+import (
+	"google.golang.org/grpc"
+)
+
+var (
+	s *grpc.Server
+)
+
+// server is used to implement helloworld.GreeterServer.
+type server struct {
+	UnimplementedGreeterServer
+}
+
+// SayHello implements helloworld.GreeterServer
+func (s *server) SayHello(ctx context.Context, in *HelloRequest) (*HelloReply, error) {
+	log.Printf("Received: %v", in.GetName())
+	return &HelloReply{Message: "Hello " + in.GetName()}, nil
+}
+
+// InitGrpcServer ...
+func InitGrpcServer() {
+	port := ":30000"
+
+	lis, err := net.Listen("tcp", port)
+	if err != nil {
+		log.Fatalf("failed to listen: %v", err)
+	}
+	s = grpc.NewServer()
+	RegisterGreeterServer(s, &server{})
+	if err := s.Serve(lis); err != nil {
+		log.Fatalf("failed to serve: %v", err)
+	}
+}
+
+// ShutdownGrpcServer ...
+func ShutdownGrpcServer() {
+	if s == nil {
+		return
+	}
+	s.GracefulStop()
+}
diff --git a/protocol/grpc/protoc-gen-dubbo/examples/Makefile b/protocol/grpc/protoc-gen-dubbo/examples/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..7893bbc51aa436f711bfb653dc81d9ec66b7e5c0
--- /dev/null
+++ b/protocol/grpc/protoc-gen-dubbo/examples/Makefile
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+grpc-gen:
+	protoc -I ./ helloworld.proto --go_out=plugins=grpc:.
+dubbo-gen:
+	protoc -I ./ helloworld.proto  --dubbo_out=plugins=grpc+dubbo:.
diff --git a/protocol/grpc/protoc-gen-dubbo/examples/helloworld.pb.go b/protocol/grpc/protoc-gen-dubbo/examples/helloworld.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..f5d3a49b0916050fc6b2e6373fde0b70df0a1c31
--- /dev/null
+++ b/protocol/grpc/protoc-gen-dubbo/examples/helloworld.pb.go
@@ -0,0 +1,301 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: helloworld.proto
+
+package main
+
+import (
+	"context"
+	"fmt"
+	"math"
+
+	"github.com/golang/protobuf/proto"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+import (
+	"github.com/apache/dubbo-go/protocol"
+	dgrpc "github.com/apache/dubbo-go/protocol/grpc"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+// The request message containing the user's name.
+type HelloRequest struct {
+	Name                 string   `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *HelloRequest) Reset()         { *m = HelloRequest{} }
+func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
+func (*HelloRequest) ProtoMessage()    {}
+func (*HelloRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_17b8c58d586b62f2, []int{0}
+}
+
+func (m *HelloRequest) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_HelloRequest.Unmarshal(m, b)
+}
+func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic)
+}
+func (m *HelloRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_HelloRequest.Merge(m, src)
+}
+func (m *HelloRequest) XXX_Size() int {
+	return xxx_messageInfo_HelloRequest.Size(m)
+}
+func (m *HelloRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_HelloRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_HelloRequest proto.InternalMessageInfo
+
+func (m *HelloRequest) GetName() string {
+	if m != nil {
+		return m.Name
+	}
+	return ""
+}
+
+// The response message containing the greetings
+type HelloReply struct {
+	Message              string   `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *HelloReply) Reset()         { *m = HelloReply{} }
+func (m *HelloReply) String() string { return proto.CompactTextString(m) }
+func (*HelloReply) ProtoMessage()    {}
+func (*HelloReply) Descriptor() ([]byte, []int) {
+	return fileDescriptor_17b8c58d586b62f2, []int{1}
+}
+
+func (m *HelloReply) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_HelloReply.Unmarshal(m, b)
+}
+func (m *HelloReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_HelloReply.Marshal(b, m, deterministic)
+}
+func (m *HelloReply) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_HelloReply.Merge(m, src)
+}
+func (m *HelloReply) XXX_Size() int {
+	return xxx_messageInfo_HelloReply.Size(m)
+}
+func (m *HelloReply) XXX_DiscardUnknown() {
+	xxx_messageInfo_HelloReply.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_HelloReply proto.InternalMessageInfo
+
+func (m *HelloReply) GetMessage() string {
+	if m != nil {
+		return m.Message
+	}
+	return ""
+}
+
+func init() {
+	proto.RegisterType((*HelloRequest)(nil), "main.HelloRequest")
+	proto.RegisterType((*HelloReply)(nil), "main.HelloReply")
+}
+
+func init() { proto.RegisterFile("helloworld.proto", fileDescriptor_17b8c58d586b62f2) }
+
+var fileDescriptor_17b8c58d586b62f2 = []byte{
+	// 185 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xc8, 0x48, 0xcd, 0xc9,
+	0xc9, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0xc9, 0x4d,
+	0xcc, 0xcc, 0x53, 0x52, 0xe2, 0xe2, 0xf1, 0x00, 0xc9, 0x04, 0xa5, 0x16, 0x96, 0xa6, 0x16, 0x97,
+	0x08, 0x09, 0x71, 0xb1, 0xe4, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06, 0x81,
+	0xd9, 0x4a, 0x6a, 0x5c, 0x5c, 0x50, 0x35, 0x05, 0x39, 0x95, 0x42, 0x12, 0x5c, 0xec, 0xb9, 0xa9,
+	0xc5, 0xc5, 0x89, 0xe9, 0x30, 0x45, 0x30, 0xae, 0x91, 0x2d, 0x17, 0xbb, 0x7b, 0x51, 0x6a, 0x6a,
+	0x49, 0x6a, 0x91, 0x90, 0x11, 0x17, 0x47, 0x70, 0x62, 0x25, 0x58, 0x97, 0x90, 0x90, 0x1e, 0xc8,
+	0x26, 0x3d, 0x64, 0x6b, 0xa4, 0x04, 0x50, 0xc4, 0x0a, 0x72, 0x2a, 0x95, 0x18, 0x9c, 0xcc, 0xb8,
+	0xa4, 0x33, 0xf3, 0xf5, 0xd2, 0x8b, 0x0a, 0x92, 0xf5, 0x52, 0x2b, 0x12, 0x73, 0x0b, 0x72, 0x52,
+	0x8b, 0xf5, 0x10, 0xae, 0x76, 0xe2, 0x07, 0x2b, 0x0e, 0x07, 0xb1, 0x03, 0x40, 0x1e, 0x08, 0x60,
+	0x5c, 0xc4, 0xc4, 0xec, 0xe1, 0x13, 0x9e, 0xc4, 0x06, 0xf6, 0x8f, 0x31, 0x20, 0x00, 0x00, 0xff,
+	0xff, 0xd2, 0x16, 0x5f, 0x34, 0xe3, 0x00, 0x00, 0x00,
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion4
+
+// GreeterClient is the client API for Greeter service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type GreeterClient interface {
+	// Sends a greeting
+	SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
+}
+
+type greeterClient struct {
+	cc *grpc.ClientConn
+}
+
+func NewGreeterClient(cc *grpc.ClientConn) GreeterClient {
+	return &greeterClient{cc}
+}
+
+func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
+	out := new(HelloReply)
+	err := c.cc.Invoke(ctx, "/main.Greeter/SayHello", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// GreeterServer is the server API for Greeter service.
+type GreeterServer interface {
+	// Sends a greeting
+	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
+}
+
+// UnimplementedGreeterServer can be embedded to have forward compatible implementations.
+type UnimplementedGreeterServer struct {
+}
+
+func (*UnimplementedGreeterServer) SayHello(ctx context.Context, req *HelloRequest) (*HelloReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
+}
+
+func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
+	s.RegisterService(&_Greeter_serviceDesc, srv)
+}
+
+func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(HelloRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(GreeterServer).SayHello(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/main.Greeter/SayHello",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _Greeter_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "main.Greeter",
+	HandlerType: (*GreeterServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "SayHello",
+			Handler:    _Greeter_SayHello_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "helloworld.proto",
+}
+
+// GreeterClientImpl is the client API for Greeter service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type GreeterClientImpl struct {
+	// Sends a greeting
+	SayHello func(ctx context.Context, in *HelloRequest, out *HelloReply) error
+}
+
+func (c *GreeterClientImpl) Reference() string {
+	return "greeterImpl"
+}
+
+func (c *GreeterClientImpl) GetDubboStub(cc *grpc.ClientConn) GreeterClient {
+	return NewGreeterClient(cc)
+}
+
+type GreeterProviderBase struct {
+	proxyImpl protocol.Invoker
+}
+
+func (s *GreeterProviderBase) SetProxyImpl(impl protocol.Invoker) {
+	s.proxyImpl = impl
+}
+
+func (s *GreeterProviderBase) GetProxyImpl() protocol.Invoker {
+	return s.proxyImpl
+}
+
+func _DUBBO_Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(HelloRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	base := srv.(dgrpc.DubboGrpcService)
+	args := []interface{}{}
+	args = append(args, in)
+	invo := invocation.NewRPCInvocation("SayHello", args, nil)
+	if interceptor == nil {
+		result := base.GetProxyImpl().Invoke(context.Background(), invo)
+		return result.Result(), result.Error()
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/main.Greeter/SayHello",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		result := base.GetProxyImpl().Invoke(context.Background(), invo)
+		return result.Result(), result.Error()
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func (s *GreeterProviderBase) ServiceDesc() *grpc.ServiceDesc {
+	return &grpc.ServiceDesc{
+		ServiceName: "main.Greeter",
+		HandlerType: (*GreeterServer)(nil),
+		Methods: []grpc.MethodDesc{
+			{
+				MethodName: "SayHello",
+				Handler:    _DUBBO_Greeter_SayHello_Handler,
+			},
+		},
+		Streams:  []grpc.StreamDesc{},
+		Metadata: "helloworld.proto",
+	}
+}
diff --git a/protocol/grpc/protoc-gen-dubbo/examples/helloworld.proto b/protocol/grpc/protoc-gen-dubbo/examples/helloworld.proto
new file mode 100644
index 0000000000000000000000000000000000000000..d68e1dd37b3276760623d214662854e931bbdd09
--- /dev/null
+++ b/protocol/grpc/protoc-gen-dubbo/examples/helloworld.proto
@@ -0,0 +1,37 @@
+// Copyright 2015 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "io.grpc.examples.helloworld";
+option java_outer_classname = "HelloWorldProto";
+option objc_class_prefix = "HLW";
+
+package main;
+
+// The greeting service definition.
+service Greeter {
+  // Sends a greeting
+  rpc SayHello (HelloRequest) returns (HelloReply) {}
+}
+
+// The request message containing the user's name.
+message HelloRequest {
+  string name = 1;
+}
+
+// The response message containing the greetings
+message HelloReply {
+  string message = 1;
+}
diff --git a/protocol/grpc/protoc-gen-dubbo/main.go b/protocol/grpc/protoc-gen-dubbo/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..b2f0e82f74a4d3c1a7013714cd18d83562baff71
--- /dev/null
+++ b/protocol/grpc/protoc-gen-dubbo/main.go
@@ -0,0 +1,74 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+	"io/ioutil"
+	"os"
+)
+
+import (
+	"github.com/golang/protobuf/proto"
+	"github.com/golang/protobuf/protoc-gen-go/generator"
+	_ "github.com/golang/protobuf/protoc-gen-go/grpc"
+)
+
+import (
+	_ "github.com/apache/dubbo-go/protocol/grpc/protoc-gen-dubbo/plugin/dubbo"
+)
+
+func main() {
+	// Begin by allocating a generate. The request and response structures are stored there
+	// so we can do error handling easily - the response structure contains the field to
+	// report failure.
+	g := generator.New()
+
+	data, err := ioutil.ReadAll(os.Stdin)
+	if err != nil {
+		g.Error(err, "reading input")
+	}
+
+	if err := proto.Unmarshal(data, g.Request); err != nil {
+		g.Error(err, "parsing input proto")
+	}
+
+	if len(g.Request.FileToGenerate) == 0 {
+		g.Fail("no files to generate")
+	}
+
+	g.CommandLineParameters(g.Request.GetParameter())
+
+	// Create a wrapped version of the Descriptors and EnumDescriptors that
+	// point to the file that defines them.
+	g.WrapTypes()
+
+	g.SetPackageNames()
+	g.BuildTypeNameMap()
+
+	g.GenerateAllFiles()
+
+	// Send back the results.
+	data, err = proto.Marshal(g.Response)
+	if err != nil {
+		g.Error(err, "failed to marshal output proto")
+	}
+	_, err = os.Stdout.Write(data)
+	if err != nil {
+		g.Error(err, "failed to write output proto")
+	}
+}
diff --git a/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/doc.go b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/doc.go
new file mode 100644
index 0000000000000000000000000000000000000000..064c738a53d2200223b0ca81aca77358afad032b
--- /dev/null
+++ b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/doc.go
@@ -0,0 +1,19 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package dubbo plugin for protobuf.
+package dubbo
diff --git a/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go
new file mode 100644
index 0000000000000000000000000000000000000000..e84a7d0cc96887cf728f499c28c26f061ed1ccdf
--- /dev/null
+++ b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go
@@ -0,0 +1,346 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package dubbo
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+import (
+	pb "github.com/golang/protobuf/protoc-gen-go/descriptor"
+	"github.com/golang/protobuf/protoc-gen-go/generator"
+)
+
+// generatedCodeVersion indicates a version of the generated code.
+// It is incremented whenever an incompatibility between the generated code and
+// the grpc package is introduced; the generated code references
+// a constant, grpc.SupportPackageIsVersionN (where N is generatedCodeVersion).
+const generatedCodeVersion = 4
+
+// Paths for packages used by code generated in this file,
+// relative to the import_prefix of the generator.Generator.
+const (
+	contextPkgPath = "context"
+	grpcPkgPath    = "google.golang.org/grpc"
+	codePkgPath    = "google.golang.org/grpc/codes"
+	statusPkgPath  = "google.golang.org/grpc/status"
+)
+
+func init() {
+	generator.RegisterPlugin(new(dubboGrpc))
+}
+
+// grpc is an implementation of the Go protocol buffer compiler's
+// plugin architecture.  It generates bindings for gRPC-dubbo support.
+type dubboGrpc struct {
+	gen *generator.Generator
+}
+
+// Name returns the name of this plugin, "grpc".
+func (g *dubboGrpc) Name() string {
+	return "dubbo"
+}
+
+// The names for packages imported in the generated code.
+// They may vary from the final path component of the import path
+// if the name is used by other packages.
+var (
+	contextPkg string
+	grpcPkg    string
+)
+
+// Init initializes the plugin.
+func (g *dubboGrpc) Init(gen *generator.Generator) {
+	g.gen = gen
+}
+
+// Given a type name defined in a .proto, return its object.
+// Also record that we're using it, to guarantee the associated import.
+func (g *dubboGrpc) objectNamed(name string) generator.Object {
+	g.gen.RecordTypeUse(name)
+	return g.gen.ObjectNamed(name)
+}
+
+// Given a type name defined in a .proto, return its name as we will print it.
+func (g *dubboGrpc) typeName(str string) string {
+	return g.gen.TypeName(g.objectNamed(str))
+}
+
+// P forwards to g.gen.P.
+func (g *dubboGrpc) P(args ...interface{}) { g.gen.P(args...) }
+
+// Generate generates code for the services in the given file.
+// be consistent with grpc plugin
+func (g *dubboGrpc) Generate(file *generator.FileDescriptor) {
+	if len(file.FileDescriptorProto.Service) == 0 {
+		return
+	}
+
+	contextPkg = string(g.gen.AddImport(contextPkgPath))
+	grpcPkg = string(g.gen.AddImport(grpcPkgPath))
+
+	for i, service := range file.FileDescriptorProto.Service {
+		g.generateService(file, service, i)
+	}
+}
+
+// GenerateImports generates the import declaration for this file.
+func (g *dubboGrpc) GenerateImports(file *generator.FileDescriptor) {
+	g.P("import (")
+	g.P(`dgrpc "github.com/apache/dubbo-go/protocol/grpc"`)
+	g.P(`"github.com/apache/dubbo-go/protocol/invocation"`)
+	g.P(`"github.com/apache/dubbo-go/protocol"`)
+	g.P(`"github.com/apache/dubbo-go/config"`)
+	g.P(` ) `)
+}
+
+func unexport(s string) string { return strings.ToLower(s[:1]) + s[1:] }
+
+// deprecationComment is the standard comment added to deprecated
+// messages, fields, enums, and enum values.
+var deprecationComment = "// Deprecated: Do not use."
+
+// generateService generates all the code for the named service.
+func (g *dubboGrpc) generateService(file *generator.FileDescriptor, service *pb.ServiceDescriptorProto, index int) {
+	path := fmt.Sprintf("6,%d", index) // 6 means service.
+
+	origServName := service.GetName()
+	fullServName := origServName
+	if pkg := file.GetPackage(); pkg != "" {
+		fullServName = pkg + "." + fullServName
+	}
+	servName := generator.CamelCase(origServName)
+	deprecated := service.GetOptions().GetDeprecated()
+
+	g.P()
+	g.P(fmt.Sprintf(`// %sClientImpl is the client API for %s service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.`, servName, servName))
+
+	// Client interface.
+	if deprecated {
+		g.P("//")
+		g.P(deprecationComment)
+	}
+	dubboSrvName := servName + "ClientImpl"
+	g.P("type ", dubboSrvName, " struct {")
+	for i, method := range service.Method {
+		g.gen.PrintComments(fmt.Sprintf("%s,2,%d", path, i)) // 2 means method in a service.
+		if method.GetOptions().GetDeprecated() {
+			g.P("//")
+			g.P(deprecationComment)
+		}
+		g.P(g.generateClientSignature(servName, method))
+	}
+	g.P("}")
+	g.P()
+
+	// NewClient factory.
+	if deprecated {
+		g.P(deprecationComment)
+	}
+
+	// add Reference method
+	//func (u *GrpcGreeterImpl) Reference() string {
+	//	return "GrpcGreeterImpl"
+	//}
+	g.P("func (c *", dubboSrvName, ") ", " Reference() string ", "{")
+	g.P(`return "`, unexport(servName), `Impl"`)
+	g.P("}")
+	g.P()
+
+	// add GetDubboStub method
+	// func (u *GrpcGreeterImpl) GetDubboStub(cc *grpc.ClientConn) GreeterClient {
+	//	return NewGreeterClient(cc)
+	//}
+	g.P("func (c *", dubboSrvName, ") ", " GetDubboStub(cc *grpc.ClientConn) ", servName, "Client {")
+	g.P(`return New`, servName, `Client(cc)`)
+	g.P("}")
+	g.P()
+
+	// Server interface.
+	serverType := servName + "ProviderBase"
+	g.P("type ", serverType, " struct {")
+	g.P("proxyImpl protocol.Invoker")
+	g.P("}")
+	g.P()
+
+	// add set method
+	//func (g *GreeterProviderBase) SetProxyImpl(impl protocol.Invoker) {
+	//	g.proxyImpl = impl
+	//}
+	g.P("func (s *", serverType, ") SetProxyImpl(impl protocol.Invoker) {")
+	g.P(`s.proxyImpl = impl`)
+	g.P("}")
+	g.P()
+
+	// return get method
+	g.P("func (s *", serverType, ") GetProxyImpl() protocol.Invoker {")
+	g.P(`return s.proxyImpl`)
+	g.P("}")
+	g.P()
+
+	// add handler
+	var handlerNames []string
+	for _, method := range service.Method {
+		hname := g.generateServerMethod(servName, fullServName, method)
+		handlerNames = append(handlerNames, hname)
+	}
+
+	grpcserverType := servName + "Server"
+	// return service desc
+	g.P("func (s *", serverType, ") ServiceDesc() *grpc.ServiceDesc {")
+	g.P(`return &grpc.ServiceDesc{`)
+	g.P("ServiceName: ", strconv.Quote(fullServName), ",")
+	g.P("HandlerType: (*", grpcserverType, ")(nil),")
+	g.P("Methods: []", grpcPkg, ".MethodDesc{")
+	for i, method := range service.Method {
+		if method.GetServerStreaming() || method.GetClientStreaming() {
+			continue
+		}
+		g.P("{")
+		g.P("MethodName: ", strconv.Quote(method.GetName()), ",")
+		g.P("Handler: ", handlerNames[i], ",")
+		g.P("},")
+	}
+	g.P("},")
+	g.P("Streams: []", grpcPkg, ".StreamDesc{},")
+	g.P("Metadata: \"", file.GetName(), "\",")
+	g.P("}")
+	g.P("}")
+	g.P()
+}
+
+// generateClientSignature returns the client-side signature for a method.
+func (g *dubboGrpc) generateClientSignature(servName string, method *pb.MethodDescriptorProto) string {
+	origMethName := method.GetName()
+	methName := generator.CamelCase(origMethName)
+	//if reservedClientName[methName] {
+	//  methName += "_"
+	//}
+	reqArg := ", in *" + g.typeName(method.GetInputType())
+	if method.GetClientStreaming() {
+		reqArg = ""
+	}
+	respName := "out *" + g.typeName(method.GetOutputType())
+	if method.GetServerStreaming() || method.GetClientStreaming() {
+		respName = servName + "_" + generator.CamelCase(origMethName) + "Client"
+	}
+	return fmt.Sprintf("%s func(ctx %s.Context%s, %s) error", methName, contextPkg, reqArg, respName)
+}
+
+func (g *dubboGrpc) generateClientMethod(servName, fullServName, serviceDescVar string, method *pb.MethodDescriptorProto, descExpr string) {
+}
+
+func (g *dubboGrpc) generateServerMethod(servName, fullServName string, method *pb.MethodDescriptorProto) string {
+	methName := generator.CamelCase(method.GetName())
+	hname := fmt.Sprintf("_DUBBO_%s_%s_Handler", servName, methName)
+	inType := g.typeName(method.GetInputType())
+	outType := g.typeName(method.GetOutputType())
+
+	if !method.GetServerStreaming() && !method.GetClientStreaming() {
+		g.P("func ", hname, "(srv interface{}, ctx ", contextPkg, ".Context, dec func(interface{}) error, interceptor ", grpcPkg, ".UnaryServerInterceptor) (interface{}, error) {")
+		g.P("in := new(", inType, ")")
+		g.P("if err := dec(in); err != nil { return nil, err }")
+
+		g.P("base := srv.(dgrpc.DubboGrpcService)")
+		g.P("args := []interface{}{}")
+		g.P("args = append(args, in)")
+		g.P(`invo := invocation.NewRPCInvocation("`, methName, `", args, nil)`)
+
+		g.P("if interceptor == nil {")
+		g.P("result := base.GetProxyImpl().Invoke(invo)")
+		g.P("return result.Result(), result.Error()")
+		g.P("}")
+
+		g.P("info := &", grpcPkg, ".UnaryServerInfo{")
+		g.P("Server: srv,")
+		g.P("FullMethod: ", strconv.Quote(fmt.Sprintf("/%s/%s", fullServName, methName)), ",")
+		g.P("}")
+
+		g.P("handler := func(ctx ", contextPkg, ".Context, req interface{}) (interface{}, error) {")
+		g.P("result := base.GetProxyImpl().Invoke(invo)")
+		g.P("return result.Result(), result.Error()")
+		g.P("}")
+
+		g.P("return interceptor(ctx, in, info, handler)")
+		g.P("}")
+		g.P()
+		return hname
+	}
+	streamType := unexport(servName) + methName + "Server"
+	g.P("func ", hname, "(srv interface{}, stream ", grpcPkg, ".ServerStream) error {")
+	if !method.GetClientStreaming() {
+		g.P("m := new(", inType, ")")
+		g.P("if err := stream.RecvMsg(m); err != nil { return err }")
+		g.P("return srv.(", servName, "Server).", methName, "(m, &", streamType, "{stream})")
+	} else {
+		g.P("return srv.(", servName, "Server).", methName, "(&", streamType, "{stream})")
+	}
+	g.P("}")
+	g.P()
+
+	genSend := method.GetServerStreaming()
+	genSendAndClose := !method.GetServerStreaming()
+	genRecv := method.GetClientStreaming()
+
+	// Stream auxiliary types and methods.
+	g.P("type ", servName, "_", methName, "Server interface {")
+	if genSend {
+		g.P("Send(*", outType, ") error")
+	}
+	if genSendAndClose {
+		g.P("SendAndClose(*", outType, ") error")
+	}
+	if genRecv {
+		g.P("Recv() (*", inType, ", error)")
+	}
+	g.P(grpcPkg, ".ServerStream")
+	g.P("}")
+	g.P()
+
+	g.P("type ", streamType, " struct {")
+	g.P(grpcPkg, ".ServerStream")
+	g.P("}")
+	g.P()
+
+	if genSend {
+		g.P("func (x *", streamType, ") Send(m *", outType, ") error {")
+		g.P("return x.ServerStream.SendMsg(m)")
+		g.P("}")
+		g.P()
+	}
+	if genSendAndClose {
+		g.P("func (x *", streamType, ") SendAndClose(m *", outType, ") error {")
+		g.P("return x.ServerStream.SendMsg(m)")
+		g.P("}")
+		g.P()
+	}
+	if genRecv {
+		g.P("func (x *", streamType, ") Recv() (*", inType, ", error) {")
+		g.P("m := new(", inType, ")")
+		g.P("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }")
+		g.P("return m, nil")
+		g.P("}")
+		g.P()
+	}
+
+	return hname
+}
diff --git a/protocol/grpc/server.go b/protocol/grpc/server.go
new file mode 100644
index 0000000000000000000000000000000000000000..19b9db4ac743ceefcf035d399c0bbcdd99f1fa80
--- /dev/null
+++ b/protocol/grpc/server.go
@@ -0,0 +1,106 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package grpc
+
+import (
+	"fmt"
+	"net"
+	"reflect"
+)
+
+import (
+	"google.golang.org/grpc"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+// Server ...
+type Server struct {
+	grpcServer *grpc.Server
+}
+
+// NewServer ...
+func NewServer() *Server {
+	return &Server{}
+}
+
+// DubboGrpcService ...
+type DubboGrpcService interface {
+	SetProxyImpl(impl protocol.Invoker)
+	GetProxyImpl() protocol.Invoker
+	ServiceDesc() *grpc.ServiceDesc
+}
+
+// Start ...
+func (s *Server) Start(url common.URL) {
+	var (
+		addr string
+		err  error
+	)
+	addr = url.Location
+	lis, err := net.Listen("tcp", addr)
+	if err != nil {
+		panic(err)
+	}
+	server := grpc.NewServer()
+
+	key := url.GetParam(constant.BEAN_NAME_KEY, "")
+	service := config.GetProviderService(key)
+
+	ds, ok := service.(DubboGrpcService)
+	if !ok {
+		panic("illegal service type registered")
+	}
+
+	m, ok := reflect.TypeOf(service).MethodByName("SetProxyImpl")
+	if !ok {
+		panic("method SetProxyImpl is necessary for grpc service")
+	}
+
+	exporter, _ := grpcProtocol.ExporterMap().Load(url.ServiceKey())
+	if exporter == nil {
+		panic(fmt.Sprintf("no exporter found for servicekey: %v", url.ServiceKey()))
+	}
+	invoker := exporter.(protocol.Exporter).GetInvoker()
+	if invoker == nil {
+		panic(fmt.Sprintf("no invoker found for servicekey: %v", url.ServiceKey()))
+	}
+	in := []reflect.Value{reflect.ValueOf(service)}
+	in = append(in, reflect.ValueOf(invoker))
+	m.Func.Call(in)
+
+	server.RegisterService(ds.ServiceDesc(), service)
+
+	s.grpcServer = server
+	go func() {
+		if err = server.Serve(lis); err != nil {
+			logger.Errorf("server serve failed with err: %v", err)
+		}
+	}()
+}
+
+// Stop ...
+func (s *Server) Stop() {
+	s.grpcServer.Stop()
+}
diff --git a/protocol/invocation.go b/protocol/invocation.go
index 055e7a4cd18707772d6ba75303053f15dc55dbe3..f32f2c3449ac063ecb89952bd4653312a07a3df4 100644
--- a/protocol/invocation.go
+++ b/protocol/invocation.go
@@ -21,9 +21,11 @@ import (
 	"reflect"
 )
 
+// Invocation ...
 type Invocation interface {
 	MethodName() string
 	ParameterTypes() []reflect.Type
+	ParameterValues() []reflect.Value
 	Arguments() []interface{}
 	Reply() interface{}
 	Attachments() map[string]string
diff --git a/protocol/invocation/rpcinvocation.go b/protocol/invocation/rpcinvocation.go
index 2124a22f1611b24d7f4370de64b117c58c4f7e7b..b207fd0b0cc4eb7de8409a8c46c6fc9ef0baa5c7 100644
--- a/protocol/invocation/rpcinvocation.go
+++ b/protocol/invocation/rpcinvocation.go
@@ -19,26 +19,32 @@ package invocation
 
 import (
 	"reflect"
+	"sync"
 )
 
 import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-/////////////////////////////
+// ///////////////////////////
 // Invocation Impletment of RPC
-/////////////////////////////
+// ///////////////////////////
+
 // todo: is it necessary to separate fields of consumer(provider) from RPCInvocation
+// RPCInvocation ...
 type RPCInvocation struct {
-	methodName     string
-	parameterTypes []reflect.Type
-	arguments      []interface{}
-	reply          interface{}
-	callBack       interface{}
-	attachments    map[string]string
-	invoker        protocol.Invoker
-}
-
+	methodName      string
+	parameterTypes  []reflect.Type
+	parameterValues []reflect.Value
+	arguments       []interface{}
+	reply           interface{}
+	callBack        interface{}
+	attachments     map[string]string
+	invoker         protocol.Invoker
+	lock            sync.RWMutex
+}
+
+// NewRPCInvocation ...
 func NewRPCInvocation(methodName string, arguments []interface{}, attachments map[string]string) *RPCInvocation {
 	return &RPCInvocation{
 		methodName:  methodName,
@@ -47,6 +53,7 @@ func NewRPCInvocation(methodName string, arguments []interface{}, attachments ma
 	}
 }
 
+// NewRPCInvocationWithOptions ...
 func NewRPCInvocationWithOptions(opts ...option) *RPCInvocation {
 	invo := &RPCInvocation{}
 	for _, opt := range opts {
@@ -55,31 +62,45 @@ func NewRPCInvocationWithOptions(opts ...option) *RPCInvocation {
 	return invo
 }
 
+// MethodName ...
 func (r *RPCInvocation) MethodName() string {
 	return r.methodName
 }
 
+// ParameterTypes ...
 func (r *RPCInvocation) ParameterTypes() []reflect.Type {
 	return r.parameterTypes
 }
 
+// ParameterValues ...
+func (r *RPCInvocation) ParameterValues() []reflect.Value {
+	return r.parameterValues
+}
+
+// Arguments ...
 func (r *RPCInvocation) Arguments() []interface{} {
 	return r.arguments
 }
 
+// Reply ...
 func (r *RPCInvocation) Reply() interface{} {
 	return r.reply
 }
 
+// SetReply ...
 func (r *RPCInvocation) SetReply(reply interface{}) {
 	r.reply = reply
 }
 
+// Attachments ...
 func (r *RPCInvocation) Attachments() map[string]string {
 	return r.attachments
 }
 
+// AttachmentsByKey ...
 func (r *RPCInvocation) AttachmentsByKey(key string, defaultValue string) string {
+	r.lock.RLock()
+	defer r.lock.RUnlock()
 	if r.attachments == nil {
 		return defaultValue
 	}
@@ -90,71 +111,92 @@ func (r *RPCInvocation) AttachmentsByKey(key string, defaultValue string) string
 	return defaultValue
 }
 
+// SetAttachments ...
 func (r *RPCInvocation) SetAttachments(key string, value string) {
+	r.lock.Lock()
+	defer r.lock.Unlock()
 	if r.attachments == nil {
 		r.attachments = make(map[string]string)
 	}
 	r.attachments[key] = value
 }
 
+// Invoker ...
 func (r *RPCInvocation) Invoker() protocol.Invoker {
 	return r.invoker
 }
 
+// SetInvoker ...
 func (r *RPCInvocation) SetInvoker() protocol.Invoker {
 	return r.invoker
 }
 
+// CallBack ...
 func (r *RPCInvocation) CallBack() interface{} {
 	return r.callBack
 }
 
+// SetCallBack ...
 func (r *RPCInvocation) SetCallBack(c interface{}) {
 	r.callBack = c
 }
 
-///////////////////////////
+// /////////////////////////
 // option
-///////////////////////////
+// /////////////////////////
 
 type option func(invo *RPCInvocation)
 
+// WithMethodName ...
 func WithMethodName(methodName string) option {
 	return func(invo *RPCInvocation) {
 		invo.methodName = methodName
 	}
 }
 
+// WithParameterTypes ...
 func WithParameterTypes(parameterTypes []reflect.Type) option {
 	return func(invo *RPCInvocation) {
 		invo.parameterTypes = parameterTypes
 	}
 }
 
+// WithParameterValues ...
+func WithParameterValues(parameterValues []reflect.Value) option {
+	return func(invo *RPCInvocation) {
+		invo.parameterValues = parameterValues
+	}
+}
+
+// WithArguments ...
 func WithArguments(arguments []interface{}) option {
 	return func(invo *RPCInvocation) {
 		invo.arguments = arguments
 	}
 }
 
+// WithReply ...
 func WithReply(reply interface{}) option {
 	return func(invo *RPCInvocation) {
 		invo.reply = reply
 	}
 }
 
+// WithCallBack ...
 func WithCallBack(callBack interface{}) option {
 	return func(invo *RPCInvocation) {
 		invo.callBack = callBack
 	}
 }
 
+// WithAttachments ...
 func WithAttachments(attachments map[string]string) option {
 	return func(invo *RPCInvocation) {
 		invo.attachments = attachments
 	}
 }
 
+// WithInvoker ...
 func WithInvoker(invoker protocol.Invoker) option {
 	return func(invo *RPCInvocation) {
 		invo.invoker = invoker
diff --git a/protocol/invoker.go b/protocol/invoker.go
index f5d41a09ad2778c12c7e5e68167a4d0acc9e3f4c..bb71bab1cfa2ede7fb035912ae996f9adb7411e0 100644
--- a/protocol/invoker.go
+++ b/protocol/invoker.go
@@ -17,28 +17,35 @@
 
 package protocol
 
+import (
+	"context"
+)
+
 import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/logger"
 )
 
+// Invoker ...
 //go:generate mockgen -source invoker.go -destination mock/mock_invoker.go  -self_package github.com/apache/dubbo-go/protocol/mock --package mock  Invoker
 // Extension - Invoker
 type Invoker interface {
 	common.Node
-	Invoke(Invocation) Result
+	Invoke(context.Context, Invocation) Result
 }
 
 /////////////////////////////
 // base invoker
 /////////////////////////////
 
+// BaseInvoker ...
 type BaseInvoker struct {
 	url       common.URL
 	available bool
 	destroyed bool
 }
 
+// NewBaseInvoker ...
 func NewBaseInvoker(url common.URL) *BaseInvoker {
 	return &BaseInvoker{
 		url:       url,
@@ -47,22 +54,27 @@ func NewBaseInvoker(url common.URL) *BaseInvoker {
 	}
 }
 
+// GetUrl ...
 func (bi *BaseInvoker) GetUrl() common.URL {
 	return bi.url
 }
 
+// IsAvailable ...
 func (bi *BaseInvoker) IsAvailable() bool {
 	return bi.available
 }
 
+// IsDestroyed ...
 func (bi *BaseInvoker) IsDestroyed() bool {
 	return bi.destroyed
 }
 
-func (bi *BaseInvoker) Invoke(invocation Invocation) Result {
+// Invoke ...
+func (bi *BaseInvoker) Invoke(context context.Context, invocation Invocation) Result {
 	return &RPCResult{}
 }
 
+// Destroy ...
 func (bi *BaseInvoker) Destroy() {
 	logger.Infof("Destroy invoker: %s", bi.GetUrl().String())
 	bi.destroyed = true
diff --git a/protocol/jsonrpc/http.go b/protocol/jsonrpc/http.go
index 3d99786624c71818cc5f787c8695d1c116c35707..ba7197dbc857c2ed7acda1a9f246a5b826e86915 100644
--- a/protocol/jsonrpc/http.go
+++ b/protocol/jsonrpc/http.go
@@ -33,18 +33,21 @@ import (
 )
 
 import (
+	"github.com/opentracing/opentracing-go"
 	perrors "github.com/pkg/errors"
 )
 
 import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
 )
 
-//////////////////////////////////////////////
+// ////////////////////////////////////////////
 // Request
-//////////////////////////////////////////////
+// ////////////////////////////////////////////
 
+// Request ...
 type Request struct {
 	ID          int64
 	group       string
@@ -56,10 +59,11 @@ type Request struct {
 	contentType string
 }
 
-//////////////////////////////////////////////
+// ////////////////////////////////////////////
 // HTTP Client
-//////////////////////////////////////////////
+// ////////////////////////////////////////////
 
+// HTTPOptions ...
 type HTTPOptions struct {
 	HandshakeTimeout time.Duration
 	HTTPTimeout      time.Duration
@@ -70,11 +74,13 @@ var defaultHTTPOptions = HTTPOptions{
 	HTTPTimeout:      3 * time.Second,
 }
 
+// HTTPClient ...
 type HTTPClient struct {
 	ID      int64
 	options HTTPOptions
 }
 
+// NewHTTPClient ...
 func NewHTTPClient(opt *HTTPOptions) *HTTPClient {
 	if opt == nil {
 		opt = &defaultHTTPOptions
@@ -94,6 +100,7 @@ func NewHTTPClient(opt *HTTPOptions) *HTTPClient {
 	}
 }
 
+// NewRequest ...
 func (c *HTTPClient) NewRequest(service common.URL, method string, args interface{}) *Request {
 
 	return &Request{
@@ -107,6 +114,7 @@ func (c *HTTPClient) NewRequest(service common.URL, method string, args interfac
 	}
 }
 
+// Call ...
 func (c *HTTPClient) Call(ctx context.Context, service common.URL, req *Request, rsp interface{}) error {
 	// header
 	httpHeader := http.Header{}
@@ -124,6 +132,13 @@ func (c *HTTPClient) Call(ctx context.Context, service common.URL, req *Request,
 		}
 	}
 
+	if span := opentracing.SpanFromContext(ctx); span != nil {
+		err := opentracing.GlobalTracer().Inject(span.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(httpHeader))
+		if err != nil {
+			logger.Error("Could not inject the Context into http header.")
+		}
+	}
+
 	// body
 	codec := newJsonClientCodec()
 	codecData := CodecData{
@@ -144,6 +159,7 @@ func (c *HTTPClient) Call(ctx context.Context, service common.URL, req *Request,
 	return perrors.WithStack(codec.Read(rspBody, rsp))
 }
 
+// Do
 // !!The high level of complexity and the likelihood that the fasthttp client has not been extensively used
 // in production means that you would need to expect a very large benefit to justify the adoption of fasthttp today.
 func (c *HTTPClient) Do(addr, path string, httpHeader http.Header, body []byte) ([]byte, error) {
diff --git a/protocol/jsonrpc/http_test.go b/protocol/jsonrpc/http_test.go
index 9be55e247a730460a3adee5622fa978ef2defbfb..0cb88b36a8f330059906eb70417b6d4841020c38 100644
--- a/protocol/jsonrpc/http_test.go
+++ b/protocol/jsonrpc/http_test.go
@@ -25,6 +25,7 @@ import (
 )
 
 import (
+	"github.com/opentracing/opentracing-go"
 	perrors "github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
@@ -55,10 +56,10 @@ func TestHTTPClient_Call(t *testing.T) {
 
 	// Export
 	proto := GetProtocol()
-	url, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/UserProvider?anyhost=true&"+
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
+	url, err := common.NewURL("jsonrpc://127.0.0.1:20001/UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
 		"side=provider&timeout=3000&timestamp=1556509797245&bean.name=UserProvider")
 	assert.NoError(t, err)
 	proto.Export(&proxy_factory.ProxyInvoker{
@@ -74,6 +75,7 @@ func TestHTTPClient_Call(t *testing.T) {
 		"X-Services": url.Path,
 		"X-Method":   "GetUser",
 	})
+
 	req := client.NewRequest(url, "GetUser", []interface{}{"1", "username"})
 	reply := &User{}
 	err = client.Call(ctx, url, req, reply)
@@ -147,6 +149,10 @@ func TestHTTPClient_Call(t *testing.T) {
 		"X-Services": url.Path,
 		"X-Method":   "GetUser4",
 	})
+
+	span := opentracing.StartSpan("Test-Inject-Tracing-ID")
+	ctx = opentracing.ContextWithSpan(ctx, span)
+
 	req = client.NewRequest(url, "GetUser4", []interface{}{1})
 	reply = &User{}
 	err = client.Call(ctx, url, req, reply)
diff --git a/protocol/jsonrpc/json.go b/protocol/jsonrpc/json.go
index 7ee454e8ad16d2ee96ed08e7e5f55b2209a81054..d1c2a858b4e4223ac32fc1160b56f6ee1862c8ce 100644
--- a/protocol/jsonrpc/json.go
+++ b/protocol/jsonrpc/json.go
@@ -31,10 +31,13 @@ import (
 )
 
 const (
+	// MAX_JSONRPC_ID max jsonrpc request/response id
 	MAX_JSONRPC_ID = 0x7FFFFFFF
-	VERSION        = "2.0"
+	// VERSION jsonrpc version
+	VERSION = "2.0"
 )
 
+// CodecData ...
 type CodecData struct {
 	ID     int64
 	Method string
@@ -54,7 +57,7 @@ const (
 	codeServerErrorEnd   = -32000
 )
 
-// rsponse Error
+// Error response Error
 type Error struct {
 	Code    int         `json:"code"`
 	Message string      `json:"message"`
@@ -278,12 +281,14 @@ type serverResponse struct {
 	Error   interface{}      `json:"error,omitempty"`
 }
 
+// ServerCodec ...
 type ServerCodec struct {
 	req serverRequest
 }
 
 var (
-	null    = json.RawMessage([]byte("null"))
+	null = json.RawMessage([]byte("null"))
+	// Version ...
 	Version = "2.0"
 )
 
@@ -291,6 +296,7 @@ func newServerCodec() *ServerCodec {
 	return &ServerCodec{}
 }
 
+// ReadHeader ...
 func (c *ServerCodec) ReadHeader(header map[string]string, body []byte) error {
 	if header["HttpMethod"] != "POST" {
 		return &Error{Code: -32601, Message: "Method not found"}
@@ -322,6 +328,7 @@ func (c *ServerCodec) ReadHeader(header map[string]string, body []byte) error {
 	return nil
 }
 
+// ReadBody ...
 func (c *ServerCodec) ReadBody(x interface{}) error {
 	// If x!=nil and return error e:
 	// - Write() will be called with e.Error() in r.Error
@@ -355,6 +362,7 @@ func (c *ServerCodec) ReadBody(x interface{}) error {
 	return nil
 }
 
+// NewError ...
 func NewError(code int, message string) *Error {
 	return &Error{Code: code, Message: message}
 }
diff --git a/protocol/jsonrpc/jsonrpc_exporter.go b/protocol/jsonrpc/jsonrpc_exporter.go
index 6720330494a3b833d4a67d8b2408377ce62b1ddf..7f8fd491854f1ab25e63410a22ef5664db92f614 100644
--- a/protocol/jsonrpc/jsonrpc_exporter.go
+++ b/protocol/jsonrpc/jsonrpc_exporter.go
@@ -28,16 +28,19 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// JsonrpcExporter ...
 type JsonrpcExporter struct {
 	protocol.BaseExporter
 }
 
+// NewJsonrpcExporter ...
 func NewJsonrpcExporter(key string, invoker protocol.Invoker, exporterMap *sync.Map) *JsonrpcExporter {
 	return &JsonrpcExporter{
 		BaseExporter: *protocol.NewBaseExporter(key, invoker, exporterMap),
 	}
 }
 
+// Unexport ...
 func (je *JsonrpcExporter) Unexport() {
 	serviceId := je.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "")
 	je.BaseExporter.Unexport()
diff --git a/protocol/jsonrpc/jsonrpc_invoker.go b/protocol/jsonrpc/jsonrpc_invoker.go
index 2c130e0d7617e96a1724edc5b63f8e66f251446e..b6e194ce0e93e84c164eccf8574e5eb20430f6e8 100644
--- a/protocol/jsonrpc/jsonrpc_invoker.go
+++ b/protocol/jsonrpc/jsonrpc_invoker.go
@@ -29,11 +29,13 @@ import (
 	invocation_impl "github.com/apache/dubbo-go/protocol/invocation"
 )
 
+// JsonrpcInvoker ...
 type JsonrpcInvoker struct {
 	protocol.BaseInvoker
 	client *HTTPClient
 }
 
+// NewJsonrpcInvoker ...
 func NewJsonrpcInvoker(url common.URL, client *HTTPClient) *JsonrpcInvoker {
 	return &JsonrpcInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
@@ -41,7 +43,8 @@ func NewJsonrpcInvoker(url common.URL, client *HTTPClient) *JsonrpcInvoker {
 	}
 }
 
-func (ji *JsonrpcInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+// Invoke ...
+func (ji *JsonrpcInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 
 	var (
 		result protocol.RPCResult
@@ -50,12 +53,12 @@ func (ji *JsonrpcInvoker) Invoke(invocation protocol.Invocation) protocol.Result
 	inv := invocation.(*invocation_impl.RPCInvocation)
 	url := ji.GetUrl()
 	req := ji.client.NewRequest(url, inv.MethodName(), inv.Arguments())
-	ctx := context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{
+	ctxNew := context.WithValue(ctx, constant.DUBBOGO_CTX_KEY, map[string]string{
 		"X-Proxy-Id": "dubbogo",
 		"X-Services": url.Path,
 		"X-Method":   inv.MethodName(),
 	})
-	result.Err = ji.client.Call(ctx, url, req, inv.Reply())
+	result.Err = ji.client.Call(ctxNew, url, req, inv.Reply())
 	if result.Err == nil {
 		result.Rest = inv.Reply()
 	}
diff --git a/protocol/jsonrpc/jsonrpc_invoker_test.go b/protocol/jsonrpc/jsonrpc_invoker_test.go
index 8c910339858f4960ad0e394ae6271863d7654adc..9e08eed2b4c61e686073a9039a605c4f73aa08c5 100644
--- a/protocol/jsonrpc/jsonrpc_invoker_test.go
+++ b/protocol/jsonrpc/jsonrpc_invoker_test.go
@@ -42,10 +42,10 @@ func TestJsonrpcInvoker_Invoke(t *testing.T) {
 
 	// Export
 	proto := GetProtocol()
-	url, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/UserProvider?anyhost=true&"+
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
+	url, err := common.NewURL("jsonrpc://127.0.0.1:20001/UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
 		"side=provider&timeout=3000&timestamp=1556509797245&bean.name=UserProvider")
 	assert.NoError(t, err)
 	proto.Export(&proxy_factory.ProxyInvoker{
@@ -60,7 +60,7 @@ func TestJsonrpcInvoker_Invoke(t *testing.T) {
 
 	jsonInvoker := NewJsonrpcInvoker(url, client)
 	user := &User{}
-	res := jsonInvoker.Invoke(invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("GetUser"), invocation.WithArguments([]interface{}{"1", "username"}),
+	res := jsonInvoker.Invoke(context.Background(), invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("GetUser"), invocation.WithArguments([]interface{}{"1", "username"}),
 		invocation.WithReply(user)))
 
 	assert.NoError(t, res.Error())
diff --git a/protocol/jsonrpc/jsonrpc_protocol.go b/protocol/jsonrpc/jsonrpc_protocol.go
index c18345d413edb2d263f1acaef1741514b665f042..bed7099ab60a6c05c3799f993c0bb348a4b00f02 100644
--- a/protocol/jsonrpc/jsonrpc_protocol.go
+++ b/protocol/jsonrpc/jsonrpc_protocol.go
@@ -20,17 +20,23 @@ package jsonrpc
 import (
 	"strings"
 	"sync"
+	"time"
 )
 
 import (
 	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/config"
 	"github.com/apache/dubbo-go/protocol"
 )
 
-const JSONRPC = "jsonrpc"
+const (
+	// JSONRPC
+	//module name
+	JSONRPC = "jsonrpc"
+)
 
 func init() {
 	extension.SetProtocol(JSONRPC, GetProtocol)
@@ -38,12 +44,14 @@ func init() {
 
 var jsonrpcProtocol *JsonrpcProtocol
 
+// JsonrpcProtocol ...
 type JsonrpcProtocol struct {
 	protocol.BaseProtocol
 	serverMap  map[string]*Server
 	serverLock sync.Mutex
 }
 
+// NewJsonrpcProtocol ...
 func NewJsonrpcProtocol() *JsonrpcProtocol {
 	return &JsonrpcProtocol{
 		BaseProtocol: protocol.NewBaseProtocol(),
@@ -51,6 +59,7 @@ func NewJsonrpcProtocol() *JsonrpcProtocol {
 	}
 }
 
+// Export ...
 func (jp *JsonrpcProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	url := invoker.GetUrl()
 	serviceKey := strings.TrimPrefix(url.Path, "/")
@@ -65,16 +74,26 @@ func (jp *JsonrpcProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	return exporter
 }
 
+// Refer ...
 func (jp *JsonrpcProtocol) Refer(url common.URL) protocol.Invoker {
+	//default requestTimeout
+	var requestTimeout = config.GetConsumerConfig().RequestTimeout
+
+	requestTimeoutStr := url.GetParam(constant.TIMEOUT_KEY, config.GetConsumerConfig().Request_Timeout)
+	if t, err := time.ParseDuration(requestTimeoutStr); err == nil {
+		requestTimeout = t
+	}
+
 	invoker := NewJsonrpcInvoker(url, NewHTTPClient(&HTTPOptions{
 		HandshakeTimeout: config.GetConsumerConfig().ConnectTimeout,
-		HTTPTimeout:      config.GetConsumerConfig().RequestTimeout,
+		HTTPTimeout:      requestTimeout,
 	}))
 	jp.SetInvokers(invoker)
 	logger.Infof("Refer service: %s", url.String())
 	return invoker
 }
 
+// Destroy ...
 func (jp *JsonrpcProtocol) Destroy() {
 	logger.Infof("jsonrpcProtocol destroy.")
 
@@ -106,6 +125,7 @@ func (jp *JsonrpcProtocol) openServer(url common.URL) {
 	}
 }
 
+// GetProtocol ...
 func GetProtocol() protocol.Protocol {
 	if jsonrpcProtocol == nil {
 		jsonrpcProtocol = NewJsonrpcProtocol()
diff --git a/protocol/jsonrpc/jsonrpc_protocol_test.go b/protocol/jsonrpc/jsonrpc_protocol_test.go
index 253ab830dd85e5424811b7fd4e7e7e848adad415..c00bed12fe9fbb4937f21810cee548a25e3b1c05 100644
--- a/protocol/jsonrpc/jsonrpc_protocol_test.go
+++ b/protocol/jsonrpc/jsonrpc_protocol_test.go
@@ -18,7 +18,6 @@
 package jsonrpc
 
 import (
-	"context"
 	"fmt"
 	"strings"
 	"testing"
@@ -38,10 +37,10 @@ import (
 func TestJsonrpcProtocol_Export(t *testing.T) {
 	// Export
 	proto := GetProtocol()
-	url, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
+	url, err := common.NewURL("jsonrpc://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
 		"side=provider&timeout=3000&timestamp=1556509797245")
 	assert.NoError(t, err)
 	exporter := proto.Export(protocol.NewBaseInvoker(url))
@@ -69,10 +68,10 @@ func TestJsonrpcProtocol_Export(t *testing.T) {
 func TestJsonrpcProtocol_Refer(t *testing.T) {
 	// Refer
 	proto := GetProtocol()
-	url, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
+	url, err := common.NewURL("jsonrpc://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
 		"side=provider&timeout=3000&timestamp=1556509797245")
 	assert.NoError(t, err)
 	con := config.ConsumerConfig{
diff --git a/protocol/jsonrpc/server.go b/protocol/jsonrpc/server.go
index dc85e0f5e76fd07dbcd11646ae529c98e5323a15..8600f02dad3d32d797613823de0bbe40261d2e71 100644
--- a/protocol/jsonrpc/server.go
+++ b/protocol/jsonrpc/server.go
@@ -32,6 +32,7 @@ import (
 )
 
 import (
+	"github.com/opentracing/opentracing-go"
 	perrors "github.com/pkg/errors"
 )
 
@@ -50,11 +51,15 @@ var (
 )
 
 const (
-	DefaultMaxSleepTime      = 1 * time.Second // accept中间最大sleep interval
+	// DefaultMaxSleepTime max sleep interval in accept
+	DefaultMaxSleepTime = 1 * time.Second
+	// DefaultHTTPRspBufferSize ...
 	DefaultHTTPRspBufferSize = 1024
-	PathPrefix               = byte('/')
+	// PathPrefix ...
+	PathPrefix = byte('/')
 )
 
+// Server ...
 type Server struct {
 	done chan struct{}
 	once sync.Once
@@ -64,6 +69,7 @@ type Server struct {
 	timeout time.Duration
 }
 
+// NewServer ...
 func NewServer() *Server {
 	return &Server{
 		done: make(chan struct{}),
@@ -93,6 +99,8 @@ func (s *Server) handlePkg(conn net.Conn) {
 		rsp := &http.Response{
 			Header:        header,
 			StatusCode:    500,
+			ProtoMajor:    1,
+			ProtoMinor:    1,
 			ContentLength: int64(len(body)),
 			Body:          ioutil.NopCloser(bytes.NewReader(body)),
 		}
@@ -147,6 +155,13 @@ func (s *Server) handlePkg(conn net.Conn) {
 		}
 
 		ctx := context.Background()
+
+		spanCtx, err := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders,
+			opentracing.HTTPHeadersCarrier(r.Header))
+		if err == nil {
+			ctx = context.WithValue(ctx, constant.TRACING_REMOTE_SPAN_CTX, spanCtx)
+		}
+
 		if len(reqHeader["Timeout"]) > 0 {
 			timeout, err := time.ParseDuration(reqHeader["Timeout"])
 			if err == nil {
@@ -213,6 +228,7 @@ func accept(listener net.Listener, fn func(net.Conn)) error {
 	}
 }
 
+// Start ...
 func (s *Server) Start(url common.URL) {
 	listener, err := net.Listen("tcp", url.Location)
 	if err != nil {
@@ -239,6 +255,7 @@ func (s *Server) Start(url common.URL) {
 	}()
 }
 
+// Stop ...
 func (s *Server) Stop() {
 	s.once.Do(func() {
 		close(s.done)
@@ -252,6 +269,8 @@ func serveRequest(ctx context.Context,
 		rsp := &http.Response{
 			Header:        make(http.Header),
 			StatusCode:    500,
+			ProtoMajor:    1,
+			ProtoMinor:    1,
 			ContentLength: int64(len(body)),
 			Body:          ioutil.NopCloser(bytes.NewReader(body)),
 		}
@@ -276,6 +295,8 @@ func serveRequest(ctx context.Context,
 		rsp := &http.Response{
 			Header:        make(http.Header),
 			StatusCode:    200,
+			ProtoMajor:    1,
+			ProtoMinor:    1,
 			ContentLength: int64(len(body)),
 			Body:          ioutil.NopCloser(bytes.NewReader(body)),
 		}
@@ -324,10 +345,9 @@ func serveRequest(ctx context.Context,
 	exporter, _ := jsonrpcProtocol.ExporterMap().Load(path)
 	invoker := exporter.(*JsonrpcExporter).GetInvoker()
 	if invoker != nil {
-		result := invoker.Invoke(invocation.NewRPCInvocation(methodName, args, map[string]string{
+		result := invoker.Invoke(ctx, invocation.NewRPCInvocation(methodName, args, map[string]string{
 			constant.PATH_KEY:    path,
-			constant.VERSION_KEY: codec.req.Version,
-		}))
+			constant.VERSION_KEY: codec.req.Version}))
 		if err := result.Error(); err != nil {
 			rspStream, err := codec.Write(err.Error(), invalidRequest)
 			if err != nil {
diff --git a/protocol/mock/mock_invoker.go b/protocol/mock/mock_invoker.go
index c509cef054f5a23fe504486e01d7cc0e8772711d..5c5b476b7b07f6c41a74a7ec8f51648aff84b1a3 100644
--- a/protocol/mock/mock_invoker.go
+++ b/protocol/mock/mock_invoker.go
@@ -21,6 +21,7 @@
 package mock
 
 import (
+	"context"
 	"reflect"
 )
 
@@ -91,7 +92,7 @@ func (mr *MockInvokerMockRecorder) Destroy() *gomock.Call {
 }
 
 // Invoke mocks base method
-func (m *MockInvoker) Invoke(arg0 protocol.Invocation) protocol.Result {
+func (m *MockInvoker) Invoke(ctx context.Context, arg0 protocol.Invocation) protocol.Result {
 	ret := m.ctrl.Call(m, "Invoke", arg0)
 	ret0, _ := ret[0].(protocol.Result)
 	return ret0
diff --git a/protocol/protocol.go b/protocol/protocol.go
index 814a85163a99aa3b161b5eafbfed5f13ac4e3eb4..a873469a8ba361c9dfc922b071ffbf256c6a8b98 100644
--- a/protocol/protocol.go
+++ b/protocol/protocol.go
@@ -26,6 +26,7 @@ import (
 	"github.com/apache/dubbo-go/common/logger"
 )
 
+// Protocol
 // Extension - protocol
 type Protocol interface {
 	Export(invoker Invoker) Exporter
@@ -33,6 +34,7 @@ type Protocol interface {
 	Destroy()
 }
 
+// Exporter
 // wrapping invoker
 type Exporter interface {
 	GetInvoker() Invoker
@@ -43,37 +45,45 @@ type Exporter interface {
 // base protocol
 /////////////////////////////
 
+// BaseProtocol ...
 type BaseProtocol struct {
 	exporterMap *sync.Map
 	invokers    []Invoker
 }
 
+// NewBaseProtocol ...
 func NewBaseProtocol() BaseProtocol {
 	return BaseProtocol{
 		exporterMap: new(sync.Map),
 	}
 }
 
+// SetExporterMap ...
 func (bp *BaseProtocol) SetExporterMap(key string, exporter Exporter) {
 	bp.exporterMap.Store(key, exporter)
 }
 
+// ExporterMap ...
 func (bp *BaseProtocol) ExporterMap() *sync.Map {
 	return bp.exporterMap
 }
 
+// SetInvokers ...
 func (bp *BaseProtocol) SetInvokers(invoker Invoker) {
 	bp.invokers = append(bp.invokers, invoker)
 }
 
+// Invokers ...
 func (bp *BaseProtocol) Invokers() []Invoker {
 	return bp.invokers
 }
 
+// Export ...
 func (bp *BaseProtocol) Export(invoker Invoker) Exporter {
 	return NewBaseExporter("base", invoker, bp.exporterMap)
 }
 
+// Refer ...
 func (bp *BaseProtocol) Refer(url common.URL) Invoker {
 	return NewBaseInvoker(url)
 }
@@ -103,12 +113,14 @@ func (bp *BaseProtocol) Destroy() {
 // base exporter
 /////////////////////////////
 
+// BaseExporter ...
 type BaseExporter struct {
 	key         string
 	invoker     Invoker
 	exporterMap *sync.Map
 }
 
+// NewBaseExporter ...
 func NewBaseExporter(key string, invoker Invoker, exporterMap *sync.Map) *BaseExporter {
 	return &BaseExporter{
 		key:         key,
@@ -117,11 +129,13 @@ func NewBaseExporter(key string, invoker Invoker, exporterMap *sync.Map) *BaseEx
 	}
 }
 
+// GetInvoker ...
 func (de *BaseExporter) GetInvoker() Invoker {
 	return de.invoker
 
 }
 
+// Unexport ...
 func (de *BaseExporter) Unexport() {
 	logger.Infof("Exporter unexport.")
 	de.invoker.Destroy()
diff --git a/protocol/protocolwrapper/mock_protocol_filter.go b/protocol/protocolwrapper/mock_protocol_filter.go
index 2efc34da4469cf369d4bbeb871ccfbdb73123f6a..dedf8aa64b6ae1b7b4782350e2625b02171aac44 100644
--- a/protocol/protocolwrapper/mock_protocol_filter.go
+++ b/protocol/protocolwrapper/mock_protocol_filter.go
@@ -28,6 +28,7 @@ import (
 
 type mockProtocolFilter struct{}
 
+// NewMockProtocolFilter ...
 func NewMockProtocolFilter() protocol.Protocol {
 	return &mockProtocolFilter{}
 }
diff --git a/protocol/protocolwrapper/protocol_filter_wrapper.go b/protocol/protocolwrapper/protocol_filter_wrapper.go
index 7c58fabea3cccf5a39e1622fedd4a3a297e05983..70d2da0faed3bc9797eb23cec653bea05d445d91 100644
--- a/protocol/protocolwrapper/protocol_filter_wrapper.go
+++ b/protocol/protocolwrapper/protocol_filter_wrapper.go
@@ -18,6 +18,7 @@
 package protocolwrapper
 
 import (
+	"context"
 	"strings"
 )
 
@@ -30,6 +31,7 @@ import (
 )
 
 const (
+	// FILTER ...
 	FILTER = "filter"
 )
 
@@ -37,11 +39,13 @@ func init() {
 	extension.SetProtocol(FILTER, GetProtocol)
 }
 
+// ProtocolFilterWrapper
 // protocol in url decide who ProtocolFilterWrapper.protocol is
 type ProtocolFilterWrapper struct {
 	protocol protocol.Protocol
 }
 
+// Export ...
 func (pfw *ProtocolFilterWrapper) Export(invoker protocol.Invoker) protocol.Exporter {
 	if pfw.protocol == nil {
 		pfw.protocol = extension.GetProtocol(invoker.GetUrl().Protocol)
@@ -50,6 +54,7 @@ func (pfw *ProtocolFilterWrapper) Export(invoker protocol.Invoker) protocol.Expo
 	return pfw.protocol.Export(invoker)
 }
 
+// Refer ...
 func (pfw *ProtocolFilterWrapper) Refer(url common.URL) protocol.Invoker {
 	if pfw.protocol == nil {
 		pfw.protocol = extension.GetProtocol(url.Protocol)
@@ -57,6 +62,7 @@ func (pfw *ProtocolFilterWrapper) Refer(url common.URL) protocol.Invoker {
 	return buildInvokerChain(pfw.protocol.Refer(url), constant.REFERENCE_FILTER_KEY)
 }
 
+// Destroy ...
 func (pfw *ProtocolFilterWrapper) Destroy() {
 	pfw.protocol.Destroy()
 }
@@ -72,14 +78,15 @@ func buildInvokerChain(invoker protocol.Invoker, key string) protocol.Invoker {
 	// The order of filters is from left to right, so loading from right to left
 
 	for i := len(filtNames) - 1; i >= 0; i-- {
-		filter := extension.GetFilter(filtNames[i])
-		fi := &FilterInvoker{next: next, invoker: invoker, filter: filter}
+		flt := extension.GetFilter(filtNames[i])
+		fi := &FilterInvoker{next: next, invoker: invoker, filter: flt}
 		next = fi
 	}
 
 	return next
 }
 
+// GetProtocol ...
 func GetProtocol() protocol.Protocol {
 	return &ProtocolFilterWrapper{}
 }
@@ -88,25 +95,30 @@ func GetProtocol() protocol.Protocol {
 // filter invoker
 ///////////////////////////
 
+// FilterInvoker ...
 type FilterInvoker struct {
 	next    protocol.Invoker
 	invoker protocol.Invoker
 	filter  filter.Filter
 }
 
+// GetUrl ...
 func (fi *FilterInvoker) GetUrl() common.URL {
 	return fi.invoker.GetUrl()
 }
 
+// IsAvailable ...
 func (fi *FilterInvoker) IsAvailable() bool {
 	return fi.invoker.IsAvailable()
 }
 
-func (fi *FilterInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
-	result := fi.filter.Invoke(fi.next, invocation)
-	return fi.filter.OnResponse(result, fi.invoker, invocation)
+// Invoke ...
+func (fi *FilterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
+	result := fi.filter.Invoke(ctx, fi.next, invocation)
+	return fi.filter.OnResponse(ctx, result, fi.invoker, invocation)
 }
 
+// Destroy ...
 func (fi *FilterInvoker) Destroy() {
 	fi.invoker.Destroy()
 }
diff --git a/protocol/protocolwrapper/protocol_filter_wrapper_test.go b/protocol/protocolwrapper/protocol_filter_wrapper_test.go
index dc376313549c24da1cc6cb64a42e8445ef4fe346..8491d57462d47d6af72040d41b78dcb30e6da697 100644
--- a/protocol/protocolwrapper/protocol_filter_wrapper_test.go
+++ b/protocol/protocolwrapper/protocol_filter_wrapper_test.go
@@ -18,6 +18,7 @@
 package protocolwrapper
 
 import (
+	"context"
 	"net/url"
 	"testing"
 )
@@ -66,7 +67,7 @@ func init() {
 
 type EchoFilterForTest struct{}
 
-func (ef *EchoFilterForTest) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+func (ef *EchoFilterForTest) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	logger.Infof("invoking echo filter.")
 	logger.Debugf("%v,%v", invocation.MethodName(), len(invocation.Arguments()))
 	if invocation.MethodName() == constant.ECHO && len(invocation.Arguments()) == 1 {
@@ -75,10 +76,10 @@ func (ef *EchoFilterForTest) Invoke(invoker protocol.Invoker, invocation protoco
 		}
 	}
 
-	return invoker.Invoke(invocation)
+	return invoker.Invoke(ctx, invocation)
 }
 
-func (ef *EchoFilterForTest) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+func (ef *EchoFilterForTest) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	return result
 }
 
diff --git a/protocol/result.go b/protocol/result.go
index dcdb62310d359d441067395ea92f8460df97eb22..34e76d2dddbaed33b2e2c015631443565cfaea87 100644
--- a/protocol/result.go
+++ b/protocol/result.go
@@ -17,6 +17,7 @@
 
 package protocol
 
+// Result ...
 type Result interface {
 	SetError(error)
 	Error() error
@@ -32,12 +33,14 @@ type Result interface {
 // Result Impletment of RPC
 /////////////////////////////
 
+// RPCResult ...
 type RPCResult struct {
 	Attrs map[string]string
 	Err   error
 	Rest  interface{}
 }
 
+// SetError ...
 func (r *RPCResult) SetError(err error) {
 	r.Err = err
 }
@@ -46,26 +49,32 @@ func (r *RPCResult) Error() error {
 	return r.Err
 }
 
+// SetResult ...
 func (r *RPCResult) SetResult(rest interface{}) {
 	r.Rest = rest
 }
 
+// Result ...
 func (r *RPCResult) Result() interface{} {
 	return r.Rest
 }
 
+// SetAttachments ...
 func (r *RPCResult) SetAttachments(attr map[string]string) {
 	r.Attrs = attr
 }
 
+// Attachments ...
 func (r *RPCResult) Attachments() map[string]string {
 	return r.Attrs
 }
 
+// AddAttachment ...
 func (r *RPCResult) AddAttachment(key, value string) {
 	r.Attrs[key] = value
 }
 
+// Attachment ...
 func (r *RPCResult) Attachment(key, defaultValue string) string {
 	v, ok := r.Attrs[key]
 	if !ok {
diff --git a/protocol/rpc_status.go b/protocol/rpc_status.go
index 3a8bfbc87f285e0e86269d44c47d6771566d97b1..639fd559aa16689a249d035895fc037dc3bc3f8b 100644
--- a/protocol/rpc_status.go
+++ b/protocol/rpc_status.go
@@ -20,6 +20,7 @@ package protocol
 import (
 	"sync"
 	"sync/atomic"
+	"time"
 )
 
 import (
@@ -27,18 +28,82 @@ import (
 )
 
 var (
-	methodStatistics sync.Map // url -> { methodName : RpcStatus}
+	methodStatistics sync.Map // url -> { methodName : RPCStatus}
+	serviceStatistic sync.Map // url -> RPCStatus
 )
 
-type RpcStatus struct {
-	active int32
+// RPCStatus ...
+type RPCStatus struct {
+	active                        int32
+	failed                        int32
+	total                         int32
+	totalElapsed                  int64
+	failedElapsed                 int64
+	maxElapsed                    int64
+	failedMaxElapsed              int64
+	succeededMaxElapsed           int64
+	successiveRequestFailureCount int32
+	lastRequestFailedTimestamp    int64
 }
 
-func (rpc *RpcStatus) GetActive() int32 {
+// GetActive ...
+func (rpc *RPCStatus) GetActive() int32 {
 	return atomic.LoadInt32(&rpc.active)
 }
 
-func GetStatus(url common.URL, methodName string) *RpcStatus {
+// GetFailed ...
+func (rpc *RPCStatus) GetFailed() int32 {
+	return atomic.LoadInt32(&rpc.failed)
+}
+
+// GetTotal ...
+func (rpc *RPCStatus) GetTotal() int32 {
+	return atomic.LoadInt32(&rpc.total)
+}
+
+// GetTotalElapsed ...
+func (rpc *RPCStatus) GetTotalElapsed() int64 {
+	return atomic.LoadInt64(&rpc.totalElapsed)
+}
+
+// GetFailedElapsed ...
+func (rpc *RPCStatus) GetFailedElapsed() int64 {
+	return atomic.LoadInt64(&rpc.failedElapsed)
+}
+
+// GetMaxElapsed ...
+func (rpc *RPCStatus) GetMaxElapsed() int64 {
+	return atomic.LoadInt64(&rpc.maxElapsed)
+}
+
+// GetFailedMaxElapsed ...
+func (rpc *RPCStatus) GetFailedMaxElapsed() int64 {
+	return atomic.LoadInt64(&rpc.failedMaxElapsed)
+}
+
+// GetSucceededMaxElapsed ...
+func (rpc *RPCStatus) GetSucceededMaxElapsed() int64 {
+	return atomic.LoadInt64(&rpc.succeededMaxElapsed)
+}
+
+// GetLastRequestFailedTimestamp ...
+func (rpc *RPCStatus) GetLastRequestFailedTimestamp() int64 {
+	return atomic.LoadInt64(&rpc.lastRequestFailedTimestamp)
+}
+
+// GetSuccessiveRequestFailureCount ...
+func (rpc *RPCStatus) GetSuccessiveRequestFailureCount() int32 {
+	return atomic.LoadInt32(&rpc.successiveRequestFailureCount)
+}
+
+// GetURLStatus ...
+func GetURLStatus(url common.URL) *RPCStatus {
+	rpcStatus, _ := serviceStatistic.LoadOrStore(url.Key(), &RPCStatus{})
+	return rpcStatus.(*RPCStatus)
+}
+
+// GetMethodStatus ...
+func GetMethodStatus(url common.URL, methodName string) *RPCStatus {
 	identifier := url.Key()
 	methodMap, found := methodStatistics.Load(identifier)
 	if !found {
@@ -49,27 +114,56 @@ func GetStatus(url common.URL, methodName string) *RpcStatus {
 	methodActive := methodMap.(*sync.Map)
 	rpcStatus, found := methodActive.Load(methodName)
 	if !found {
-		rpcStatus = &RpcStatus{}
+		rpcStatus = &RPCStatus{}
 		methodActive.Store(methodName, rpcStatus)
 	}
 
-	status := rpcStatus.(*RpcStatus)
+	status := rpcStatus.(*RPCStatus)
 	return status
 }
 
+// BeginCount ...
 func BeginCount(url common.URL, methodName string) {
-	beginCount0(GetStatus(url, methodName))
+	beginCount0(GetURLStatus(url))
+	beginCount0(GetMethodStatus(url, methodName))
 }
 
-func EndCount(url common.URL, methodName string) {
-	endCount0(GetStatus(url, methodName))
+// EndCount ...
+func EndCount(url common.URL, methodName string, elapsed int64, succeeded bool) {
+	endCount0(GetURLStatus(url), elapsed, succeeded)
+	endCount0(GetMethodStatus(url, methodName), elapsed, succeeded)
 }
 
 // private methods
-func beginCount0(rpcStatus *RpcStatus) {
+func beginCount0(rpcStatus *RPCStatus) {
 	atomic.AddInt32(&rpcStatus.active, 1)
 }
 
-func endCount0(rpcStatus *RpcStatus) {
+func endCount0(rpcStatus *RPCStatus, elapsed int64, succeeded bool) {
 	atomic.AddInt32(&rpcStatus.active, -1)
+	atomic.AddInt32(&rpcStatus.total, 1)
+	atomic.AddInt64(&rpcStatus.totalElapsed, elapsed)
+
+	if rpcStatus.maxElapsed < elapsed {
+		atomic.StoreInt64(&rpcStatus.maxElapsed, elapsed)
+	}
+	if succeeded {
+		if rpcStatus.succeededMaxElapsed < elapsed {
+			atomic.StoreInt64(&rpcStatus.succeededMaxElapsed, elapsed)
+		}
+		atomic.StoreInt32(&rpcStatus.successiveRequestFailureCount, 0)
+	} else {
+		atomic.StoreInt64(&rpcStatus.lastRequestFailedTimestamp, time.Now().Unix())
+		atomic.AddInt32(&rpcStatus.successiveRequestFailureCount, 1)
+		atomic.AddInt32(&rpcStatus.failed, 1)
+		atomic.AddInt64(&rpcStatus.failedElapsed, elapsed)
+		if rpcStatus.failedMaxElapsed < elapsed {
+			atomic.StoreInt64(&rpcStatus.failedMaxElapsed, elapsed)
+		}
+	}
+}
+
+// CurrentTimeMillis ...
+func CurrentTimeMillis() int64 {
+	return time.Now().UnixNano() / int64(time.Millisecond)
 }
diff --git a/protocol/rpc_status_test.go b/protocol/rpc_status_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ffdb3b535667f32e96c3af2be84851655abf5954
--- /dev/null
+++ b/protocol/rpc_status_test.go
@@ -0,0 +1,151 @@
+package protocol
+
+import (
+	"strconv"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+)
+
+func TestBeginCount(t *testing.T) {
+	defer destroy()
+
+	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	BeginCount(url, "test")
+	urlStatus := GetURLStatus(url)
+	methodStatus := GetMethodStatus(url, "test")
+	methodStatus1 := GetMethodStatus(url, "test1")
+	assert.Equal(t, int32(1), methodStatus.active)
+	assert.Equal(t, int32(1), urlStatus.active)
+	assert.Equal(t, int32(0), methodStatus1.active)
+
+}
+
+func TestEndCount(t *testing.T) {
+	defer destroy()
+
+	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	EndCount(url, "test", 100, true)
+	urlStatus := GetURLStatus(url)
+	methodStatus := GetMethodStatus(url, "test")
+	assert.Equal(t, int32(-1), methodStatus.active)
+	assert.Equal(t, int32(-1), urlStatus.active)
+	assert.Equal(t, int32(1), methodStatus.total)
+	assert.Equal(t, int32(1), urlStatus.total)
+}
+
+func TestGetMethodStatus(t *testing.T) {
+	defer destroy()
+
+	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	status := GetMethodStatus(url, "test")
+	assert.NotNil(t, status)
+	assert.Equal(t, int32(0), status.total)
+}
+
+func TestGetUrlStatus(t *testing.T) {
+	defer destroy()
+
+	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	status := GetURLStatus(url)
+	assert.NotNil(t, status)
+	assert.Equal(t, int32(0), status.total)
+}
+
+func Test_beginCount0(t *testing.T) {
+	defer destroy()
+
+	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	status := GetURLStatus(url)
+	beginCount0(status)
+	assert.Equal(t, int32(1), status.active)
+}
+
+func Test_All(t *testing.T) {
+	defer destroy()
+
+	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	request(url, "test", 100, false, true)
+	urlStatus := GetURLStatus(url)
+	methodStatus := GetMethodStatus(url, "test")
+	assert.Equal(t, int32(1), methodStatus.total)
+	assert.Equal(t, int32(1), urlStatus.total)
+	assert.Equal(t, int32(0), methodStatus.active)
+	assert.Equal(t, int32(0), urlStatus.active)
+	assert.Equal(t, int32(0), methodStatus.failed)
+	assert.Equal(t, int32(0), urlStatus.failed)
+	assert.Equal(t, int32(0), methodStatus.successiveRequestFailureCount)
+	assert.Equal(t, int32(0), urlStatus.successiveRequestFailureCount)
+	assert.Equal(t, int64(100), methodStatus.totalElapsed)
+	assert.Equal(t, int64(100), urlStatus.totalElapsed)
+	request(url, "test", 100, false, false)
+	request(url, "test", 100, false, false)
+	request(url, "test", 100, false, false)
+	request(url, "test", 100, false, false)
+	request(url, "test", 100, false, false)
+	assert.Equal(t, int32(6), methodStatus.total)
+	assert.Equal(t, int32(6), urlStatus.total)
+	assert.Equal(t, int32(5), methodStatus.failed)
+	assert.Equal(t, int32(5), urlStatus.failed)
+	assert.Equal(t, int32(5), methodStatus.successiveRequestFailureCount)
+	assert.Equal(t, int32(5), urlStatus.successiveRequestFailureCount)
+	assert.Equal(t, int64(600), methodStatus.totalElapsed)
+	assert.Equal(t, int64(600), urlStatus.totalElapsed)
+	assert.Equal(t, int64(500), methodStatus.failedElapsed)
+	assert.Equal(t, int64(500), urlStatus.failedElapsed)
+
+	request(url, "test", 100, false, true)
+	assert.Equal(t, int32(0), methodStatus.successiveRequestFailureCount)
+	assert.Equal(t, int32(0), urlStatus.successiveRequestFailureCount)
+
+	request(url, "test", 200, false, false)
+	request(url, "test", 200, false, false)
+	assert.Equal(t, int32(2), methodStatus.successiveRequestFailureCount)
+	assert.Equal(t, int32(2), urlStatus.successiveRequestFailureCount)
+	assert.Equal(t, int64(200), methodStatus.maxElapsed)
+	assert.Equal(t, int64(200), urlStatus.maxElapsed)
+
+	request(url, "test1", 200, false, false)
+	request(url, "test1", 200, false, false)
+	request(url, "test1", 200, false, false)
+	assert.Equal(t, int32(5), urlStatus.successiveRequestFailureCount)
+	methodStatus1 := GetMethodStatus(url, "test1")
+	assert.Equal(t, int32(2), methodStatus.successiveRequestFailureCount)
+	assert.Equal(t, int32(3), methodStatus1.successiveRequestFailureCount)
+
+}
+
+func request(url common.URL, method string, elapsed int64, active, succeeded bool) {
+	BeginCount(url, method)
+	if !active {
+		EndCount(url, method, elapsed, succeeded)
+	}
+}
+
+func TestCurrentTimeMillis(t *testing.T) {
+	defer destroy()
+	c := CurrentTimeMillis()
+	assert.NotNil(t, c)
+	str := strconv.FormatInt(c, 10)
+	i, _ := strconv.ParseInt(str, 10, 64)
+	assert.Equal(t, c, i)
+}
+
+func destroy() {
+	delete1 := func(key interface{}, value interface{}) bool {
+		methodStatistics.Delete(key)
+		return true
+	}
+	methodStatistics.Range(delete1)
+	delete2 := func(key interface{}, value interface{}) bool {
+		serviceStatistic.Delete(key)
+		return true
+	}
+	serviceStatistic.Range(delete2)
+}
diff --git a/registry/base_configuration_listener.go b/registry/base_configuration_listener.go
index 056a93aaff1ec657db89f21b4a6b28efc354b49b..55418318dfc52ed9f17f1ec6a18ad9ef9d8163bf 100644
--- a/registry/base_configuration_listener.go
+++ b/registry/base_configuration_listener.go
@@ -29,15 +29,19 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
+// BaseConfigurationListener ...
 type BaseConfigurationListener struct {
 	configurators           []config_center.Configurator
 	dynamicConfiguration    config_center.DynamicConfiguration
 	defaultConfiguratorFunc func(url *common.URL) config_center.Configurator
 }
 
+// Configurators ...
 func (bcl *BaseConfigurationListener) Configurators() []config_center.Configurator {
 	return bcl.configurators
 }
+
+// InitWith ...
 func (bcl *BaseConfigurationListener) InitWith(key string, listener config_center.ConfigurationListener, f func(url *common.URL) config_center.Configurator) {
 	bcl.dynamicConfiguration = config.GetEnvInstance().GetDynamicConfiguration()
 	if bcl.dynamicConfiguration == nil {
@@ -56,6 +60,7 @@ func (bcl *BaseConfigurationListener) InitWith(key string, listener config_cente
 	}
 }
 
+// Process ...
 func (bcl *BaseConfigurationListener) Process(event *config_center.ConfigChangeEvent) {
 	logger.Infof("Notification of overriding rule, change type is: %v , raw config content is:%v", event.ConfigType, event.Value)
 	if event.ConfigType == remoting.EventTypeDel {
@@ -76,12 +81,15 @@ func (bcl *BaseConfigurationListener) genConfiguratorFromRawRule(rawConfig strin
 	bcl.configurators = ToConfigurators(urls, bcl.defaultConfiguratorFunc)
 	return nil
 }
+
+// OverrideUrl ...
 func (bcl *BaseConfigurationListener) OverrideUrl(url *common.URL) {
 	for _, v := range bcl.configurators {
 		v.Configure(url)
 	}
 }
 
+// ToConfigurators ...
 func ToConfigurators(urls []*common.URL, f func(url *common.URL) config_center.Configurator) []config_center.Configurator {
 	if len(urls) == 0 {
 		return nil
diff --git a/registry/base_registry.go b/registry/base_registry.go
new file mode 100644
index 0000000000000000000000000000000000000000..5b9aef82928d491d4b8f4dbe3caa4bd64a185dad
--- /dev/null
+++ b/registry/base_registry.go
@@ -0,0 +1,375 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package registry
+
+import (
+	"context"
+	"fmt"
+	"net/url"
+	"os"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+import (
+	gxnet "github.com/dubbogo/gost/net"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+)
+
+const (
+	// RegistryConnDelay connection delay
+	RegistryConnDelay = 3
+	// MaxWaitInterval max wait interval
+	MaxWaitInterval = 3 * time.Second
+)
+
+var (
+	processID = ""
+	localIP   = ""
+)
+
+func init() {
+	processID = fmt.Sprintf("%d", os.Getpid())
+	localIP, _ = gxnet.GetLocalIP()
+}
+
+/*
+ * -----------------------------------NOTICE---------------------------------------------
+ * If there is no special case, you'd better inherit BaseRegistry and implement the
+ * FacadeBasedRegistry interface instead of directly implementing the Registry interface.
+ * --------------------------------------------------------------------------------------
+ */
+
+/*
+ * FacadeBasedRegistry interface is subclass of Registry, and it is designed for registry who want to inherit BaseRegistry.
+ * You have to implement the interface to inherit BaseRegistry.
+ */
+type FacadeBasedRegistry interface {
+	Registry
+	CreatePath(string) error
+	DoRegister(string, string) error
+	DoSubscribe(conf *common.URL) (Listener, error)
+	CloseAndNilClient()
+	CloseListener()
+	InitListeners()
+}
+
+// BaseRegistry is a common logic abstract for registry. It implement Registry interface.
+type BaseRegistry struct {
+	context             context.Context
+	facadeBasedRegistry FacadeBasedRegistry
+	*common.URL
+	birth    int64          // time of file birth, seconds since Epoch; 0 if unknown
+	wg       sync.WaitGroup // wg+done for zk restart
+	done     chan struct{}
+	cltLock  sync.Mutex            //ctl lock is a lock for services map
+	services map[string]common.URL // service name + protocol -> service config, for store the service registered
+}
+
+// InitBaseRegistry for init some local variables and set BaseRegistry's subclass to it
+func (r *BaseRegistry) InitBaseRegistry(url *common.URL, facadeRegistry FacadeBasedRegistry) Registry {
+	r.URL = url
+	r.birth = time.Now().UnixNano()
+	r.done = make(chan struct{})
+	r.services = make(map[string]common.URL)
+	r.facadeBasedRegistry = facadeRegistry
+	return r
+}
+
+// GetUrl for get registry's url
+func (r *BaseRegistry) GetUrl() common.URL {
+	return *r.URL
+}
+
+// Destroy for graceful down
+func (r *BaseRegistry) Destroy() {
+	//first step close registry's all listeners
+	r.facadeBasedRegistry.CloseListener()
+	// then close r.done to notify other program who listen to it
+	close(r.done)
+	// wait waitgroup done (wait listeners outside close over)
+	r.wg.Wait()
+	//close registry client
+	r.closeRegisters()
+}
+
+// Register implement interface registry to register
+func (r *BaseRegistry) Register(conf common.URL) error {
+	var (
+		ok  bool
+		err error
+	)
+	role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, ""))
+	// Check if the service has been registered
+	r.cltLock.Lock()
+	_, ok = r.services[conf.Key()]
+	r.cltLock.Unlock()
+	if ok {
+		return perrors.Errorf("Path{%s} has been registered", conf.Key())
+	}
+
+	err = r.register(conf)
+	if err != nil {
+		return perrors.WithMessagef(err, "register(conf:%+v)", conf)
+	}
+
+	r.cltLock.Lock()
+	r.services[conf.Key()] = conf
+	r.cltLock.Unlock()
+	logger.Debugf("(%sRegistry)Register(conf{%#v})", common.DubboRole[role], conf)
+
+	return nil
+}
+
+// service is for getting service path stored in url
+func (r *BaseRegistry) service(c common.URL) string {
+	return url.QueryEscape(c.Service())
+}
+
+// RestartCallBack for reregister when reconnect
+func (r *BaseRegistry) RestartCallBack() bool {
+
+	// copy r.services
+	services := []common.URL{}
+	for _, confIf := range r.services {
+		services = append(services, confIf)
+	}
+
+	flag := true
+	for _, confIf := range services {
+		err := r.register(confIf)
+		if err != nil {
+			logger.Errorf("(ZkProviderRegistry)register(conf{%#v}) = error{%#v}",
+				confIf, perrors.WithStack(err))
+			flag = false
+			break
+		}
+		logger.Infof("success to re-register service :%v", confIf.Key())
+	}
+	r.facadeBasedRegistry.InitListeners()
+
+	return flag
+}
+
+// register for register url to registry, include init params
+func (r *BaseRegistry) register(c common.URL) error {
+	var (
+		err error
+		//revision   string
+		params     url.Values
+		rawURL     string
+		encodedURL string
+		dubboPath  string
+		//conf       config.URL
+	)
+	params = url.Values{}
+
+	c.RangeParams(func(key, value string) bool {
+		params.Add(key, value)
+		return true
+	})
+
+	params.Add("pid", processID)
+	params.Add("ip", localIP)
+	//params.Add("timeout", fmt.Sprintf("%d", int64(r.Timeout)/1e6))
+
+	role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, ""))
+	switch role {
+
+	case common.PROVIDER:
+		dubboPath, rawURL, err = r.providerRegistry(c, params)
+	case common.CONSUMER:
+		dubboPath, rawURL, err = r.consumerRegistry(c, params)
+	default:
+		return perrors.Errorf("@c{%v} type is not referencer or provider", c)
+	}
+	encodedURL = url.QueryEscape(rawURL)
+	dubboPath = strings.ReplaceAll(dubboPath, "$", "%24")
+	err = r.facadeBasedRegistry.DoRegister(dubboPath, encodedURL)
+
+	if err != nil {
+		return perrors.WithMessagef(err, "register Node(path:%s, url:%s)", dubboPath, rawURL)
+	}
+	return nil
+}
+
+// providerRegistry for provider role do
+func (r *BaseRegistry) providerRegistry(c common.URL, params url.Values) (string, string, error) {
+	var (
+		dubboPath string
+		rawURL    string
+		err       error
+	)
+	if c.Path == "" || len(c.Methods) == 0 {
+		return "", "", perrors.Errorf("conf{Path:%s, Methods:%s}", c.Path, c.Methods)
+	}
+	dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.PROVIDER])
+	r.cltLock.Lock()
+	err = r.facadeBasedRegistry.CreatePath(dubboPath)
+	r.cltLock.Unlock()
+	if err != nil {
+		logger.Errorf("facadeBasedRegistry.CreatePath(path{%s}) = error{%#v}", dubboPath, perrors.WithStack(err))
+		return "", "", perrors.WithMessagef(err, "facadeBasedRegistry.CreatePath(path:%s)", dubboPath)
+	}
+	params.Add("anyhost", "true")
+
+	// Dubbo java consumer to start looking for the provider url,because the category does not match,
+	// the provider will not find, causing the consumer can not start, so we use consumers.
+	// DubboRole               = [...]string{"consumer", "", "", "provider"}
+	// params.Add("category", (RoleType(PROVIDER)).Role())
+	params.Add("category", (common.RoleType(common.PROVIDER)).String())
+	params.Add("dubbo", "dubbo-provider-golang-"+constant.Version)
+
+	params.Add("side", (common.RoleType(common.PROVIDER)).Role())
+
+	if len(c.Methods) == 0 {
+		params.Add("methods", strings.Join(c.Methods, ","))
+	}
+	logger.Debugf("provider url params:%#v", params)
+	var host string
+	if c.Ip == "" {
+		host = localIP + ":" + c.Port
+	} else {
+		host = c.Ip + ":" + c.Port
+	}
+
+	rawURL = fmt.Sprintf("%s://%s%s?%s", c.Protocol, host, c.Path, params.Encode())
+	// Print your own registration service providers.
+	dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.PROVIDER)).String())
+	logger.Debugf("provider path:%s, url:%s", dubboPath, rawURL)
+	return dubboPath, rawURL, nil
+}
+
+// consumerRegistry for consumer role do
+func (r *BaseRegistry) consumerRegistry(c common.URL, params url.Values) (string, string, error) {
+	var (
+		dubboPath string
+		rawURL    string
+		err       error
+	)
+	dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.CONSUMER])
+	r.cltLock.Lock()
+	err = r.facadeBasedRegistry.CreatePath(dubboPath)
+	r.cltLock.Unlock()
+	if err != nil {
+		logger.Errorf("facadeBasedRegistry.CreatePath(path{%s}) = error{%v}", dubboPath, perrors.WithStack(err))
+		return "", "", perrors.WithStack(err)
+	}
+	dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.PROVIDER])
+	r.cltLock.Lock()
+	err = r.facadeBasedRegistry.CreatePath(dubboPath)
+	r.cltLock.Unlock()
+	if err != nil {
+		logger.Errorf("facadeBasedRegistry.CreatePath(path{%s}) = error{%v}", dubboPath, perrors.WithStack(err))
+		return "", "", perrors.WithStack(err)
+	}
+
+	params.Add("protocol", c.Protocol)
+	params.Add("category", (common.RoleType(common.CONSUMER)).String())
+	params.Add("dubbo", "dubbogo-consumer-"+constant.Version)
+
+	rawURL = fmt.Sprintf("consumer://%s%s?%s", localIP, c.Path, params.Encode())
+	dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.CONSUMER)).String())
+
+	logger.Debugf("consumer path:%s, url:%s", dubboPath, rawURL)
+	return dubboPath, rawURL, nil
+}
+
+// sleepWait...
+func sleepWait(n int) {
+	wait := time.Duration((n + 1) * 2e8)
+	if wait > MaxWaitInterval {
+		wait = MaxWaitInterval
+	}
+	time.Sleep(wait)
+}
+
+// Subscribe :subscribe from registry, event will notify by notifyListener
+func (r *BaseRegistry) Subscribe(url *common.URL, notifyListener NotifyListener) {
+	n := 0
+	for {
+		n++
+		if !r.IsAvailable() {
+			logger.Warnf("event listener game over.")
+			return
+		}
+
+		listener, err := r.facadeBasedRegistry.DoSubscribe(url)
+		if err != nil {
+			if !r.IsAvailable() {
+				logger.Warnf("event listener game over.")
+				return
+			}
+			logger.Warnf("getListener() = err:%v", perrors.WithStack(err))
+			time.Sleep(time.Duration(RegistryConnDelay) * time.Second)
+			continue
+		}
+
+		for {
+			if serviceEvent, err := listener.Next(); err != nil {
+				logger.Warnf("Selector.watch() = error{%v}", perrors.WithStack(err))
+				listener.Close()
+				break
+			} else {
+				logger.Infof("update begin, service event: %v", serviceEvent.String())
+				notifyListener.Notify(serviceEvent)
+			}
+
+		}
+		sleepWait(n)
+	}
+}
+
+// closeRegisters close and remove registry client and reset services map
+func (r *BaseRegistry) closeRegisters() {
+	r.cltLock.Lock()
+	defer r.cltLock.Unlock()
+	logger.Infof("begin to close provider client")
+	// Close and remove(set to nil) the registry client
+	r.facadeBasedRegistry.CloseAndNilClient()
+	// reset the services map
+	r.services = nil
+}
+
+// IsAvailable judge to is registry not closed by chan r.done
+func (r *BaseRegistry) IsAvailable() bool {
+	select {
+	case <-r.done:
+		return false
+	default:
+		return true
+	}
+}
+
+// WaitGroup open for outside add the waitgroup to add some logic before registry destroyed over(graceful down)
+func (r *BaseRegistry) WaitGroup() *sync.WaitGroup {
+	return &r.wg
+}
+
+// Done open for outside to listen the event of registry Destroy() called.
+func (r *BaseRegistry) Done() chan struct{} {
+	return r.done
+}
diff --git a/registry/consul/registry.go b/registry/consul/registry.go
index 73bf3975bc7c73f4a7748f46280ffb1aa5525ca8..c5b8510a6c87068a5b4f1ce52203d401a896a6c2 100644
--- a/registry/consul/registry.go
+++ b/registry/consul/registry.go
@@ -36,6 +36,7 @@ import (
 )
 
 const (
+	// RegistryConnDelay ...
 	RegistryConnDelay = 3
 )
 
@@ -137,14 +138,15 @@ func (r *consulRegistry) subscribe(url *common.URL, notifyListener registry.Noti
 		}
 
 		for {
-			if serviceEvent, err := listener.Next(); err != nil {
+			serviceEvent, err := listener.Next()
+			if err != nil {
 				logger.Warnf("Selector.watch() = error{%v}", perrors.WithStack(err))
 				listener.Close()
 				return
-			} else {
-				logger.Infof("update begin, service event: %v", serviceEvent.String())
-				notifyListener.Notify(serviceEvent)
 			}
+
+			logger.Infof("update begin, service event: %v", serviceEvent.String())
+			notifyListener.Notify(serviceEvent)
 		}
 	}
 }
diff --git a/registry/consul/utils.go b/registry/consul/utils.go
index d295f644631ae63b6bdf035f71f5f104a64083e2..05ac5e76e292a2b574bd5e661bbbcca4f419fc22 100644
--- a/registry/consul/utils.go
+++ b/registry/consul/utils.go
@@ -18,7 +18,6 @@
 package consul
 
 import (
-	"context"
 	"crypto/md5"
 	"encoding/hex"
 	"fmt"
@@ -100,7 +99,7 @@ func retrieveURL(service *consul.ServiceEntry) (common.URL, error) {
 	if !ok {
 		return common.URL{}, perrors.New("retrieve url fails with no url key in service meta")
 	}
-	url1, err := common.NewURL(context.Background(), url)
+	url1, err := common.NewURL(url)
 	if err != nil {
 		return common.URL{}, perrors.WithStack(err)
 	}
diff --git a/registry/directory/directory.go b/registry/directory/directory.go
index e88c611f6f20bc182c3630e328caab848affc08b..f9670af7ea566ce35e89d9173b54752fd16f92bf 100644
--- a/registry/directory/directory.go
+++ b/registry/directory/directory.go
@@ -41,10 +41,12 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
+// Options ...
 type Options struct {
 	serviceTTL time.Duration
 }
 
+// Option ...
 type Option func(*Options)
 
 type registryDirectory struct {
@@ -61,6 +63,7 @@ type registryDirectory struct {
 	Options
 }
 
+// NewRegistryDirectory ...
 func NewRegistryDirectory(url *common.URL, registry registry.Registry, opts ...Option) (*registryDirectory, error) {
 	options := Options{
 		//default 300s
@@ -222,13 +225,14 @@ func (dir *registryDirectory) List(invocation protocol.Invocation) []protocol.In
 func (dir *registryDirectory) IsAvailable() bool {
 	if !dir.BaseDirectory.IsAvailable() {
 		return dir.BaseDirectory.IsAvailable()
-	} else {
-		for _, ivk := range dir.cacheInvokers {
-			if ivk.IsAvailable() {
-				return true
-			}
+	}
+
+	for _, ivk := range dir.cacheInvokers {
+		if ivk.IsAvailable() {
+			return true
 		}
 	}
+
 	return false
 }
 
diff --git a/registry/directory/directory_test.go b/registry/directory/directory_test.go
index b3c1d35aaa66b3437ff89807fba2df0a383921cb..8ebd130d7d1797a9d8707628d7e5920be758e389 100644
--- a/registry/directory/directory_test.go
+++ b/registry/directory/directory_test.go
@@ -18,7 +18,6 @@
 package directory
 
 import (
-	"context"
 	"net/url"
 	"strconv"
 	"testing"
@@ -62,7 +61,7 @@ func TestSubscribe(t *testing.T) {
 //}
 
 func TestSubscribe_InvalidUrl(t *testing.T) {
-	url, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111")
+	url, _ := common.NewURL("mock://127.0.0.1:1111")
 	mockRegistry, _ := registry.NewMockRegistry(&common.URL{})
 	_, err := NewRegistryDirectory(&url, mockRegistry)
 	assert.Error(t, err)
@@ -72,8 +71,8 @@ func TestSubscribe_Group(t *testing.T) {
 	extension.SetProtocol(protocolwrapper.FILTER, protocolwrapper.NewMockProtocolFilter)
 	extension.SetCluster("mock", cluster_impl.NewMockCluster)
 
-	regurl, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111")
-	suburl, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000")
+	regurl, _ := common.NewURL("mock://127.0.0.1:1111")
+	suburl, _ := common.NewURL("dubbo://127.0.0.1:20000")
 	suburl.SetParam(constant.CLUSTER_KEY, "mock")
 	regurl.SubURL = &suburl
 	mockRegistry, _ := registry.NewMockRegistry(&common.URL{})
@@ -124,7 +123,7 @@ func Test_List(t *testing.T) {
 }
 func Test_MergeProviderUrl(t *testing.T) {
 	registryDirectory, mockRegistry := normalRegistryDir(true)
-	providerUrl, _ := common.NewURL(context.TODO(), "dubbo://0.0.0.0:20000/org.apache.dubbo-go.mockService",
+	providerUrl, _ := common.NewURL("dubbo://0.0.0.0:20000/org.apache.dubbo-go.mockService",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock1"),
 		common.WithParamsValue(constant.GROUP_KEY, "group"),
 		common.WithParamsValue(constant.VERSION_KEY, "1.0.0"))
@@ -139,7 +138,7 @@ func Test_MergeProviderUrl(t *testing.T) {
 
 func Test_MergeOverrideUrl(t *testing.T) {
 	registryDirectory, mockRegistry := normalRegistryDir(true)
-	providerUrl, _ := common.NewURL(context.TODO(), "dubbo://0.0.0.0:20000/org.apache.dubbo-go.mockService",
+	providerUrl, _ := common.NewURL("dubbo://0.0.0.0:20000/org.apache.dubbo-go.mockService",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 		common.WithParamsValue(constant.GROUP_KEY, "group"),
 		common.WithParamsValue(constant.VERSION_KEY, "1.0.0"))
@@ -147,7 +146,7 @@ func Test_MergeOverrideUrl(t *testing.T) {
 Loop1:
 	for {
 		if len(registryDirectory.cacheInvokers) > 0 {
-			overrideUrl, _ := common.NewURL(context.TODO(), "override://0.0.0.0:20000/org.apache.dubbo-go.mockService",
+			overrideUrl, _ := common.NewURL("override://0.0.0.0:20000/org.apache.dubbo-go.mockService",
 				common.WithParamsValue(constant.CLUSTER_KEY, "mock1"),
 				common.WithParamsValue(constant.GROUP_KEY, "group"),
 				common.WithParamsValue(constant.VERSION_KEY, "1.0.0"))
@@ -173,9 +172,8 @@ Loop1:
 func normalRegistryDir(noMockEvent ...bool) (*registryDirectory, *registry.MockRegistry) {
 	extension.SetProtocol(protocolwrapper.FILTER, protocolwrapper.NewMockProtocolFilter)
 
-	url, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111")
+	url, _ := common.NewURL("mock://127.0.0.1:1111")
 	suburl, _ := common.NewURL(
-		context.TODO(),
 		"dubbo://127.0.0.1:20000/org.apache.dubbo-go.mockService",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 		common.WithParamsValue(constant.GROUP_KEY, "group"),
diff --git a/registry/etcdv3/listener.go b/registry/etcdv3/listener.go
index 31d62fa916e5659cf424839cedf8f063fabedaa0..79e3ad514584937e742db4bbc993202dd6a9f5b9 100644
--- a/registry/etcdv3/listener.go
+++ b/registry/etcdv3/listener.go
@@ -18,7 +18,6 @@
 package etcdv3
 
 import (
-	"context"
 	"strings"
 )
 
@@ -39,6 +38,7 @@ type dataListener struct {
 	listener      config_center.ConfigurationListener
 }
 
+// NewRegistryDataListener ...
 func NewRegistryDataListener(listener config_center.ConfigurationListener) *dataListener {
 	return &dataListener{listener: listener, interestedURL: []*common.URL{}}
 }
@@ -50,7 +50,7 @@ func (l *dataListener) AddInterestedURL(url *common.URL) {
 func (l *dataListener) DataChange(eventType remoting.Event) bool {
 
 	url := eventType.Path[strings.Index(eventType.Path, "/providers/")+len("/providers/"):]
-	serviceURL, err := common.NewURL(context.Background(), url)
+	serviceURL, err := common.NewURL(url)
 	if err != nil {
 		logger.Warnf("Listen NewURL(r{%s}) = error{%v}", eventType.Path, err)
 		return false
@@ -77,9 +77,10 @@ type configurationListener struct {
 	events   chan *config_center.ConfigChangeEvent
 }
 
+// NewConfigurationListener for listening the event of etcdv3.
 func NewConfigurationListener(reg *etcdV3Registry) *configurationListener {
 	// add a new waiter
-	reg.wg.Add(1)
+	reg.WaitGroup().Add(1)
 	return &configurationListener{registry: reg, events: make(chan *config_center.ConfigChangeEvent, 32)}
 }
 func (l *configurationListener) Process(configType *config_center.ConfigChangeEvent) {
@@ -89,7 +90,7 @@ func (l *configurationListener) Process(configType *config_center.ConfigChangeEv
 func (l *configurationListener) Next() (*registry.ServiceEvent, error) {
 	for {
 		select {
-		case <-l.registry.done:
+		case <-l.registry.Done():
 			logger.Warnf("listener's etcd client connection is broken, so etcd event listener exit now.")
 			return nil, perrors.New("listener stopped")
 
@@ -97,7 +98,7 @@ func (l *configurationListener) Next() (*registry.ServiceEvent, error) {
 			logger.Infof("got etcd event %#v", e)
 			if e.ConfigType == remoting.EventTypeDel {
 				select {
-				case <-l.registry.done:
+				case <-l.registry.Done():
 					logger.Warnf("update @result{%s}. But its connection to registry is invalid", e.Value)
 				default:
 				}
@@ -108,5 +109,5 @@ func (l *configurationListener) Next() (*registry.ServiceEvent, error) {
 	}
 }
 func (l *configurationListener) Close() {
-	l.registry.wg.Done()
+	l.registry.WaitGroup().Done()
 }
diff --git a/registry/etcdv3/listener_test.go b/registry/etcdv3/listener_test.go
index c064f99c6c4b447a6c81093b87d99e1d1ba6d17a..928e3fa83d4a19869903d3aaee1691c298b031b2 100644
--- a/registry/etcdv3/listener_test.go
+++ b/registry/etcdv3/listener_test.go
@@ -18,10 +18,10 @@
 package etcdv3
 
 import (
-	"context"
-	"github.com/apache/dubbo-go/config_center"
 	"testing"
 	"time"
+
+	"github.com/apache/dubbo-go/config_center"
 )
 
 import (
@@ -73,7 +73,7 @@ func (suite *RegistryTestSuite) TestDataChange() {
 	t := suite.T()
 
 	listener := NewRegistryDataListener(&MockDataListener{})
-	url, _ := common.NewURL(context.Background(), "jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100")
+	url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100")
 	listener.AddInterestedURL(&url)
 	if !listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"}) {
 		t.Fatal("data change not ok")
diff --git a/registry/etcdv3/registry.go b/registry/etcdv3/registry.go
index b058113c69b8007803a8a18c1b5e0c3af8c184f4..e1c25768119ea7d7122b9aa22a5f881db44bafd9 100644
--- a/registry/etcdv3/registry.go
+++ b/registry/etcdv3/registry.go
@@ -19,17 +19,13 @@ package etcdv3
 
 import (
 	"fmt"
-	"net/url"
-	"os"
 	"path"
-	"strconv"
 	"strings"
 	"sync"
 	"time"
 )
 
 import (
-	gxnet "github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
 )
 
@@ -42,74 +38,39 @@ import (
 	"github.com/apache/dubbo-go/remoting/etcdv3"
 )
 
-var (
-	processID = ""
-	localIP   = ""
-)
-
 const (
-	Name              = "etcdv3"
-	RegistryConnDelay = 3
+	// Name module name
+	Name = "etcdv3"
 )
 
 func init() {
-	processID = fmt.Sprintf("%d", os.Getpid())
-	localIP, _ = gxnet.GetLocalIP()
 	extension.SetRegistry(Name, newETCDV3Registry)
 }
 
 type etcdV3Registry struct {
-	*common.URL
-	birth int64 // time of file birth, seconds since Epoch; 0 if unknown
-
-	cltLock  sync.Mutex
-	client   *etcdv3.Client
-	services map[string]common.URL // service name + protocol -> service config
-
+	registry.BaseRegistry
+	cltLock        sync.Mutex
+	client         *etcdv3.Client
 	listenerLock   sync.Mutex
 	listener       *etcdv3.EventListener
 	dataListener   *dataListener
 	configListener *configurationListener
-
-	wg   sync.WaitGroup // wg+done for etcd client restart
-	done chan struct{}
 }
 
+// Client get the etcdv3 client
 func (r *etcdV3Registry) Client() *etcdv3.Client {
 	return r.client
 }
+
+//SetClient set the etcdv3 client
 func (r *etcdV3Registry) SetClient(client *etcdv3.Client) {
 	r.client = client
 }
+
+//
 func (r *etcdV3Registry) ClientLock() *sync.Mutex {
 	return &r.cltLock
 }
-func (r *etcdV3Registry) WaitGroup() *sync.WaitGroup {
-	return &r.wg
-}
-func (r *etcdV3Registry) GetDone() chan struct{} {
-	return r.done
-}
-func (r *etcdV3Registry) RestartCallBack() bool {
-
-	services := []common.URL{}
-	for _, confIf := range r.services {
-		services = append(services, confIf)
-	}
-
-	flag := true
-	for _, confIf := range services {
-		err := r.Register(confIf)
-		if err != nil {
-			logger.Errorf("(etcdV3ProviderRegistry)register(conf{%#v}) = error{%#v}",
-				confIf, perrors.WithStack(err))
-			flag = false
-			break
-		}
-		logger.Infof("success to re-register service :%v", confIf.Key())
-	}
-	return flag
-}
 
 func newETCDV3Registry(url *common.URL) (registry.Registry, error) {
 
@@ -122,12 +83,9 @@ func newETCDV3Registry(url *common.URL) (registry.Registry, error) {
 
 	logger.Infof("etcd address is: %v, timeout is: %s", url.Location, timeout.String())
 
-	r := &etcdV3Registry{
-		URL:      url,
-		birth:    time.Now().UnixNano(),
-		done:     make(chan struct{}),
-		services: make(map[string]common.URL),
-	}
+	r := &etcdV3Registry{}
+
+	r.InitBaseRegistry(url, r)
 
 	if err := etcdv3.ValidateClient(
 		r,
@@ -137,89 +95,37 @@ func newETCDV3Registry(url *common.URL) (registry.Registry, error) {
 	); err != nil {
 		return nil, err
 	}
+	r.WaitGroup().Add(1) //etcdv3 client start successful, then wg +1
 
-	r.wg.Add(1)
 	go etcdv3.HandleClientRestart(r)
 
-	r.listener = etcdv3.NewEventListener(r.client)
-	r.configListener = NewConfigurationListener(r)
-	r.dataListener = NewRegistryDataListener(r.configListener)
+	r.InitListeners()
 
 	return r, nil
 }
 
-func (r *etcdV3Registry) GetUrl() common.URL {
-	return *r.URL
-}
-
-func (r *etcdV3Registry) IsAvailable() bool {
-
-	select {
-	case <-r.done:
-		return false
-	default:
-		return true
-	}
+func (r *etcdV3Registry) InitListeners() {
+	r.listener = etcdv3.NewEventListener(r.client)
+	r.configListener = NewConfigurationListener(r)
+	r.dataListener = NewRegistryDataListener(r.configListener)
 }
 
-func (r *etcdV3Registry) Destroy() {
-
-	if r.configListener != nil {
-		r.configListener.Close()
-	}
-	r.stop()
+func (r *etcdV3Registry) DoRegister(root string, node string) error {
+	return r.client.Create(path.Join(root, node), "")
 }
 
-func (r *etcdV3Registry) stop() {
-
-	close(r.done)
-
-	// close current client
+func (r *etcdV3Registry) CloseAndNilClient() {
 	r.client.Close()
-
-	r.cltLock.Lock()
 	r.client = nil
-	r.services = nil
-	r.cltLock.Unlock()
 }
 
-func (r *etcdV3Registry) Register(svc common.URL) error {
-
-	role, err := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, ""))
-	if err != nil {
-		return perrors.WithMessage(err, "get registry role")
-	}
-
-	r.cltLock.Lock()
-	if _, ok := r.services[svc.Key()]; ok {
-		r.cltLock.Unlock()
-		return perrors.New(fmt.Sprintf("Path{%s} has been registered", svc.Path))
-	}
-	r.cltLock.Unlock()
-
-	switch role {
-	case common.PROVIDER:
-		logger.Debugf("(provider register )Register(conf{%#v})", svc)
-		if err := r.registerProvider(svc); err != nil {
-			return perrors.WithMessage(err, "register provider")
-		}
-	case common.CONSUMER:
-		logger.Debugf("(consumer register )Register(conf{%#v})", svc)
-		if err := r.registerConsumer(svc); err != nil {
-			return perrors.WithMessage(err, "register consumer")
-		}
-	default:
-		return perrors.New(fmt.Sprintf("unknown role %d", role))
+func (r *etcdV3Registry) CloseListener() {
+	if r.configListener != nil {
+		r.configListener.Close()
 	}
-
-	r.cltLock.Lock()
-	r.services[svc.Key()] = svc
-	r.cltLock.Unlock()
-	return nil
 }
 
-func (r *etcdV3Registry) createDirIfNotExist(k string) error {
-
+func (r *etcdV3Registry) CreatePath(k string) error {
 	var tmpPath string
 	for _, str := range strings.Split(k, "/")[1:] {
 		tmpPath = path.Join(tmpPath, "/", str)
@@ -231,89 +137,7 @@ func (r *etcdV3Registry) createDirIfNotExist(k string) error {
 	return nil
 }
 
-func (r *etcdV3Registry) registerConsumer(svc common.URL) error {
-
-	consumersNode := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), common.DubboNodes[common.CONSUMER])
-	if err := r.createDirIfNotExist(consumersNode); err != nil {
-		logger.Errorf("etcd client create path %s: %v", consumersNode, err)
-		return perrors.WithMessage(err, "etcd create consumer nodes")
-	}
-	providersNode := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), common.DubboNodes[common.PROVIDER])
-	if err := r.createDirIfNotExist(providersNode); err != nil {
-		return perrors.WithMessage(err, "create provider node")
-	}
-
-	params := url.Values{}
-
-	params.Add("protocol", svc.Protocol)
-
-	params.Add("category", (common.RoleType(common.CONSUMER)).String())
-	params.Add("dubbo", "dubbogo-consumer-"+constant.Version)
-
-	encodedURL := url.QueryEscape(fmt.Sprintf("consumer://%s%s?%s", localIP, svc.Path, params.Encode()))
-	dubboPath := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), (common.RoleType(common.CONSUMER)).String())
-	if err := r.client.Create(path.Join(dubboPath, encodedURL), ""); err != nil {
-		return perrors.WithMessagef(err, "create k/v in etcd (path:%s, url:%s)", dubboPath, encodedURL)
-	}
-
-	return nil
-}
-
-func (r *etcdV3Registry) registerProvider(svc common.URL) error {
-
-	if len(svc.Path) == 0 || len(svc.Methods) == 0 {
-		return perrors.New(fmt.Sprintf("service path %s or service method %s", svc.Path, svc.Methods))
-	}
-
-	var (
-		urlPath    string
-		encodedURL string
-		dubboPath  string
-	)
-
-	providersNode := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), common.DubboNodes[common.PROVIDER])
-	if err := r.createDirIfNotExist(providersNode); err != nil {
-		return perrors.WithMessage(err, "create provider node")
-	}
-
-	params := url.Values{}
-
-	svc.RangeParams(func(key, value string) bool {
-		params[key] = []string{value}
-		return true
-	})
-	params.Add("pid", processID)
-	params.Add("ip", localIP)
-	params.Add("anyhost", "true")
-	params.Add("category", (common.RoleType(common.PROVIDER)).String())
-	params.Add("dubbo", "dubbo-provider-golang-"+constant.Version)
-	params.Add("side", (common.RoleType(common.PROVIDER)).Role())
-
-	if len(svc.Methods) == 0 {
-		params.Add("methods", strings.Join(svc.Methods, ","))
-	}
-
-	logger.Debugf("provider url params:%#v", params)
-	var host string
-	if len(svc.Ip) == 0 {
-		host = localIP + ":" + svc.Port
-	} else {
-		host = svc.Ip + ":" + svc.Port
-	}
-
-	urlPath = svc.Path
-
-	encodedURL = url.QueryEscape(fmt.Sprintf("%s://%s%s?%s", svc.Protocol, host, urlPath, params.Encode()))
-	dubboPath = fmt.Sprintf("/dubbo/%s/%s", svc.Service(), (common.RoleType(common.PROVIDER)).String())
-
-	if err := r.client.Create(path.Join(dubboPath, encodedURL), ""); err != nil {
-		return perrors.WithMessagef(err, "create k/v in etcd (path:%s, url:%s)", dubboPath, encodedURL)
-	}
-
-	return nil
-}
-
-func (r *etcdV3Registry) subscribe(svc *common.URL) (registry.Listener, error) {
+func (r *etcdV3Registry) DoSubscribe(svc *common.URL) (registry.Listener, error) {
 
 	var (
 		configListener *configurationListener
@@ -346,37 +170,3 @@ func (r *etcdV3Registry) subscribe(svc *common.URL) (registry.Listener, error) {
 
 	return configListener, nil
 }
-
-//subscribe from registry
-func (r *etcdV3Registry) Subscribe(url *common.URL, notifyListener registry.NotifyListener) {
-	for {
-		if !r.IsAvailable() {
-			logger.Warnf("event listener game over.")
-			return
-		}
-
-		listener, err := r.subscribe(url)
-		if err != nil {
-			if !r.IsAvailable() {
-				logger.Warnf("event listener game over.")
-				return
-			}
-			logger.Warnf("getListener() = err:%v", perrors.WithStack(err))
-			time.Sleep(time.Duration(RegistryConnDelay) * time.Second)
-			continue
-		}
-
-		for {
-			if serviceEvent, err := listener.Next(); err != nil {
-				logger.Warnf("Selector.watch() = error{%v}", perrors.WithStack(err))
-				listener.Close()
-				return
-			} else {
-				logger.Infof("update begin, service event: %v", serviceEvent.String())
-				notifyListener.Notify(serviceEvent)
-			}
-
-		}
-
-	}
-}
diff --git a/registry/etcdv3/registry_test.go b/registry/etcdv3/registry_test.go
index 3f8c0f4cfccc2bcc68fc1e55fa69d74e9f0f8c0f..6e26a8f3fcbbf50592520a44b253e5abbaedb061 100644
--- a/registry/etcdv3/registry_test.go
+++ b/registry/etcdv3/registry_test.go
@@ -18,7 +18,6 @@
 package etcdv3
 
 import (
-	"context"
 	"strconv"
 	"testing"
 	"time"
@@ -35,7 +34,7 @@ import (
 
 func initRegistry(t *testing.T) *etcdV3Registry {
 
-	regurl, err := common.NewURL(context.Background(), "registry://127.0.0.1:2379", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	regurl, err := common.NewURL("registry://127.0.0.1:2379", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -46,7 +45,8 @@ func initRegistry(t *testing.T) *etcdV3Registry {
 	}
 
 	out := reg.(*etcdV3Registry)
-	out.client.CleanKV()
+	err = out.client.CleanKV()
+	assert.NoError(t, err)
 	return out
 }
 
@@ -54,23 +54,24 @@ func (suite *RegistryTestSuite) TestRegister() {
 
 	t := suite.T()
 
-	url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	reg := initRegistry(t)
 	err := reg.Register(url)
+	assert.NoError(t, err)
 	children, _, err := reg.client.GetChildrenKVList("/dubbo/com.ikurento.user.UserProvider/providers")
 	if err != nil {
 		t.Fatal(err)
 	}
-	assert.Regexp(t, ".*dubbo%3A%2F%2F127.0.0.1%3A20000%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26category%3Dproviders%26cluster%3Dmock%26dubbo%3Ddubbo-provider-golang-2.6.0%26.*provider", children)
+	assert.Regexp(t, ".*dubbo%3A%2F%2F127.0.0.1%3A20000%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26category%3Dproviders%26cluster%3Dmock%26dubbo%3Ddubbo-provider-golang-1.3.0%26.*provider", children)
 	assert.NoError(t, err)
 }
 
 func (suite *RegistryTestSuite) TestSubscribe() {
 
 	t := suite.T()
-	regurl, _ := common.NewURL(context.Background(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
-	url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	reg := initRegistry(t)
 	//provider register
@@ -83,8 +84,9 @@ func (suite *RegistryTestSuite) TestSubscribe() {
 	regurl.SetParam(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
 	reg2 := initRegistry(t)
 
-	reg2.Register(url)
-	listener, err := reg2.subscribe(&url)
+	err = reg2.Register(url)
+	assert.NoError(t, err)
+	listener, err := reg2.DoSubscribe(&url)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -99,10 +101,10 @@ func (suite *RegistryTestSuite) TestSubscribe() {
 func (suite *RegistryTestSuite) TestConsumerDestory() {
 
 	t := suite.T()
-	url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	reg := initRegistry(t)
-	_, err := reg.subscribe(&url)
+	_, err := reg.DoSubscribe(&url)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -119,8 +121,9 @@ func (suite *RegistryTestSuite) TestProviderDestory() {
 
 	t := suite.T()
 	reg := initRegistry(t)
-	url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
-	reg.Register(url)
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	err := reg.Register(url)
+	assert.NoError(t, err)
 
 	//listener.Close()
 	time.Sleep(1e9)
diff --git a/registry/event.go b/registry/event.go
index 24f5b72e8b27d4dc727e72d641d8bae3e00ff165..37d863d2162cb3b9d6a9f7eba8823286eb99441c 100644
--- a/registry/event.go
+++ b/registry/event.go
@@ -36,6 +36,7 @@ func init() {
 // service event
 //////////////////////////////////////////
 
+// ServiceEvent ...
 type ServiceEvent struct {
 	Action  remoting.EventType
 	Service common.URL
diff --git a/registry/mock_registry.go b/registry/mock_registry.go
index 512c452e39082d619ffceae7f82d28127fbe2975..9591928eebd22bf2a99ec9dcfeb285c4519a3b90 100644
--- a/registry/mock_registry.go
+++ b/registry/mock_registry.go
@@ -30,11 +30,13 @@ import (
 	"github.com/apache/dubbo-go/common/logger"
 )
 
+// MockRegistry ...
 type MockRegistry struct {
 	listener  *listener
 	destroyed *atomic.Bool
 }
 
+// NewMockRegistry ...
 func NewMockRegistry(url *common.URL) (Registry, error) {
 	registry := &MockRegistry{
 		destroyed: atomic.NewBool(false),
@@ -43,17 +45,24 @@ func NewMockRegistry(url *common.URL) (Registry, error) {
 	registry.listener = listener
 	return registry, nil
 }
+
+// Register ...
 func (*MockRegistry) Register(url common.URL) error {
 	return nil
 }
 
+// Destroy ...
 func (r *MockRegistry) Destroy() {
 	if r.destroyed.CAS(false, true) {
 	}
 }
+
+// IsAvailable ...
 func (r *MockRegistry) IsAvailable() bool {
 	return !r.destroyed.Load()
 }
+
+// GetUrl ...
 func (r *MockRegistry) GetUrl() common.URL {
 	return common.URL{}
 }
@@ -61,6 +70,8 @@ func (r *MockRegistry) GetUrl() common.URL {
 func (r *MockRegistry) subscribe(*common.URL) (Listener, error) {
 	return r.listener, nil
 }
+
+// Subscribe ...
 func (r *MockRegistry) Subscribe(url *common.URL, notifyListener NotifyListener) {
 	go func() {
 		for {
@@ -81,17 +92,16 @@ func (r *MockRegistry) Subscribe(url *common.URL, notifyListener NotifyListener)
 			}
 
 			for {
-				if serviceEvent, err := listener.Next(); err != nil {
+				serviceEvent, err := listener.Next()
+				if err != nil {
 					listener.Close()
 					time.Sleep(time.Duration(3) * time.Second)
 					return
-				} else {
-					logger.Infof("update begin, service event: %v", serviceEvent.String())
-					notifyListener.Notify(serviceEvent)
 				}
 
+				logger.Infof("update begin, service event: %v", serviceEvent.String())
+				notifyListener.Notify(serviceEvent)
 			}
-
 		}
 	}()
 }
@@ -113,6 +123,7 @@ func (*listener) Close() {
 
 }
 
+// MockEvent ...
 func (r *MockRegistry) MockEvent(event *ServiceEvent) {
 	r.listener.listenChan <- event
 }
diff --git a/registry/nacos/listener.go b/registry/nacos/listener.go
index 25cd3d09b5711e4e7db56cd8e40f3283f3252e10..a2237dca265f25b07b19a8e1f4fe5a5f6ea9183e 100644
--- a/registry/nacos/listener.go
+++ b/registry/nacos/listener.go
@@ -51,6 +51,7 @@ type nacosListener struct {
 	subscribeParam *vo.SubscribeParam
 }
 
+// NewNacosListener ...
 func NewNacosListener(url common.URL, namingClient naming_client.INamingClient) (*nacosListener, error) {
 	listener := &nacosListener{
 		namingClient: namingClient,
diff --git a/registry/nacos/registry.go b/registry/nacos/registry.go
index a8b9fa83fa73858064e570722341c14f974f5c9e..965e91e894ac61562bfd25c8f564f789afd6c8a1 100644
--- a/registry/nacos/registry.go
+++ b/registry/nacos/registry.go
@@ -47,6 +47,7 @@ var (
 )
 
 const (
+	//RegistryConnDelay registry connection delay
 	RegistryConnDelay = 3
 )
 
@@ -209,15 +210,15 @@ func (nr *nacosRegistry) Subscribe(url *common.URL, notifyListener registry.Noti
 		}
 
 		for {
-			if serviceEvent, err := listener.Next(); err != nil {
+			serviceEvent, err := listener.Next()
+			if err != nil {
 				logger.Warnf("Selector.watch() = error{%v}", perrors.WithStack(err))
 				listener.Close()
 				return
-			} else {
-				logger.Infof("update begin, service event: %v", serviceEvent.String())
-				notifyListener.Notify(serviceEvent)
 			}
 
+			logger.Infof("update begin, service event: %v", serviceEvent.String())
+			notifyListener.Notify(serviceEvent)
 		}
 
 	}
diff --git a/registry/nacos/registry_test.go b/registry/nacos/registry_test.go
index e6ab693cd3f5432fe30c2b83011cd56e44ac509f..7475b455c0dda09da65012465711ece264bb3dd5 100644
--- a/registry/nacos/registry_test.go
+++ b/registry/nacos/registry_test.go
@@ -18,7 +18,6 @@
 package nacos
 
 import (
-	"context"
 	"encoding/json"
 	"net/url"
 	"strconv"
@@ -36,14 +35,14 @@ import (
 )
 
 func TestNacosRegistry_Register(t *testing.T) {
-	regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
 	urlMap := url.Values{}
 	urlMap.Set(constant.GROUP_KEY, "guangzhou-idc")
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
 	urlMap.Set(constant.INTERFACE_KEY, "com.ikurento.user.UserProvider")
 	urlMap.Set(constant.VERSION_KEY, "1.0.0")
 	urlMap.Set(constant.CLUSTER_KEY, "mock")
-	url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	reg, err := newNacosRegistry(&regurl)
 	assert.Nil(t, err)
@@ -65,7 +64,7 @@ func TestNacosRegistry_Register(t *testing.T) {
 }
 
 func TestNacosRegistry_Subscribe(t *testing.T) {
-	regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
 	urlMap := url.Values{}
 	urlMap.Set(constant.GROUP_KEY, "guangzhou-idc")
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
@@ -73,7 +72,7 @@ func TestNacosRegistry_Subscribe(t *testing.T) {
 	urlMap.Set(constant.VERSION_KEY, "1.0.0")
 	urlMap.Set(constant.CLUSTER_KEY, "mock")
 	urlMap.Set(constant.NACOS_PATH_KEY, "")
-	url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	reg, _ := newNacosRegistry(&regurl)
 	err := reg.Register(url)
@@ -103,7 +102,7 @@ func TestNacosRegistry_Subscribe(t *testing.T) {
 }
 
 func TestNacosRegistry_Subscribe_del(t *testing.T) {
-	regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
 	urlMap := url.Values{}
 	urlMap.Set(constant.GROUP_KEY, "guangzhou-idc")
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
@@ -111,8 +110,8 @@ func TestNacosRegistry_Subscribe_del(t *testing.T) {
 	urlMap.Set(constant.VERSION_KEY, "2.0.0")
 	urlMap.Set(constant.CLUSTER_KEY, "mock")
 	urlMap.Set(constant.NACOS_PATH_KEY, "")
-	url1, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
-	url2, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.2:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+	url1, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+	url2, _ := common.NewURL("dubbo://127.0.0.2:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	reg, _ := newNacosRegistry(&regurl)
 	err := reg.Register(url1)
@@ -169,7 +168,7 @@ func TestNacosRegistry_Subscribe_del(t *testing.T) {
 }
 
 func TestNacosListener_Close(t *testing.T) {
-	regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
 	urlMap := url.Values{}
 	urlMap.Set(constant.GROUP_KEY, "guangzhou-idc")
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
@@ -177,7 +176,7 @@ func TestNacosListener_Close(t *testing.T) {
 	urlMap.Set(constant.VERSION_KEY, "1.0.0")
 	urlMap.Set(constant.CLUSTER_KEY, "mock")
 	urlMap.Set(constant.NACOS_PATH_KEY, "")
-	url1, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider2", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+	url1, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider2", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 	reg, _ := newNacosRegistry(&regurl)
 	listener, err := reg.(*nacosRegistry).subscribe(&url1)
 	assert.Nil(t, err)
diff --git a/registry/protocol/protocol.go b/registry/protocol/protocol.go
index 534a4b945965f332e49ff343557fa20355921454..748b8204d97e60c9803821290184fc5717c41025 100644
--- a/registry/protocol/protocol.go
+++ b/registry/protocol/protocol.go
@@ -18,12 +18,13 @@
 package protocol
 
 import (
+	"context"
 	"strings"
 	"sync"
 )
 
 import (
-	"github.com/dubbogo/gost/container/gxset"
+	gxset "github.com/dubbogo/gost/container/set"
 )
 
 import (
@@ -337,6 +338,7 @@ func setProviderUrl(regURL *common.URL, providerURL *common.URL) {
 	regURL.SubURL = providerURL
 }
 
+// GetProtocol ...
 func GetProtocol() protocol.Protocol {
 	if regProtocol != nil {
 		return regProtocol
@@ -356,10 +358,10 @@ func newWrappedInvoker(invoker protocol.Invoker, url *common.URL) *wrappedInvoke
 	}
 }
 
-func (ivk *wrappedInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+func (ivk *wrappedInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	// get right url
 	ivk.invoker.(*proxy_factory.ProxyInvoker).BaseInvoker = *protocol.NewBaseInvoker(ivk.GetUrl())
-	return ivk.invoker.Invoke(invocation)
+	return ivk.invoker.Invoke(ctx, invocation)
 }
 
 type providerConfigurationListener struct {
diff --git a/registry/protocol/protocol_test.go b/registry/protocol/protocol_test.go
index 0c19da59df6e4fd2f663f9e8d541165fe26c3ffa..de57a0afa7529dd5c77c1fe5440b336cdd212fca 100644
--- a/registry/protocol/protocol_test.go
+++ b/registry/protocol/protocol_test.go
@@ -18,7 +18,6 @@
 package protocol
 
 import (
-	"context"
 	"testing"
 	"time"
 )
@@ -51,9 +50,8 @@ func referNormal(t *testing.T, regProtocol *registryProtocol) {
 	extension.SetProtocol(protocolwrapper.FILTER, protocolwrapper.NewMockProtocolFilter)
 	extension.SetCluster("mock", cluster.NewMockCluster)
 
-	url, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111")
+	url, _ := common.NewURL("mock://127.0.0.1:1111")
 	suburl, _ := common.NewURL(
-		context.TODO(),
 		"dubbo://127.0.0.1:20000//",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 	)
@@ -76,9 +74,8 @@ func TestRefer(t *testing.T) {
 func TestMultiRegRefer(t *testing.T) {
 	regProtocol := newRegistryProtocol()
 	referNormal(t, regProtocol)
-	url2, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:2222")
+	url2, _ := common.NewURL("mock://127.0.0.1:2222")
 	suburl2, _ := common.NewURL(
-		context.TODO(),
 		"dubbo://127.0.0.1:20000//",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 	)
@@ -98,9 +95,8 @@ func TestOneRegRefer(t *testing.T) {
 	regProtocol := newRegistryProtocol()
 	referNormal(t, regProtocol)
 
-	url2, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111")
+	url2, _ := common.NewURL("mock://127.0.0.1:1111")
 	suburl2, _ := common.NewURL(
-		context.TODO(),
 		"dubbo://127.0.0.1:20000//",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 	)
@@ -120,9 +116,8 @@ func exporterNormal(t *testing.T, regProtocol *registryProtocol) *common.URL {
 	extension.SetProtocol("registry", GetProtocol)
 	extension.SetRegistry("mock", registry.NewMockRegistry)
 	extension.SetProtocol(protocolwrapper.FILTER, protocolwrapper.NewMockProtocolFilter)
-	url, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111")
+	url, _ := common.NewURL("mock://127.0.0.1:1111")
 	suburl, _ := common.NewURL(
-		context.TODO(),
 		"dubbo://127.0.0.1:20000/org.apache.dubbo-go.mockService",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 		common.WithParamsValue(constant.GROUP_KEY, "group"),
@@ -148,9 +143,8 @@ func TestMultiRegAndMultiProtoExporter(t *testing.T) {
 	regProtocol := newRegistryProtocol()
 	exporterNormal(t, regProtocol)
 
-	url2, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:2222")
+	url2, _ := common.NewURL("mock://127.0.0.1:2222")
 	suburl2, _ := common.NewURL(
-		context.TODO(),
 		"jsonrpc://127.0.0.1:20000//",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 	)
@@ -178,9 +172,8 @@ func TestOneRegAndProtoExporter(t *testing.T) {
 	regProtocol := newRegistryProtocol()
 	exporterNormal(t, regProtocol)
 
-	url2, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111")
+	url2, _ := common.NewURL("mock://127.0.0.1:1111")
 	suburl2, _ := common.NewURL(
-		context.TODO(),
 		"dubbo://127.0.0.1:20000/org.apache.dubbo-go.mockService",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 		common.WithParamsValue(constant.GROUP_KEY, "group"),
@@ -242,7 +235,6 @@ func TestExportWithOverrideListener(t *testing.T) {
 		return
 	}
 	overrideUrl, _ := common.NewURL(
-		context.Background(),
 		"override://0:0:0:0/org.apache.dubbo-go.mockService?cluster=mock1&&group=group&&version=1.0.0",
 	)
 	event := &registry.ServiceEvent{Action: remoting.EventTypeAdd, Service: overrideUrl}
@@ -256,7 +248,7 @@ func TestExportWithOverrideListener(t *testing.T) {
 
 func TestExportWithServiceConfig(t *testing.T) {
 	extension.SetDefaultConfigurator(configurator.NewMockConfigurator)
-	ccUrl, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111")
+	ccUrl, _ := common.NewURL("mock://127.0.0.1:1111")
 	dc, _ := (&config_center.MockDynamicConfigurationFactory{}).GetDynamicConfiguration(&ccUrl)
 	common_cfg.GetEnvInstance().SetDynamicConfiguration(dc)
 	regProtocol := newRegistryProtocol()
@@ -275,7 +267,7 @@ func TestExportWithServiceConfig(t *testing.T) {
 
 func TestExportWithApplicationConfig(t *testing.T) {
 	extension.SetDefaultConfigurator(configurator.NewMockConfigurator)
-	ccUrl, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111")
+	ccUrl, _ := common.NewURL("mock://127.0.0.1:1111")
 	dc, _ := (&config_center.MockDynamicConfigurationFactory{}).GetDynamicConfiguration(&ccUrl)
 	common_cfg.GetEnvInstance().SetDynamicConfiguration(dc)
 	regProtocol := newRegistryProtocol()
diff --git a/registry/registry.go b/registry/registry.go
index c7279a29e1f423ca200aa2bf9390c127efcf10cb..d673864700e6ba99e8f0283247d53760b85598aa 100644
--- a/registry/registry.go
+++ b/registry/registry.go
@@ -21,7 +21,13 @@ import (
 	"github.com/apache/dubbo-go/common"
 )
 
-// Extension - Registry
+/*
+ * -----------------------------------NOTICE---------------------------------------------
+ * If there is no special case, you'd better inherit BaseRegistry and implement the
+ * FacadeBasedRegistry interface instead of directly implementing the Registry interface.
+ * --------------------------------------------------------------------------------------
+ */
+// Registry Extension - Registry
 type Registry interface {
 	common.Node
 	//used for service provider calling , register services to registry
@@ -38,11 +44,13 @@ type Registry interface {
 	//mode2 : callback mode, subscribe with notify(notify listener).
 	Subscribe(*common.URL, NotifyListener)
 }
+
+// NotifyListener ...
 type NotifyListener interface {
 	Notify(*ServiceEvent)
 }
 
-//Deprecated!
+// Listener Deprecated!
 type Listener interface {
 	Next() (*ServiceEvent, error)
 	Close()
diff --git a/registry/zookeeper/listener.go b/registry/zookeeper/listener.go
index 53a592609153003d7d6c24881bccde0dfe6cdde6..588e0c519288ed32a2453fac87d226b41d4a5194 100644
--- a/registry/zookeeper/listener.go
+++ b/registry/zookeeper/listener.go
@@ -18,7 +18,6 @@
 package zookeeper
 
 import (
-	"context"
 	"strings"
 	"sync"
 )
@@ -36,18 +35,23 @@ import (
 	zk "github.com/apache/dubbo-go/remoting/zookeeper"
 )
 
+// RegistryDataListener ...
 type RegistryDataListener struct {
 	interestedURL []*common.URL
 	listener      config_center.ConfigurationListener
 }
 
+// NewRegistryDataListener ...
 func NewRegistryDataListener(listener config_center.ConfigurationListener) *RegistryDataListener {
 	return &RegistryDataListener{listener: listener, interestedURL: []*common.URL{}}
 }
+
+// AddInterestedURL ...
 func (l *RegistryDataListener) AddInterestedURL(url *common.URL) {
 	l.interestedURL = append(l.interestedURL, url)
 }
 
+// DataChange ...
 func (l *RegistryDataListener) DataChange(eventType remoting.Event) bool {
 	// Intercept the last bit
 	index := strings.Index(eventType.Path, "/providers/")
@@ -56,7 +60,7 @@ func (l *RegistryDataListener) DataChange(eventType remoting.Event) bool {
 		return false
 	}
 	url := eventType.Path[index+len("/providers/"):]
-	serviceURL, err := common.NewURL(context.TODO(), url)
+	serviceURL, err := common.NewURL(url)
 	if err != nil {
 		logger.Errorf("Listen NewURL(r{%s}) = error{%v} eventType.Path={%v}", url, err, eventType.Path)
 		return false
@@ -71,6 +75,7 @@ func (l *RegistryDataListener) DataChange(eventType remoting.Event) bool {
 	return false
 }
 
+// RegistryConfigurationListener ...
 type RegistryConfigurationListener struct {
 	client    *zk.ZookeeperClient
 	registry  *zkRegistry
@@ -79,14 +84,18 @@ type RegistryConfigurationListener struct {
 	closeOnce sync.Once
 }
 
+// NewRegistryConfigurationListener for listening the event of zk.
 func NewRegistryConfigurationListener(client *zk.ZookeeperClient, reg *zkRegistry) *RegistryConfigurationListener {
-	reg.wg.Add(1)
+	reg.WaitGroup().Add(1)
 	return &RegistryConfigurationListener{client: client, registry: reg, events: make(chan *config_center.ConfigChangeEvent, 32), isClosed: false}
 }
+
+// Process ...
 func (l *RegistryConfigurationListener) Process(configType *config_center.ConfigChangeEvent) {
 	l.events <- configType
 }
 
+// Next ...
 func (l *RegistryConfigurationListener) Next() (*registry.ServiceEvent, error) {
 	for {
 		select {
@@ -94,7 +103,7 @@ func (l *RegistryConfigurationListener) Next() (*registry.ServiceEvent, error) {
 			logger.Warnf("listener's zk client connection is broken, so zk event listener exit now.")
 			return nil, perrors.New("listener stopped")
 
-		case <-l.registry.done:
+		case <-l.registry.Done():
 			logger.Warnf("zk consumer register has quit, so zk event listener exit now.")
 			return nil, perrors.New("listener stopped")
 
@@ -111,11 +120,13 @@ func (l *RegistryConfigurationListener) Next() (*registry.ServiceEvent, error) {
 		}
 	}
 }
+
+// Close ...
 func (l *RegistryConfigurationListener) Close() {
 	// ensure that the listener will be closed at most once.
 	l.closeOnce.Do(func() {
 		l.isClosed = true
-		l.registry.wg.Done()
+		l.registry.WaitGroup().Done()
 	})
 }
 
diff --git a/registry/zookeeper/listener_test.go b/registry/zookeeper/listener_test.go
index 910d47b7e4e3d27c6f7245777cba1f46adc8e318..1a76b29a6f64e0329b289ce50218032a25f6f5cd 100644
--- a/registry/zookeeper/listener_test.go
+++ b/registry/zookeeper/listener_test.go
@@ -18,7 +18,6 @@
 package zookeeper
 
 import (
-	"context"
 	"testing"
 )
 
@@ -34,9 +33,9 @@ import (
 
 func Test_DataChange(t *testing.T) {
 	listener := NewRegistryDataListener(&MockDataListener{})
-	url, _ := common.NewURL(context.TODO(), "jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100")
+	url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100")
 	listener.AddInterestedURL(&url)
-	int := listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"})
+	int := listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"})
 	assert.Equal(t, true, int)
 }
 
diff --git a/registry/zookeeper/registry.go b/registry/zookeeper/registry.go
index 1defedc28a2d42183be8c2e5d77441d8831c1d30..f4e53dcc4219d947fea93a10bccc420811afd2b9 100644
--- a/registry/zookeeper/registry.go
+++ b/registry/zookeeper/registry.go
@@ -18,20 +18,16 @@
 package zookeeper
 
 import (
-	"context"
 	"fmt"
 	"net/url"
-	"os"
-	"strconv"
 	"strings"
 	"sync"
 	"time"
 )
 
 import (
-	gxnet "github.com/dubbogo/gost/net"
+	"github.com/dubbogo/go-zookeeper/zk"
 	perrors "github.com/pkg/errors"
-	"github.com/samuel/go-zookeeper/zk"
 )
 
 import (
@@ -44,20 +40,11 @@ import (
 )
 
 const (
-	RegistryZkClient  = "zk registry"
-	RegistryConnDelay = 3
-	MaxWaitInterval   = time.Duration(3e9)
-)
-
-var (
-	processID = ""
-	localIP   = ""
+	// RegistryZkClient zk client name
+	RegistryZkClient = "zk registry"
 )
 
 func init() {
-	processID = fmt.Sprintf("%d", os.Getpid())
-	localIP, _ = gxnet.GetLocalIP()
-	//plugins.PluggableRegistries["zookeeper"] = newZkRegistry
 	extension.SetRegistry("zookeeper", newZkRegistry)
 }
 
@@ -66,20 +53,13 @@ func init() {
 /////////////////////////////////////
 
 type zkRegistry struct {
-	context context.Context
-	*common.URL
-	birth int64          // time of file birth, seconds since Epoch; 0 if unknown
-	wg    sync.WaitGroup // wg+done for zk restart
-	done  chan struct{}
-
-	cltLock  sync.Mutex
-	client   *zookeeper.ZookeeperClient
-	services map[string]common.URL // service name + protocol -> service config
-
+	registry.BaseRegistry
+	client         *zookeeper.ZookeeperClient
 	listenerLock   sync.Mutex
 	listener       *zookeeper.ZkEventListener
 	dataListener   *RegistryDataListener
 	configListener *RegistryConfigurationListener
+	cltLock        sync.Mutex
 	//for provider
 	zkPath map[string]int // key = protocol://ip:port/interface
 }
@@ -89,21 +69,17 @@ func newZkRegistry(url *common.URL) (registry.Registry, error) {
 		err error
 		r   *zkRegistry
 	)
-
 	r = &zkRegistry{
-		URL:      url,
-		birth:    time.Now().UnixNano(),
-		done:     make(chan struct{}),
-		services: make(map[string]common.URL),
-		zkPath:   make(map[string]int),
+		zkPath: make(map[string]int),
 	}
+	r.InitBaseRegistry(url, r)
 
 	err = zookeeper.ValidateZookeeperClient(r, zookeeper.WithZkName(RegistryZkClient))
 	if err != nil {
 		return nil, err
 	}
+	r.WaitGroup().Add(1) //zk client start successful, then wg +1
 
-	r.wg.Add(1)
 	go zookeeper.HandleClientRestart(r)
 
 	r.listener = zookeeper.NewZkEventListener(r.client)
@@ -113,10 +89,12 @@ func newZkRegistry(url *common.URL) (registry.Registry, error) {
 	return r, nil
 }
 
+// Options ...
 type Options struct {
 	client *zookeeper.ZookeeperClient
 }
 
+// Option ...
 type Option func(*Options)
 
 func newMockZkRegistry(url *common.URL, opts ...zookeeper.Option) (*zk.TestCluster, *zkRegistry, error) {
@@ -128,27 +106,41 @@ func newMockZkRegistry(url *common.URL, opts ...zookeeper.Option) (*zk.TestClust
 	)
 
 	r = &zkRegistry{
-		URL:      url,
-		birth:    time.Now().UnixNano(),
-		done:     make(chan struct{}),
-		services: make(map[string]common.URL),
-		zkPath:   make(map[string]int),
+		zkPath: make(map[string]int),
 	}
-
+	r.InitBaseRegistry(url, r)
 	c, r.client, _, err = zookeeper.NewMockZookeeperClient("test", 15*time.Second, opts...)
 	if err != nil {
 		return nil, nil, err
 	}
-	r.wg.Add(1)
+	r.WaitGroup().Add(1) //zk client start successful, then wg +1
 	go zookeeper.HandleClientRestart(r)
+	r.InitListeners()
+	return c, r, nil
+}
 
+func (r *zkRegistry) InitListeners() {
 	r.listener = zookeeper.NewZkEventListener(r.client)
 	r.configListener = NewRegistryConfigurationListener(r.client, r)
 	r.dataListener = NewRegistryDataListener(r.configListener)
+}
 
-	return c, r, nil
+func (r *zkRegistry) CreatePath(path string) error {
+	return r.ZkClient().Create(path)
+}
+
+func (r *zkRegistry) DoRegister(root string, node string) error {
+	return r.registerTempZookeeperNode(root, node)
+}
+
+func (r *zkRegistry) DoSubscribe(conf *common.URL) (registry.Listener, error) {
+	return r.getListener(conf)
 }
 
+func (r *zkRegistry) CloseAndNilClient() {
+	r.client.Close()
+	r.client = nil
+}
 func (r *zkRegistry) ZkClient() *zookeeper.ZookeeperClient {
 	return r.client
 }
@@ -161,221 +153,10 @@ func (r *zkRegistry) ZkClientLock() *sync.Mutex {
 	return &r.cltLock
 }
 
-func (r *zkRegistry) WaitGroup() *sync.WaitGroup {
-	return &r.wg
-}
-
-func (r *zkRegistry) GetDone() chan struct{} {
-	return r.done
-}
-
-func (r *zkRegistry) GetUrl() common.URL {
-	return *r.URL
-}
-
-func (r *zkRegistry) Destroy() {
+func (r *zkRegistry) CloseListener() {
 	if r.configListener != nil {
 		r.configListener.Close()
 	}
-	close(r.done)
-	r.wg.Wait()
-	r.closeRegisters()
-}
-
-func (r *zkRegistry) RestartCallBack() bool {
-
-	// copy r.services
-	services := []common.URL{}
-	for _, confIf := range r.services {
-		services = append(services, confIf)
-	}
-
-	flag := true
-	for _, confIf := range services {
-		err := r.register(confIf)
-		if err != nil {
-			logger.Errorf("(ZkProviderRegistry)register(conf{%#v}) = error{%#v}",
-				confIf, perrors.WithStack(err))
-			flag = false
-			break
-		}
-		logger.Infof("success to re-register service :%v", confIf.Key())
-	}
-	r.listener = zookeeper.NewZkEventListener(r.client)
-	r.configListener = NewRegistryConfigurationListener(r.client, r)
-	r.dataListener = NewRegistryDataListener(r.configListener)
-
-	return flag
-}
-
-func (r *zkRegistry) Register(conf common.URL) error {
-	var (
-		ok  bool
-		err error
-	)
-	role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, ""))
-	switch role {
-	case common.CONSUMER:
-		r.cltLock.Lock()
-		_, ok = r.services[conf.Key()]
-		r.cltLock.Unlock()
-		if ok {
-			return perrors.Errorf("Path{%s} has been registered", conf.Path)
-		}
-
-		err = r.register(conf)
-		if err != nil {
-			return perrors.WithStack(err)
-		}
-
-		r.cltLock.Lock()
-		r.services[conf.Key()] = conf
-		r.cltLock.Unlock()
-		logger.Debugf("(consumerZkConsumerRegistry)Register(conf{%#v})", conf)
-
-	case common.PROVIDER:
-
-		// Check if the service has been registered
-		r.cltLock.Lock()
-		// Note the difference between consumer and consumerZookeeperRegistry (consumer use conf.Path).
-		// Because the consumer wants to provide monitoring functions for the selector,
-		// the provider allows multiple groups or versions of the same service to be registered.
-		_, ok = r.services[conf.Key()]
-		r.cltLock.Unlock()
-		if ok {
-			return perrors.Errorf("Path{%s} has been registered", conf.Key())
-		}
-
-		err = r.register(conf)
-		if err != nil {
-			return perrors.WithMessagef(err, "register(conf:%+v)", conf)
-		}
-
-		r.cltLock.Lock()
-		r.services[conf.Key()] = conf
-		r.cltLock.Unlock()
-
-		logger.Debugf("(ZkProviderRegistry)Register(conf{%#v})", conf)
-	}
-
-	return nil
-}
-
-func (r *zkRegistry) service(c common.URL) string {
-	return url.QueryEscape(c.Service())
-}
-
-func (r *zkRegistry) register(c common.URL) error {
-	var (
-		err error
-		//revision   string
-		params     url.Values
-		rawURL     string
-		encodedURL string
-		dubboPath  string
-		//conf       config.URL
-	)
-
-	err = zookeeper.ValidateZookeeperClient(r, zookeeper.WithZkName(RegistryZkClient))
-	if err != nil {
-		return perrors.WithStack(err)
-	}
-	params = url.Values{}
-
-	c.RangeParams(func(key, value string) bool {
-		params.Add(key, value)
-		return true
-	})
-
-	params.Add("pid", processID)
-	params.Add("ip", localIP)
-	//params.Add("timeout", fmt.Sprintf("%d", int64(r.Timeout)/1e6))
-
-	role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, ""))
-	switch role {
-
-	case common.PROVIDER:
-
-		if c.Path == "" || len(c.Methods) == 0 {
-			return perrors.Errorf("conf{Path:%s, Methods:%s}", c.Path, c.Methods)
-		}
-		// 先创建服务下面的provider node
-		dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.PROVIDER])
-		r.cltLock.Lock()
-		err = r.client.Create(dubboPath)
-		r.cltLock.Unlock()
-		if err != nil {
-			logger.Errorf("zkClient.create(path{%s}) = error{%#v}", dubboPath, perrors.WithStack(err))
-			return perrors.WithMessagef(err, "zkclient.Create(path:%s)", dubboPath)
-		}
-		params.Add("anyhost", "true")
-
-		// Dubbo java consumer to start looking for the provider url,because the category does not match,
-		// the provider will not find, causing the consumer can not start, so we use consumers.
-		// DubboRole               = [...]string{"consumer", "", "", "provider"}
-		// params.Add("category", (RoleType(PROVIDER)).Role())
-		params.Add("category", (common.RoleType(common.PROVIDER)).String())
-		params.Add("dubbo", "dubbo-provider-golang-"+constant.Version)
-
-		params.Add("side", (common.RoleType(common.PROVIDER)).Role())
-
-		if len(c.Methods) == 0 {
-			params.Add("methods", strings.Join(c.Methods, ","))
-		}
-		logger.Debugf("provider zk url params:%#v", params)
-		var host string
-		if c.Ip == "" {
-			host = localIP + ":" + c.Port
-		} else {
-			host = c.Ip + ":" + c.Port
-		}
-
-		rawURL = fmt.Sprintf("%s://%s%s?%s", c.Protocol, host, c.Path, params.Encode())
-		encodedURL = url.QueryEscape(rawURL)
-
-		// Print your own registration service providers.
-		dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.PROVIDER)).String())
-		logger.Debugf("provider path:%s, url:%s", dubboPath, rawURL)
-
-	case common.CONSUMER:
-		dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.CONSUMER])
-		r.cltLock.Lock()
-		err = r.client.Create(dubboPath)
-		r.cltLock.Unlock()
-		if err != nil {
-			logger.Errorf("zkClient.create(path{%s}) = error{%v}", dubboPath, perrors.WithStack(err))
-			return perrors.WithStack(err)
-		}
-		dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.PROVIDER])
-		r.cltLock.Lock()
-		err = r.client.Create(dubboPath)
-		r.cltLock.Unlock()
-		if err != nil {
-			logger.Errorf("zkClient.create(path{%s}) = error{%v}", dubboPath, perrors.WithStack(err))
-			return perrors.WithStack(err)
-		}
-
-		params.Add("protocol", c.Protocol)
-
-		params.Add("category", (common.RoleType(common.CONSUMER)).String())
-		params.Add("dubbo", "dubbogo-consumer-"+constant.Version)
-
-		rawURL = fmt.Sprintf("consumer://%s%s?%s", localIP, c.Path, params.Encode())
-		encodedURL = url.QueryEscape(rawURL)
-
-		dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.CONSUMER)).String())
-		logger.Debugf("consumer path:%s, url:%s", dubboPath, rawURL)
-
-	default:
-		return perrors.Errorf("@c{%v} type is not referencer or provider", c)
-	}
-
-	err = r.registerTempZookeeperNode(dubboPath, encodedURL)
-
-	if err != nil {
-		return perrors.WithMessagef(err, "registerTempZookeeperNode(path:%s, url:%s)", dubboPath, rawURL)
-	}
-	return nil
 }
 
 func (r *zkRegistry) registerTempZookeeperNode(root string, node string) error {
@@ -405,53 +186,6 @@ func (r *zkRegistry) registerTempZookeeperNode(root string, node string) error {
 	return nil
 }
 
-func (r *zkRegistry) subscribe(conf *common.URL) (registry.Listener, error) {
-	return r.getListener(conf)
-}
-func sleepWait(n int) {
-	wait := time.Duration((n + 1) * 2e8)
-	if wait > MaxWaitInterval {
-		wait = MaxWaitInterval
-	}
-	time.Sleep(wait)
-}
-
-//subscribe from registry
-func (r *zkRegistry) Subscribe(url *common.URL, notifyListener registry.NotifyListener) {
-	n := 0
-	for {
-		n++
-		if !r.IsAvailable() {
-			logger.Warnf("event listener game over.")
-			return
-		}
-
-		listener, err := r.subscribe(url)
-		if err != nil {
-			if !r.IsAvailable() {
-				logger.Warnf("event listener game over.")
-				return
-			}
-			logger.Warnf("getListener() = err:%v", perrors.WithStack(err))
-			time.Sleep(time.Duration(RegistryConnDelay) * time.Second)
-			continue
-		}
-
-		for {
-			if serviceEvent, err := listener.Next(); err != nil {
-				logger.Warnf("Selector.watch() = error{%v}", perrors.WithStack(err))
-				listener.Close()
-				break
-			} else {
-				logger.Infof("update begin, service event: %v", serviceEvent.String())
-				notifyListener.Notify(serviceEvent)
-			}
-
-		}
-		sleepWait(n)
-	}
-}
-
 func (r *zkRegistry) getListener(conf *common.URL) (*RegistryConfigurationListener, error) {
 	var (
 		zkListener *RegistryConfigurationListener
@@ -488,22 +222,3 @@ func (r *zkRegistry) getListener(conf *common.URL) (*RegistryConfigurationListen
 
 	return zkListener, nil
 }
-
-func (r *zkRegistry) closeRegisters() {
-	r.cltLock.Lock()
-	defer r.cltLock.Unlock()
-	logger.Infof("begin to close provider zk client")
-	// Close the old client first to close the tmp node.
-	r.client.Close()
-	r.client = nil
-	r.services = nil
-}
-
-func (r *zkRegistry) IsAvailable() bool {
-	select {
-	case <-r.done:
-		return false
-	default:
-		return true
-	}
-}
diff --git a/registry/zookeeper/registry_test.go b/registry/zookeeper/registry_test.go
index 841c38da7fbf1830b6f7c55809fc50d52468ef46..0d7623ca12a9b4e49f84ec988c796f2e913d537f 100644
--- a/registry/zookeeper/registry_test.go
+++ b/registry/zookeeper/registry_test.go
@@ -18,7 +18,6 @@
 package zookeeper
 
 import (
-	"context"
 	"strconv"
 	"testing"
 	"time"
@@ -35,20 +34,20 @@ import (
 )
 
 func Test_Register(t *testing.T) {
-	regurl, _ := common.NewURL(context.TODO(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
-	url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithParamsValue("serviceid", "soa.mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithParamsValue("serviceid", "soa.mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	ts, reg, _ := newMockZkRegistry(&regurl)
 	defer ts.Stop()
 	err := reg.Register(url)
 	children, _ := reg.client.GetChildren("/dubbo/com.ikurento.user.UserProvider/providers")
-	assert.Regexp(t, ".*dubbo%3A%2F%2F127.0.0.1%3A20000%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26category%3Dproviders%26cluster%3Dmock%26dubbo%3Ddubbo-provider-golang-2.6.0%26.*.serviceid%3Dsoa.mock%26.*provider", children)
+	assert.Regexp(t, ".*dubbo%3A%2F%2F127.0.0.1%3A20000%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26category%3Dproviders%26cluster%3Dmock%26dubbo%3Ddubbo-provider-golang-1.3.0%26.*.serviceid%3Dsoa.mock%26.*provider", children)
 	assert.NoError(t, err)
 }
 
 func Test_Subscribe(t *testing.T) {
-	regurl, _ := common.NewURL(context.TODO(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
-	url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 	ts, reg, _ := newMockZkRegistry(&regurl)
 
 	//provider register
@@ -64,7 +63,7 @@ func Test_Subscribe(t *testing.T) {
 	_, reg2, _ := newMockZkRegistry(&regurl, zookeeper.WithTestCluster(ts))
 
 	reg2.Register(url)
-	listener, _ := reg2.subscribe(&url)
+	listener, _ := reg2.DoSubscribe(&url)
 
 	serviceEvent, _ := listener.Next()
 	assert.NoError(t, err)
@@ -76,8 +75,8 @@ func Test_Subscribe(t *testing.T) {
 }
 
 func Test_ConsumerDestory(t *testing.T) {
-	regurl, _ := common.NewURL(context.TODO(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER)))
-	url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER)))
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	ts, reg, err := newMockZkRegistry(&regurl)
 	defer ts.Stop()
@@ -85,7 +84,7 @@ func Test_ConsumerDestory(t *testing.T) {
 	assert.NoError(t, err)
 	err = reg.Register(url)
 	assert.NoError(t, err)
-	_, err = reg.subscribe(&url)
+	_, err = reg.DoSubscribe(&url)
 	assert.NoError(t, err)
 
 	//listener.Close()
@@ -96,8 +95,8 @@ func Test_ConsumerDestory(t *testing.T) {
 }
 
 func Test_ProviderDestory(t *testing.T) {
-	regurl, _ := common.NewURL(context.TODO(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
-	url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	ts, reg, err := newMockZkRegistry(&regurl)
 	defer ts.Stop()
diff --git a/remoting/etcdv3/client.go b/remoting/etcdv3/client.go
index 050968565387fd31871b0aa8e9969496d39f6534..ba3ea6e864923b1e70cc4a0d31ee98415807699c 100644
--- a/remoting/etcdv3/client.go
+++ b/remoting/etcdv3/client.go
@@ -36,16 +36,22 @@ import (
 )
 
 const (
-	ConnDelay            = 3
-	MaxFailTimes         = 15
+	// ConnDelay connection dalay
+	ConnDelay = 3
+	// MaxFailTimes max failure times
+	MaxFailTimes = 15
+	// RegistryETCDV3Client client name
 	RegistryETCDV3Client = "etcd registry"
 )
 
 var (
+	// ErrNilETCDV3Client ...
 	ErrNilETCDV3Client = perrors.New("etcd raw client is nil") // full describe the ERR
-	ErrKVPairNotFound  = perrors.New("k/v pair not found")
+	// ErrKVPairNotFound ...
+	ErrKVPairNotFound = perrors.New("k/v pair not found")
 )
 
+// Options ...
 type Options struct {
 	name      string
 	endpoints []string
@@ -54,30 +60,38 @@ type Options struct {
 	heartbeat int // heartbeat second
 }
 
+// Option ...
 type Option func(*Options)
 
+// WithEndpoints ...
 func WithEndpoints(endpoints ...string) Option {
 	return func(opt *Options) {
 		opt.endpoints = endpoints
 	}
 }
+
+// WithName ...
 func WithName(name string) Option {
 	return func(opt *Options) {
 		opt.name = name
 	}
 }
+
+// WithTimeout ...
 func WithTimeout(timeout time.Duration) Option {
 	return func(opt *Options) {
 		opt.timeout = timeout
 	}
 }
 
+// WithHeartbeat ...
 func WithHeartbeat(heartbeat int) Option {
 	return func(opt *Options) {
 		opt.heartbeat = heartbeat
 	}
 }
 
+// ValidateClient ...
 func ValidateClient(container clientFacade, opts ...Option) error {
 
 	options := &Options{
@@ -117,6 +131,7 @@ func ValidateClient(container clientFacade, opts ...Option) error {
 	return nil
 }
 
+// Client ...
 type Client struct {
 	lock sync.RWMutex
 
@@ -191,6 +206,7 @@ func (c *Client) stop() bool {
 	return false
 }
 
+// Close ...
 func (c *Client) Close() {
 
 	if c == nil {
@@ -309,6 +325,7 @@ func (c *Client) get(k string) (string, error) {
 	return string(resp.Kvs[0].Value), nil
 }
 
+// CleanKV ...
 func (c *Client) CleanKV() error {
 
 	c.lock.RLock()
@@ -408,10 +425,12 @@ func (c *Client) keepAliveKV(k string, v string) error {
 	return nil
 }
 
+// Done ...
 func (c *Client) Done() <-chan struct{} {
 	return c.exit
 }
 
+// Valid ...
 func (c *Client) Valid() bool {
 	select {
 	case <-c.exit:
@@ -428,6 +447,7 @@ func (c *Client) Valid() bool {
 	return true
 }
 
+// Create ...
 func (c *Client) Create(k string, v string) error {
 
 	err := c.put(k, v)
@@ -437,6 +457,7 @@ func (c *Client) Create(k string, v string) error {
 	return nil
 }
 
+// Delete ...
 func (c *Client) Delete(k string) error {
 
 	err := c.delete(k)
@@ -447,6 +468,7 @@ func (c *Client) Delete(k string) error {
 	return nil
 }
 
+// RegisterTemp ...
 func (c *Client) RegisterTemp(basePath string, node string) (string, error) {
 
 	completeKey := path.Join(basePath, node)
@@ -459,6 +481,7 @@ func (c *Client) RegisterTemp(basePath string, node string) (string, error) {
 	return completeKey, nil
 }
 
+// GetChildrenKVList ...
 func (c *Client) GetChildrenKVList(k string) ([]string, []string, error) {
 
 	kList, vList, err := c.getChildren(k)
@@ -468,6 +491,7 @@ func (c *Client) GetChildrenKVList(k string) ([]string, []string, error) {
 	return kList, vList, nil
 }
 
+// Get ...
 func (c *Client) Get(k string) (string, error) {
 
 	v, err := c.get(k)
@@ -478,6 +502,7 @@ func (c *Client) Get(k string) (string, error) {
 	return v, nil
 }
 
+// Watch ...
 func (c *Client) Watch(k string) (clientv3.WatchChan, error) {
 
 	wc, err := c.watch(k)
@@ -487,6 +512,7 @@ func (c *Client) Watch(k string) (clientv3.WatchChan, error) {
 	return wc, nil
 }
 
+// WatchWithPrefix ...
 func (c *Client) WatchWithPrefix(prefix string) (clientv3.WatchChan, error) {
 
 	wc, err := c.watchWithPrefix(prefix)
diff --git a/remoting/etcdv3/facade.go b/remoting/etcdv3/facade.go
index 499044b8d77d3dcd8d32b0cb70cb78f84fae8ec4..35befc85e449ec02a6377faec300aa6b46bcc8bf 100644
--- a/remoting/etcdv3/facade.go
+++ b/remoting/etcdv3/facade.go
@@ -38,11 +38,12 @@ type clientFacade interface {
 	SetClient(*Client)
 	ClientLock() *sync.Mutex
 	WaitGroup() *sync.WaitGroup //for wait group control, etcd client listener & etcd client container
-	GetDone() chan struct{}     //for etcd client control
+	Done() chan struct{}        //for etcd client control
 	RestartCallBack() bool
 	common.Node
 }
 
+// HandleClientRestart ...
 func HandleClientRestart(r clientFacade) {
 
 	var (
@@ -54,7 +55,7 @@ func HandleClientRestart(r clientFacade) {
 LOOP:
 	for {
 		select {
-		case <-r.GetDone():
+		case <-r.Done():
 			logger.Warnf("(ETCDV3ProviderRegistry)reconnectETCDV3 goroutine exit now...")
 			break LOOP
 			// re-register all services
@@ -71,7 +72,7 @@ LOOP:
 			failTimes = 0
 			for {
 				select {
-				case <-r.GetDone():
+				case <-r.Done():
 					logger.Warnf("(ETCDV3ProviderRegistry)reconnectETCDRegistry goroutine exit now...")
 					break LOOP
 				case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)): // avoid connect frequent
diff --git a/remoting/etcdv3/listener.go b/remoting/etcdv3/listener.go
index a4d5805a6dbf3c76f43cb6085653c791b33ab119..a51a68bce78f4f24658f96dac5dc8778a07a6d9a 100644
--- a/remoting/etcdv3/listener.go
+++ b/remoting/etcdv3/listener.go
@@ -33,6 +33,7 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
+// EventListener ...
 type EventListener struct {
 	client     *Client
 	keyMapLock sync.Mutex
@@ -40,6 +41,7 @@ type EventListener struct {
 	wg         sync.WaitGroup
 }
 
+// NewEventListener ...
 func NewEventListener(client *Client) *EventListener {
 	return &EventListener{
 		client: client,
@@ -47,7 +49,7 @@ func NewEventListener(client *Client) *EventListener {
 	}
 }
 
-// Listen on a spec key
+// ListenServiceNodeEvent Listen on a spec key
 // this method will return true when spec key deleted,
 // this method will return false when deep layer connection lose
 func (l *EventListener) ListenServiceNodeEvent(key string, listener ...remoting.DataListener) bool {
@@ -134,7 +136,7 @@ func (l *EventListener) handleEvents(event *clientv3.Event, listeners ...remotin
 	panic("unreachable")
 }
 
-// Listen on a set of key with spec prefix
+// ListenServiceNodeEventWithPrefix Listen on a set of key with spec prefix
 func (l *EventListener) ListenServiceNodeEventWithPrefix(prefix string, listener ...remoting.DataListener) {
 
 	l.wg.Add(1)
@@ -180,7 +182,7 @@ func timeSecondDuration(sec int) time.Duration {
 	return time.Duration(sec) * time.Second
 }
 
-// this func is invoked by etcdv3 ConsumerRegistry::Registe/ etcdv3 ConsumerRegistry::get/etcdv3 ConsumerRegistry::getListener
+// ListenServiceEvent is invoked by etcdv3 ConsumerRegistry::Registe/ etcdv3 ConsumerRegistry::get/etcdv3 ConsumerRegistry::getListener
 // registry.go:Listen -> listenServiceEvent -> listenDirEvent -> ListenServiceNodeEvent
 //                            |
 //                            --------> ListenServiceNodeEvent
@@ -229,6 +231,7 @@ func (l *EventListener) ListenServiceEvent(key string, listener remoting.DataLis
 	}(key)
 }
 
+// Close ...
 func (l *EventListener) Close() {
 	l.wg.Wait()
 }
diff --git a/remoting/listener.go b/remoting/listener.go
index 8d1e357d37ff92e7bf60121133998dc1745c9af8..3713ba0ccf9d98d4470741785a9490e657cf051c 100644
--- a/remoting/listener.go
+++ b/remoting/listener.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 )
 
+// DataListener ...
 type DataListener interface {
 	DataChange(eventType Event) bool //bool is return for interface implement is interesting
 }
@@ -29,11 +30,15 @@ type DataListener interface {
 // event type
 //////////////////////////////////////////
 
+// EventType ...
 type EventType int
 
 const (
+	// EventTypeAdd ...
 	EventTypeAdd = iota
+	// EventTypeDel ...
 	EventTypeDel
+	// EventTypeUpdate ...
 	EventTypeUpdate
 )
 
@@ -51,6 +56,7 @@ func (t EventType) String() string {
 // service event
 //////////////////////////////////////////
 
+// Event ...
 type Event struct {
 	Path    string
 	Action  EventType
diff --git a/remoting/zookeeper/client.go b/remoting/zookeeper/client.go
index a7fc568f567d720448d0be63c592fae5f8df9bbf..f95231b374230c93036e0fbd74aeca4ecfe57f46 100644
--- a/remoting/zookeeper/client.go
+++ b/remoting/zookeeper/client.go
@@ -25,8 +25,8 @@ import (
 )
 
 import (
+	"github.com/dubbogo/go-zookeeper/zk"
 	perrors "github.com/pkg/errors"
-	"github.com/samuel/go-zookeeper/zk"
 )
 
 import (
@@ -35,14 +35,19 @@ import (
 )
 
 const (
-	ConnDelay    = 3
+	// ConnDelay connection delay interval
+	ConnDelay = 3
+	// MaxFailTimes max fail times
 	MaxFailTimes = 15
 )
 
 var (
 	errNilZkClientConn = perrors.New("zookeeperclient{conn} is nil")
+	errNilChildren     = perrors.Errorf("has none children")
+	errNilNode         = perrors.Errorf("node does not exist")
 )
 
+// ZookeeperClient ...
 type ZookeeperClient struct {
 	name          string
 	ZkAddrs       []string
@@ -54,6 +59,7 @@ type ZookeeperClient struct {
 	eventRegistry map[string][]*chan struct{}
 }
 
+// StateToString ...
 func StateToString(state zk.State) string {
 	switch state {
 	case zk.StateDisconnected:
@@ -85,6 +91,7 @@ func StateToString(state zk.State) string {
 	return "zookeeper unknown state"
 }
 
+// Options ...
 type Options struct {
 	zkName string
 	client *ZookeeperClient
@@ -92,14 +99,17 @@ type Options struct {
 	ts *zk.TestCluster
 }
 
+// Option ...
 type Option func(*Options)
 
+// WithZkName ...
 func WithZkName(name string) Option {
 	return func(opt *Options) {
 		opt.zkName = name
 	}
 }
 
+// ValidateZookeeperClient ...
 func ValidateZookeeperClient(container zkClientFacade, opts ...Option) error {
 	var (
 		err error
@@ -173,12 +183,14 @@ func newZookeeperClient(name string, zkAddrs []string, timeout time.Duration) (*
 	return z, nil
 }
 
+// WithTestCluster ...
 func WithTestCluster(ts *zk.TestCluster) Option {
 	return func(opt *Options) {
 		opt.ts = ts
 	}
 }
 
+// NewMockZookeeperClient ...
 func NewMockZookeeperClient(name string, timeout time.Duration, opts ...Option) (*zk.TestCluster, *ZookeeperClient, <-chan zk.Event, error) {
 	var (
 		err   error
@@ -224,6 +236,7 @@ func NewMockZookeeperClient(name string, timeout time.Duration, opts ...Option)
 	return ts, z, event, nil
 }
 
+// HandleZkEvent ...
 func (z *ZookeeperClient) HandleZkEvent(session <-chan zk.Event) {
 	var (
 		state int
@@ -248,11 +261,13 @@ LOOP:
 				logger.Warnf("zk{addr:%s} state is StateDisconnected, so close the zk client{name:%s}.", z.ZkAddrs, z.name)
 				z.stop()
 				z.Lock()
-				if z.Conn != nil {
-					z.Conn.Close()
-					z.Conn = nil
-				}
+				conn := z.Conn
+				z.Conn = nil
 				z.Unlock()
+				if conn != nil {
+					conn.Close()
+				}
+
 				break LOOP
 			case (int)(zk.EventNodeDataChanged), (int)(zk.EventNodeChildrenChanged):
 				logger.Infof("zkClient{%s} get zk node changed event{path:%s}", z.name, event.Path)
@@ -282,6 +297,7 @@ LOOP:
 	}
 }
 
+// RegisterEvent ...
 func (z *ZookeeperClient) RegisterEvent(zkPath string, event *chan struct{}) {
 	if zkPath == "" || event == nil {
 		return
@@ -290,11 +306,13 @@ func (z *ZookeeperClient) RegisterEvent(zkPath string, event *chan struct{}) {
 	z.Lock()
 	a := z.eventRegistry[zkPath]
 	a = append(a, event)
+
 	z.eventRegistry[zkPath] = a
 	logger.Debugf("zkClient{%s} register event{path:%s, ptr:%p}", z.name, zkPath, event)
 	z.Unlock()
 }
 
+// UnregisterEvent ...
 func (z *ZookeeperClient) UnregisterEvent(zkPath string, event *chan struct{}) {
 	if zkPath == "" {
 		return
@@ -321,6 +339,7 @@ func (z *ZookeeperClient) UnregisterEvent(zkPath string, event *chan struct{}) {
 	}
 }
 
+// Done ...
 func (z *ZookeeperClient) Done() <-chan struct{} {
 	return z.exit
 }
@@ -336,6 +355,7 @@ func (z *ZookeeperClient) stop() bool {
 	return false
 }
 
+// ZkConnValid ...
 func (z *ZookeeperClient) ZkConnValid() bool {
 	select {
 	case <-z.exit:
@@ -353,6 +373,7 @@ func (z *ZookeeperClient) ZkConnValid() bool {
 	return valid
 }
 
+// Close ...
 func (z *ZookeeperClient) Close() {
 	if z == nil {
 		return
@@ -361,14 +382,17 @@ func (z *ZookeeperClient) Close() {
 	z.stop()
 	z.Wait.Wait()
 	z.Lock()
-	if z.Conn != nil {
-		z.Conn.Close()
-		z.Conn = nil
-	}
+	conn := z.Conn
+	z.Conn = nil
 	z.Unlock()
+	if conn != nil {
+		conn.Close()
+	}
+
 	logger.Warnf("zkClient{name:%s, zk addr:%s} exit now.", z.name, z.ZkAddrs)
 }
 
+// Create ...
 func (z *ZookeeperClient) Create(basePath string) error {
 	var (
 		err     error
@@ -380,10 +404,12 @@ func (z *ZookeeperClient) Create(basePath string) error {
 		tmpPath = path.Join(tmpPath, "/", str)
 		err = errNilZkClientConn
 		z.Lock()
-		if z.Conn != nil {
-			_, err = z.Conn.Create(tmpPath, []byte(""), 0, zk.WorldACL(zk.PermAll))
-		}
+		conn := z.Conn
 		z.Unlock()
+		if conn != nil {
+			_, err = conn.Create(tmpPath, []byte(""), 0, zk.WorldACL(zk.PermAll))
+		}
+
 		if err != nil {
 			if err == zk.ErrNodeExists {
 				logger.Infof("zk.create(\"%s\") exists\n", tmpPath)
@@ -397,6 +423,7 @@ func (z *ZookeeperClient) Create(basePath string) error {
 	return nil
 }
 
+// Delete ...
 func (z *ZookeeperClient) Delete(basePath string) error {
 	var (
 		err error
@@ -404,14 +431,16 @@ func (z *ZookeeperClient) Delete(basePath string) error {
 
 	err = errNilZkClientConn
 	z.Lock()
-	if z.Conn != nil {
-		err = z.Conn.Delete(basePath, -1)
-	}
+	conn := z.Conn
 	z.Unlock()
+	if conn != nil {
+		err = conn.Delete(basePath, -1)
+	}
 
 	return perrors.WithMessagef(err, "Delete(basePath:%s)", basePath)
 }
 
+// RegisterTemp ...
 func (z *ZookeeperClient) RegisterTemp(basePath string, node string) (string, error) {
 	var (
 		err     error
@@ -424,10 +453,12 @@ func (z *ZookeeperClient) RegisterTemp(basePath string, node string) (string, er
 	data = []byte("")
 	zkPath = path.Join(basePath) + "/" + node
 	z.Lock()
-	if z.Conn != nil {
-		tmpPath, err = z.Conn.Create(zkPath, data, zk.FlagEphemeral, zk.WorldACL(zk.PermAll))
-	}
+	conn := z.Conn
 	z.Unlock()
+	if conn != nil {
+		tmpPath, err = conn.Create(zkPath, data, zk.FlagEphemeral, zk.WorldACL(zk.PermAll))
+	}
+
 	//if err != nil && err != zk.ErrNodeExists {
 	if err != nil {
 		logger.Warnf("conn.Create(\"%s\", zk.FlagEphemeral) = error(%v)\n", zkPath, perrors.WithStack(err))
@@ -438,6 +469,7 @@ func (z *ZookeeperClient) RegisterTemp(basePath string, node string) (string, er
 	return tmpPath, nil
 }
 
+// RegisterTempSeq ...
 func (z *ZookeeperClient) RegisterTempSeq(basePath string, data []byte) (string, error) {
 	var (
 		err     error
@@ -446,15 +478,17 @@ func (z *ZookeeperClient) RegisterTempSeq(basePath string, data []byte) (string,
 
 	err = errNilZkClientConn
 	z.Lock()
-	if z.Conn != nil {
-		tmpPath, err = z.Conn.Create(
+	conn := z.Conn
+	z.Unlock()
+	if conn != nil {
+		tmpPath, err = conn.Create(
 			path.Join(basePath)+"/",
 			data,
 			zk.FlagEphemeral|zk.FlagSequence,
 			zk.WorldACL(zk.PermAll),
 		)
 	}
-	z.Unlock()
+
 	logger.Debugf("zookeeperClient.RegisterTempSeq(basePath{%s}) = tempPath{%s}", basePath, tmpPath)
 	if err != nil && err != zk.ErrNodeExists {
 		logger.Errorf("zkClient{%s} conn.Create(\"%s\", \"%s\", zk.FlagEphemeral|zk.FlagSequence) error(%v)\n",
@@ -466,37 +500,44 @@ func (z *ZookeeperClient) RegisterTempSeq(basePath string, data []byte) (string,
 	return tmpPath, nil
 }
 
+// GetChildrenW ...
 func (z *ZookeeperClient) GetChildrenW(path string) ([]string, <-chan zk.Event, error) {
 	var (
 		err      error
 		children []string
 		stat     *zk.Stat
-		event    <-chan zk.Event
+		watcher  *zk.Watcher
 	)
 
 	err = errNilZkClientConn
 	z.Lock()
-	if z.Conn != nil {
-		children, stat, event, err = z.Conn.ChildrenW(path)
-	}
+	conn := z.Conn
 	z.Unlock()
+	if conn != nil {
+		children, stat, watcher, err = conn.ChildrenW(path)
+	}
+
 	if err != nil {
+		if err == zk.ErrNoChildrenForEphemerals {
+			return nil, nil, errNilChildren
+		}
 		if err == zk.ErrNoNode {
-			return nil, nil, perrors.Errorf("path{%s} has none children", path)
+			return nil, nil, errNilNode
 		}
 		logger.Errorf("zk.ChildrenW(path{%s}) = error(%v)", path, err)
 		return nil, nil, perrors.WithMessagef(err, "zk.ChildrenW(path:%s)", path)
 	}
 	if stat == nil {
-		return nil, nil, perrors.Errorf("path{%s} has none children", path)
+		return nil, nil, perrors.Errorf("path{%s} get stat is nil", path)
 	}
 	if len(children) == 0 {
-		return nil, nil, perrors.Errorf("path{%s} has none children", path)
+		return nil, nil, errNilChildren
 	}
 
-	return children, event, nil
+	return children, watcher.EvtCh, nil
 }
 
+// GetChildren ...
 func (z *ZookeeperClient) GetChildren(path string) ([]string, error) {
 	var (
 		err      error
@@ -506,10 +547,12 @@ func (z *ZookeeperClient) GetChildren(path string) ([]string, error) {
 
 	err = errNilZkClientConn
 	z.Lock()
-	if z.Conn != nil {
-		children, stat, err = z.Conn.Children(path)
-	}
+	conn := z.Conn
 	z.Unlock()
+	if conn != nil {
+		children, stat, err = conn.Children(path)
+	}
+
 	if err != nil {
 		if err == zk.ErrNoNode {
 			return nil, perrors.Errorf("path{%s} has none children", path)
@@ -521,25 +564,28 @@ func (z *ZookeeperClient) GetChildren(path string) ([]string, error) {
 		return nil, perrors.Errorf("path{%s} has none children", path)
 	}
 	if len(children) == 0 {
-		return nil, perrors.Errorf("path{%s} has none children", path)
+		return nil, errNilChildren
 	}
 
 	return children, nil
 }
 
+// ExistW ...
 func (z *ZookeeperClient) ExistW(zkPath string) (<-chan zk.Event, error) {
 	var (
-		exist bool
-		err   error
-		event <-chan zk.Event
+		exist   bool
+		err     error
+		watcher *zk.Watcher
 	)
 
 	err = errNilZkClientConn
 	z.Lock()
-	if z.Conn != nil {
-		exist, _, event, err = z.Conn.ExistsW(zkPath)
-	}
+	conn := z.Conn
 	z.Unlock()
+	if conn != nil {
+		exist, _, watcher, err = conn.ExistsW(zkPath)
+	}
+
 	if err != nil {
 		logger.Warnf("zkClient{%s}.ExistsW(path{%s}) = error{%v}.", z.name, zkPath, perrors.WithStack(err))
 		return nil, perrors.WithMessagef(err, "zk.ExistsW(path:%s)", zkPath)
@@ -549,9 +595,10 @@ func (z *ZookeeperClient) ExistW(zkPath string) (<-chan zk.Event, error) {
 		return nil, perrors.Errorf("zkClient{%s} App zk path{%s} does not exist.", z.name, zkPath)
 	}
 
-	return event, nil
+	return watcher.EvtCh, nil
 }
 
+// GetContent ...
 func (z *ZookeeperClient) GetContent(zkPath string) ([]byte, *zk.Stat, error) {
 	return z.Conn.Get(zkPath)
 }
diff --git a/remoting/zookeeper/client_test.go b/remoting/zookeeper/client_test.go
index f1bd0c2cb38669ad968bd83efae166a4432c6e2d..cb41eb326be95470e39694fc5df233fdf073b905 100644
--- a/remoting/zookeeper/client_test.go
+++ b/remoting/zookeeper/client_test.go
@@ -24,7 +24,7 @@ import (
 )
 
 import (
-	"github.com/samuel/go-zookeeper/zk"
+	"github.com/dubbogo/go-zookeeper/zk"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -133,3 +133,12 @@ func TestRegisterTempSeq(t *testing.T) {
 	states := []zk.State{zk.StateConnecting, zk.StateConnected, zk.StateHasSession}
 	verifyEventStateOrder(t, event, states, "event channel")
 }
+
+func Test_UnregisterEvent(t *testing.T) {
+	client := &ZookeeperClient{}
+	client.eventRegistry = make(map[string][]*chan struct{})
+	array := []*chan struct{}{}
+	array = append(array, new(chan struct{}))
+	client.eventRegistry["test"] = array
+	client.UnregisterEvent("test", new(chan struct{}))
+}
diff --git a/remoting/zookeeper/facade.go b/remoting/zookeeper/facade.go
index cdc7ead61226906a629fdb99b6b966ada5ee5253..055db4f716a914354d1bada653fbc0a850b615b5 100644
--- a/remoting/zookeeper/facade.go
+++ b/remoting/zookeeper/facade.go
@@ -35,11 +35,12 @@ type zkClientFacade interface {
 	SetZkClient(*ZookeeperClient)
 	ZkClientLock() *sync.Mutex
 	WaitGroup() *sync.WaitGroup //for wait group control, zk client listener & zk client container
-	GetDone() chan struct{}     //for zk client control
+	Done() chan struct{}        //for zk client control
 	RestartCallBack() bool
 	common.Node
 }
 
+// HandleClientRestart ...
 func HandleClientRestart(r zkClientFacade) {
 	var (
 		err error
@@ -51,7 +52,7 @@ func HandleClientRestart(r zkClientFacade) {
 LOOP:
 	for {
 		select {
-		case <-r.GetDone():
+		case <-r.Done():
 			logger.Warnf("(ZkProviderRegistry)reconnectZkRegistry goroutine exit now...")
 			break LOOP
 			// re-register all services
@@ -67,7 +68,7 @@ LOOP:
 			failTimes = 0
 			for {
 				select {
-				case <-r.GetDone():
+				case <-r.Done():
 					logger.Warnf("(ZkProviderRegistry)reconnectZkRegistry goroutine exit now...")
 					break LOOP
 				case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)): // Prevent crazy reconnection zk.
diff --git a/remoting/zookeeper/facade_test.go b/remoting/zookeeper/facade_test.go
index 58e0d69dcfd9bf645c147f6e920e56ed5f3951eb..97ea775652cf82ce86388fb376832ccb7e07a205 100644
--- a/remoting/zookeeper/facade_test.go
+++ b/remoting/zookeeper/facade_test.go
@@ -18,13 +18,12 @@
 package zookeeper
 
 import (
-	"context"
 	"sync"
 	"testing"
 	"time"
 )
 import (
-	"github.com/samuel/go-zookeeper/zk"
+	"github.com/dubbogo/go-zookeeper/zk"
 	"github.com/stretchr/testify/assert"
 )
 import (
@@ -55,7 +54,7 @@ func (r *mockFacade) WaitGroup() *sync.WaitGroup {
 	return &r.wg
 }
 
-func (r *mockFacade) GetDone() chan struct{} {
+func (r *mockFacade) Done() chan struct{} {
 	return r.done
 }
 
@@ -79,7 +78,7 @@ func Test_Facade(t *testing.T) {
 	ts, z, event, err := NewMockZookeeperClient("test", 15*time.Second)
 	assert.NoError(t, err)
 	defer ts.Stop()
-	url, _ := common.NewURL(context.Background(), "mock://127.0.0.1")
+	url, _ := common.NewURL("mock://127.0.0.1")
 	mock := &mockFacade{client: z, URL: &url}
 	go HandleClientRestart(mock)
 	states := []zk.State{zk.StateConnecting, zk.StateConnected, zk.StateHasSession}
diff --git a/remoting/zookeeper/listener.go b/remoting/zookeeper/listener.go
index 9521ea749027582c015ac998a6f6f68d350cc3bc..4493c06dc3f13d59b9388268613fe9e08a14033e 100644
--- a/remoting/zookeeper/listener.go
+++ b/remoting/zookeeper/listener.go
@@ -25,8 +25,8 @@ import (
 
 import (
 	"github.com/dubbogo/getty"
+	"github.com/dubbogo/go-zookeeper/zk"
 	perrors "github.com/pkg/errors"
-	"github.com/samuel/go-zookeeper/zk"
 )
 
 import (
@@ -34,6 +34,7 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
+// ZkEventListener ...
 type ZkEventListener struct {
 	client      *ZookeeperClient
 	pathMapLock sync.Mutex
@@ -41,6 +42,7 @@ type ZkEventListener struct {
 	wg          sync.WaitGroup
 }
 
+// NewZkEventListener ...
 func NewZkEventListener(client *ZookeeperClient) *ZkEventListener {
 	return &ZkEventListener{
 		client:  client,
@@ -48,10 +50,12 @@ func NewZkEventListener(client *ZookeeperClient) *ZkEventListener {
 	}
 }
 
+// SetClient ...
 func (l *ZkEventListener) SetClient(client *ZookeeperClient) {
 	l.client = client
 }
 
+// ListenServiceNodeEvent ...
 func (l *ZkEventListener) ListenServiceNodeEvent(zkPath string, listener ...remoting.DataListener) bool {
 	l.wg.Add(1)
 	defer l.wg.Done()
@@ -106,8 +110,17 @@ func (l *ZkEventListener) handleZkNodeEvent(zkPath string, children []string, li
 
 	newChildren, err := l.client.GetChildren(zkPath)
 	if err != nil {
-		logger.Errorf("path{%s} child nodes changed, zk.Children() = error{%v}", zkPath, perrors.WithStack(err))
-		return
+		if err == errNilChildren {
+			content, _, err := l.client.Conn.Get(zkPath)
+			if err != nil {
+				logger.Errorf("Get new node path {%v} 's content error,message is  {%v}", zkPath, perrors.WithStack(err))
+			} else {
+				listener.DataChange(remoting.Event{Path: zkPath, Action: remoting.EventTypeUpdate, Content: string(content)})
+			}
+
+		} else {
+			logger.Errorf("path{%s} child nodes changed, zk.Children() = error{%v}", zkPath, perrors.WithStack(err))
+		}
 	}
 
 	// a node was added -- listen the new node
@@ -177,7 +190,7 @@ func (l *ZkEventListener) listenDirEvent(zkPath string, listener remoting.DataLi
 			if MaxFailTimes <= failTimes {
 				failTimes = MaxFailTimes
 			}
-			logger.Warnf("listenDirEvent(path{%s}) = error{%v}", zkPath, err)
+			logger.Infof("listenDirEvent(path{%s}) = error{%v}", zkPath, err)
 			// clear the event channel
 		CLEAR:
 			for {
@@ -188,6 +201,11 @@ func (l *ZkEventListener) listenDirEvent(zkPath string, listener remoting.DataLi
 				}
 			}
 			l.client.RegisterEvent(zkPath, &event)
+			if err == errNilNode {
+				logger.Warnf("listenDirEvent(path{%s}) got errNilNode,so exit listen", zkPath)
+				l.client.UnregisterEvent(zkPath, &event)
+				return
+			}
 			select {
 			case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)):
 				l.client.UnregisterEvent(zkPath, &event)
@@ -262,55 +280,11 @@ func timeSecondDuration(sec int) time.Duration {
 	return time.Duration(sec) * time.Second
 }
 
-// this func is invoked by ZkConsumerRegistry::Register/ZkConsumerRegistry::get/ZkConsumerRegistry::getListener
+// ListenServiceEvent is invoked by ZkConsumerRegistry::Register/ZkConsumerRegistry::get/ZkConsumerRegistry::getListener
 // registry.go:Listen -> listenServiceEvent -> listenDirEvent -> ListenServiceNodeEvent
 //                            |
 //                            --------> ListenServiceNodeEvent
 func (l *ZkEventListener) ListenServiceEvent(zkPath string, listener remoting.DataListener) {
-	var (
-		err       error
-		dubboPath string
-		children  []string
-	)
-
-	l.pathMapLock.Lock()
-	_, ok := l.pathMap[zkPath]
-	l.pathMapLock.Unlock()
-	if ok {
-		logger.Warnf("@zkPath %s has already been listened.", zkPath)
-		return
-	}
-
-	l.pathMapLock.Lock()
-	l.pathMap[zkPath] = struct{}{}
-	l.pathMapLock.Unlock()
-
-	logger.Infof("listen dubbo provider path{%s} event and wait to get all provider zk nodes", zkPath)
-	children, err = l.client.GetChildren(zkPath)
-	if err != nil {
-		children = nil
-		logger.Warnf("fail to get children of zk path{%s}", zkPath)
-	}
-
-	for _, c := range children {
-		// listen l service node
-		dubboPath = path.Join(zkPath, c)
-		content, _, err := l.client.Conn.Get(dubboPath)
-		if err != nil {
-			logger.Errorf("Get new node path {%v} 's content error,message is  {%v}", dubboPath, perrors.WithStack(err))
-		}
-		if !listener.DataChange(remoting.Event{Path: dubboPath, Action: remoting.EventTypeAdd, Content: string(content)}) {
-			continue
-		}
-		logger.Infof("listen dubbo service key{%s}", dubboPath)
-		go func(zkPath string, listener remoting.DataListener) {
-			if l.ListenServiceNodeEvent(zkPath) {
-				listener.DataChange(remoting.Event{Path: zkPath, Action: remoting.EventTypeDel})
-			}
-			logger.Warnf("listenSelf(zk path{%s}) goroutine exit now", zkPath)
-		}(dubboPath, listener)
-	}
-
 	logger.Infof("listen dubbo path{%s}", zkPath)
 	go func(zkPath string, listener remoting.DataListener) {
 		l.listenDirEvent(zkPath, listener)
@@ -322,6 +296,7 @@ func (l *ZkEventListener) valid() bool {
 	return l.client.ZkConnValid()
 }
 
+// Close ...
 func (l *ZkEventListener) Close() {
 	l.wg.Wait()
 }
diff --git a/remoting/zookeeper/listener_test.go b/remoting/zookeeper/listener_test.go
index aa627c7e8a53ef87fb39446b05d4001bcf18cf3f..43e9aca3f44470873c3c97ec2447bebcc57e5545 100644
--- a/remoting/zookeeper/listener_test.go
+++ b/remoting/zookeeper/listener_test.go
@@ -24,7 +24,7 @@ import (
 	"time"
 )
 import (
-	"github.com/samuel/go-zookeeper/zk"
+	"github.com/dubbogo/go-zookeeper/zk"
 	"github.com/stretchr/testify/assert"
 )
 import (
@@ -97,12 +97,11 @@ func TestListener(t *testing.T) {
 	listener := NewZkEventListener(client)
 	dataListener := &mockDataListener{client: client, changedData: changedData, wait: &wait}
 	listener.ListenServiceEvent("/dubbo", dataListener)
-
+	time.Sleep(1 * time.Second)
 	_, err := client.Conn.Set("/dubbo/dubbo.properties", []byte(changedData), 1)
 	assert.NoError(t, err)
 	wait.Wait()
 	assert.Equal(t, changedData, dataListener.eventList[1].Content)
-	client.Close()
 
 }