diff --git a/README.md b/README.md
index 9bade617c8b05ec52c2018cf231ae036a7ae91d3..3f8394536f944518f8d969289147272c32f169da 100644
--- a/README.md
+++ b/README.md
@@ -176,5 +176,5 @@ About dubbo-go benchmarking report, please refer to [dubbo benchmarking report](
 If you are using [apache/dubbo-go](github.com/apache/dubbo-go) and think that it helps you or want do some contributions to it, please add your company to to [the user list](https://github.com/apache/dubbo-go/issues/2) to let us know your needs.
 
 ![ctrip](https://pic.c-ctrip.com/common/c_logo2013.png)
-![Excellent Health Technology Group](https://raw.githubusercontent.com/dajiiu/photo/static/mirror/haozhuo_logo.png)
+![Excellent Health Technology Group](https://user-images.githubusercontent.com/52339367/84628582-80512200-af1b-11ea-945a-c6b4b9ad31f2.png)
 ![tuya](https://raw.githubusercontent.com/pantianying/go-tool/master/picture/logo_2-removebg-preview.png)
diff --git a/README_CN.md b/README_CN.md
index 180759f36663a587ee02232e229ae7c3ebbb06c1..582c5cf04cba08d4167c87b40fd0e86a3aa2ceb0 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -175,5 +175,5 @@ go test ./... -coverprofile=coverage.txt -covermode=atomic
 鑻ヤ綘姝e湪浣跨敤 [apache/dubbo-go](github.com/apache/dubbo-go) 涓旇涓哄叾鏈夌敤鎴栬€呭悜瀵瑰叾鍋氭敼杩涳紝璇峰繚鍒楄吹鍙镐俊鎭簬 [鐢ㄦ埛鍒楄〃](https://github.com/apache/dubbo-go/issues/2)锛屼互渚挎垜浠煡鏅撲箣銆�
 
 ![ctrip](https://pic.c-ctrip.com/common/c_logo2013.png)
-![Excellent Health Technology Group](https://raw.githubusercontent.com/dajiiu/photo/static/mirror/haozhuo_logo.png)
+![Excellent Health Technology Group](https://user-images.githubusercontent.com/52339367/84628582-80512200-af1b-11ea-945a-c6b4b9ad31f2.png)
 ![tuya](https://raw.githubusercontent.com/pantianying/go-tool/master/picture/logo_2-removebg-preview.png)
diff --git a/before_ut.bat b/before_ut.bat
index 5e1c877af229b2b30bffc8b802cc35b6aab6c80a..dc51008dadaad21af6fcb6021863ff4102b0afa2 100644
--- a/before_ut.bat
+++ b/before_ut.bat
@@ -20,7 +20,7 @@ set zkJarPath=remoting/zookeeper/zookeeper-4unittest/contrib/fatjar
 set zkJar=%zkJarPath%/%zkJarName%
 
 if not exist "%zkJar%" (
-   md %zkJarPath%
+   md "%zkJarPath%"
    curl -L %remoteJarUrl% -o %zkJar%
 )
 
diff --git a/cluster/cluster.go b/cluster/cluster.go
index 617ce5ebf0fa7b5dc7f6047caacec9865aa6960f..7a0df4c0a24faf45d6d3d3da8651600481f782ba 100644
--- a/cluster/cluster.go
+++ b/cluster/cluster.go
@@ -21,7 +21,8 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// Cluster ...
+// Cluster
+// Extension - 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 e041d91edb969c8a9b6f0309d1146f1ea874b42a..b70a97fad2de1b267ac1c6a5f0672ff445fadcc3 100644
--- a/cluster/cluster_impl/available_cluster.go
+++ b/cluster/cluster_impl/available_cluster.go
@@ -31,7 +31,9 @@ func init() {
 	extension.SetCluster(available, NewAvailableCluster)
 }
 
-// NewAvailableCluster ...
+// NewAvailableCluster returns a cluster instance
+//
+// Obtain available service providers
 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 e69f8b9f471d2aa6241b34bd01990d5d003feb3e..39a892379d3871565ec977aac874bb6509515ee2 100644
--- a/cluster/cluster_impl/available_cluster_invoker.go
+++ b/cluster/cluster_impl/available_cluster_invoker.go
@@ -35,7 +35,7 @@ type availableClusterInvoker struct {
 	baseClusterInvoker
 }
 
-// NewAvailableClusterInvoker ...
+// NewAvailableClusterInvoker returns a cluster invoker instance
 func NewAvailableClusterInvoker(directory cluster.Directory) protocol.Invoker {
 	return &availableClusterInvoker{
 		baseClusterInvoker: newBaseClusterInvoker(directory),
diff --git a/cluster/cluster_impl/available_cluster_invoker_test.go b/cluster/cluster_impl/available_cluster_invoker_test.go
index 61d1c934522008e4d9bc46bbd57eb6fed6bf00f9..063100020ad36192a051d1e736af7264cd8df42d 100644
--- a/cluster/cluster_impl/available_cluster_invoker_test.go
+++ b/cluster/cluster_impl/available_cluster_invoker_test.go
@@ -19,6 +19,7 @@ package cluster_impl
 
 import (
 	"context"
+	"fmt"
 	"strings"
 	"testing"
 )
@@ -32,6 +33,7 @@ import (
 	"github.com/apache/dubbo-go/cluster/directory"
 	"github.com/apache/dubbo-go/cluster/loadbalance"
 	"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"
 	"github.com/apache/dubbo-go/protocol/invocation"
@@ -39,7 +41,8 @@ import (
 )
 
 var (
-	availableUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	availableUrl, _ = common.NewURL(fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider",
+		constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
 )
 
 func registerAvailable(invoker *mock.MockInvoker) protocol.Invoker {
diff --git a/cluster/cluster_impl/base_cluster_invoker.go b/cluster/cluster_impl/base_cluster_invoker.go
index cabd6c5f17cd3a3310054c0ff7b9a9877d581345..bbdfa715d7cdc461689e60a5a41171ad5c9770e1 100644
--- a/cluster/cluster_impl/base_cluster_invoker.go
+++ b/cluster/cluster_impl/base_cluster_invoker.go
@@ -88,6 +88,10 @@ func (invoker *baseClusterInvoker) checkWhetherDestroyed() error {
 
 func (invoker *baseClusterInvoker) doSelect(lb cluster.LoadBalance, invocation protocol.Invocation, invokers []protocol.Invoker, invoked []protocol.Invoker) protocol.Invoker {
 	var selectedInvoker protocol.Invoker
+	if len(invokers) <= 0 {
+		return selectedInvoker
+	}
+
 	url := invokers[0].GetUrl()
 	sticky := url.GetParamBool(constant.STICKY_KEY, false)
 	//Get the service method sticky config if have
@@ -97,19 +101,17 @@ func (invoker *baseClusterInvoker) doSelect(lb cluster.LoadBalance, invocation p
 		invoker.stickyInvoker = nil
 	}
 
-	if sticky && invoker.stickyInvoker != nil && (invoked == nil || !isInvoked(invoker.stickyInvoker, invoked)) {
-		if invoker.availablecheck && invoker.stickyInvoker.IsAvailable() {
-			return invoker.stickyInvoker
-		}
+	if sticky && invoker.availablecheck &&
+		invoker.stickyInvoker != nil && invoker.stickyInvoker.IsAvailable() &&
+		(invoked == nil || !isInvoked(invoker.stickyInvoker, invoked)) {
+		return invoker.stickyInvoker
 	}
 
 	selectedInvoker = invoker.doSelectInvoker(lb, invocation, invokers, invoked)
-
 	if sticky {
 		invoker.stickyInvoker = selectedInvoker
 	}
 	return selectedInvoker
-
 }
 
 func (invoker *baseClusterInvoker) doSelectInvoker(lb cluster.LoadBalance, invocation protocol.Invocation, invokers []protocol.Invoker, invoked []protocol.Invoker) protocol.Invoker {
diff --git a/cluster/cluster_impl/base_cluster_invoker_test.go b/cluster/cluster_impl/base_cluster_invoker_test.go
index d074697b85a3cf5b770de90da4847043d98c9df1..695ffcddbbce5a1c65f806b4561670d726588aaa 100644
--- a/cluster/cluster_impl/base_cluster_invoker_test.go
+++ b/cluster/cluster_impl/base_cluster_invoker_test.go
@@ -33,7 +33,7 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-func Test_StickyNormal(t *testing.T) {
+func TestStickyNormal(t *testing.T) {
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
 		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
@@ -43,12 +43,15 @@ func Test_StickyNormal(t *testing.T) {
 	base := &baseClusterInvoker{}
 	base.availablecheck = true
 	invoked := []protocol.Invoker{}
-	result := base.doSelect(loadbalance.NewRandomLoadBalance(), invocation.NewRPCInvocation("getUser", nil, nil), invokers, invoked)
-	result1 := base.doSelect(loadbalance.NewRandomLoadBalance(), invocation.NewRPCInvocation("getUser", nil, nil), invokers, invoked)
+
+	tmpRandomBalance := loadbalance.NewRandomLoadBalance()
+	tmpInvocation := invocation.NewRPCInvocation("getUser", nil, nil)
+	result := base.doSelect(tmpRandomBalance, tmpInvocation, invokers, invoked)
+	result1 := base.doSelect(tmpRandomBalance, tmpInvocation, invokers, invoked)
 	assert.Equal(t, result, result1)
 }
 
-func Test_StickyNormalWhenError(t *testing.T) {
+func TestStickyNormalWhenError(t *testing.T) {
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
 		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
diff --git a/cluster/cluster_impl/broadcast_cluster.go b/cluster/cluster_impl/broadcast_cluster.go
index a1692e96c5b68bc01adeab6600e99dff16a1bea1..ba454af6a8553f31b72b1d30ef5f44ec7a8278d2 100644
--- a/cluster/cluster_impl/broadcast_cluster.go
+++ b/cluster/cluster_impl/broadcast_cluster.go
@@ -31,7 +31,10 @@ func init() {
 	extension.SetCluster(broadcast, NewBroadcastCluster)
 }
 
-// NewBroadcastCluster ...
+// NewBroadcastCluster returns a broadcast cluster instance.
+//
+// Calling all providers' broadcast one by one. All errors will be reported.
+// It is usually used to notify all providers to update local resource information such as caches or logs.
 func NewBroadcastCluster() cluster.Cluster {
 	return &broadcastCluster{}
 }
diff --git a/cluster/cluster_impl/broadcast_cluster_invoker_test.go b/cluster/cluster_impl/broadcast_cluster_invoker_test.go
index 9b5733e98b142759c3317f9cb3e3d3f08eea81e4..08d0002ee79b2f3fda5a50ce90747c0aaad91932 100644
--- a/cluster/cluster_impl/broadcast_cluster_invoker_test.go
+++ b/cluster/cluster_impl/broadcast_cluster_invoker_test.go
@@ -20,6 +20,7 @@ package cluster_impl
 import (
 	"context"
 	"errors"
+	"fmt"
 	"testing"
 )
 
@@ -32,6 +33,7 @@ import (
 	"github.com/apache/dubbo-go/cluster/directory"
 	"github.com/apache/dubbo-go/cluster/loadbalance"
 	"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"
 	"github.com/apache/dubbo-go/protocol/invocation"
@@ -39,10 +41,11 @@ import (
 )
 
 var (
-	broadcastUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	broadcastUrl, _ = common.NewURL(
+		fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
 )
 
-func registerBroadcast(t *testing.T, mockInvokers ...*mock.MockInvoker) protocol.Invoker {
+func registerBroadcast(mockInvokers ...*mock.MockInvoker) protocol.Invoker {
 	extension.SetLoadbalance("random", loadbalance.NewRandomLoadBalance)
 
 	invokers := []protocol.Invoker{}
@@ -59,7 +62,7 @@ func registerBroadcast(t *testing.T, mockInvokers ...*mock.MockInvoker) protocol
 	return clusterInvoker
 }
 
-func Test_BroadcastInvokeSuccess(t *testing.T) {
+func TestBroadcastInvokeSuccess(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
@@ -72,13 +75,13 @@ func Test_BroadcastInvokeSuccess(t *testing.T) {
 		invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
 	}
 
-	clusterInvoker := registerBroadcast(t, invokers...)
+	clusterInvoker := registerBroadcast(invokers...)
 
 	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Equal(t, mockResult, result)
 }
 
-func Test_BroadcastInvokeFailed(t *testing.T) {
+func TestBroadcastInvokeFailed(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
@@ -102,7 +105,7 @@ func Test_BroadcastInvokeFailed(t *testing.T) {
 		invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
 	}
 
-	clusterInvoker := registerBroadcast(t, invokers...)
+	clusterInvoker := registerBroadcast(invokers...)
 
 	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 76573571684c07f63609009f59ab0ac881ae1b50..432e33122c2ee599bc848ca9ab1842084da5ef68 100644
--- a/cluster/cluster_impl/failback_cluster.go
+++ b/cluster/cluster_impl/failback_cluster.go
@@ -31,7 +31,10 @@ func init() {
 	extension.SetCluster(failback, NewFailbackCluster)
 }
 
-// NewFailbackCluster ...
+// NewFailbackCluster returns a failback cluster instance
+//
+// Failure automatically restored, failed to record the background request,
+// regular retransmission. Usually used for message notification operations.
 func NewFailbackCluster() cluster.Cluster {
 	return &failbackCluster{}
 }
diff --git a/cluster/cluster_impl/failback_cluster_test.go b/cluster/cluster_impl/failback_cluster_test.go
index 69418bc3b876f7c9375a2164d78bac2fcbb05043..0edb81d4285fa68ceefd96100b541ba334f95bda 100644
--- a/cluster/cluster_impl/failback_cluster_test.go
+++ b/cluster/cluster_impl/failback_cluster_test.go
@@ -19,6 +19,7 @@ package cluster_impl
 
 import (
 	"context"
+	"fmt"
 	"sync"
 	"testing"
 	"time"
@@ -34,6 +35,7 @@ import (
 	"github.com/apache/dubbo-go/cluster/directory"
 	"github.com/apache/dubbo-go/cluster/loadbalance"
 	"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"
 	"github.com/apache/dubbo-go/protocol/invocation"
@@ -41,11 +43,12 @@ import (
 )
 
 var (
-	failbackUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	failbackUrl, _ = common.NewURL(
+		fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
 )
 
 // registerFailback register failbackCluster to cluster extension.
-func registerFailback(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker {
+func registerFailback(invoker *mock.MockInvoker) protocol.Invoker {
 	extension.SetLoadbalance("random", loadbalance.NewRandomLoadBalance)
 	failbackCluster := NewFailbackCluster()
 
@@ -60,12 +63,12 @@ func registerFailback(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker
 }
 
 // success firstly, failback should return origin invoke result.
-func Test_FailbackSuceess(t *testing.T) {
+func TestFailbackSuceess(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerFailback(t, invoker).(*failbackClusterInvoker)
+	clusterInvoker := registerFailback(invoker).(*failbackClusterInvoker)
 
 	invoker.EXPECT().GetUrl().Return(failbackUrl).AnyTimes()
 
@@ -77,12 +80,12 @@ func Test_FailbackSuceess(t *testing.T) {
 }
 
 // failed firstly, success later after one retry.
-func Test_FailbackRetryOneSuccess(t *testing.T) {
+func TestFailbackRetryOneSuccess(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerFailback(t, invoker).(*failbackClusterInvoker)
+	clusterInvoker := registerFailback(invoker).(*failbackClusterInvoker)
 
 	invoker.EXPECT().GetUrl().Return(failbackUrl).AnyTimes()
 
@@ -95,7 +98,7 @@ func Test_FailbackRetryOneSuccess(t *testing.T) {
 	wg.Add(1)
 	now := time.Now()
 	mockSuccResult := &protocol.RPCResult{Rest: rest{tried: 0, success: true}}
-	invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(func(invocation protocol.Invocation) protocol.Result {
+	invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(func(protocol.Invocation) protocol.Result {
 		delta := time.Since(now).Nanoseconds() / int64(time.Second)
 		assert.True(t, delta >= 5)
 		wg.Done()
@@ -120,12 +123,12 @@ func Test_FailbackRetryOneSuccess(t *testing.T) {
 }
 
 // failed firstly, and failed again after ech retry time.
-func Test_FailbackRetryFailed(t *testing.T) {
+func TestFailbackRetryFailed(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerFailback(t, invoker).(*failbackClusterInvoker)
+	clusterInvoker := registerFailback(invoker).(*failbackClusterInvoker)
 
 	invoker.EXPECT().GetUrl().Return(failbackUrl).AnyTimes()
 
@@ -141,7 +144,7 @@ func Test_FailbackRetryFailed(t *testing.T) {
 	// add retry call that eventually failed.
 	for i := 0; i < retries; i++ {
 		j := i + 1
-		invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(func(invocation protocol.Invocation) protocol.Result {
+		invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(func(protocol.Invocation) protocol.Result {
 			delta := time.Since(now).Nanoseconds() / int64(time.Second)
 			assert.True(t, delta >= int64(5*j))
 			wg.Done()
@@ -166,12 +169,12 @@ func Test_FailbackRetryFailed(t *testing.T) {
 }
 
 // add 10 tasks but all failed firstly, and failed again with one retry.
-func Test_FailbackRetryFailed10Times(t *testing.T) {
+func TestFailbackRetryFailed10Times(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerFailback(t, invoker).(*failbackClusterInvoker)
+	clusterInvoker := registerFailback(invoker).(*failbackClusterInvoker)
 	clusterInvoker.maxRetries = 10
 
 	invoker.EXPECT().GetUrl().Return(failbackUrl).AnyTimes()
@@ -184,7 +187,7 @@ func Test_FailbackRetryFailed10Times(t *testing.T) {
 	var wg sync.WaitGroup
 	wg.Add(10)
 	now := time.Now()
-	invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(func(invocation protocol.Invocation) protocol.Result {
+	invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(func(protocol.Invocation) protocol.Result {
 		delta := time.Since(now).Nanoseconds() / int64(time.Second)
 		assert.True(t, delta >= 5)
 		wg.Done()
@@ -208,12 +211,12 @@ func Test_FailbackRetryFailed10Times(t *testing.T) {
 	assert.Equal(t, int64(0), clusterInvoker.taskList.Len())
 }
 
-func Test_FailbackOutOfLimit(t *testing.T) {
+func TestFailbackOutOfLimit(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerFailback(t, invoker).(*failbackClusterInvoker)
+	clusterInvoker := registerFailback(invoker).(*failbackClusterInvoker)
 	clusterInvoker.failbackTasks = 1
 
 	invoker.EXPECT().GetUrl().Return(failbackUrl).AnyTimes()
diff --git a/cluster/cluster_impl/failfast_cluster.go b/cluster/cluster_impl/failfast_cluster.go
index 1e85485f7144f27a1994b18ba9419d9537d93ca1..ac9ec6b821c1d0333c73fae56169d5bc8256ec5b 100644
--- a/cluster/cluster_impl/failfast_cluster.go
+++ b/cluster/cluster_impl/failfast_cluster.go
@@ -31,7 +31,10 @@ func init() {
 	extension.SetCluster(failfast, NewFailFastCluster)
 }
 
-// NewFailFastCluster ...
+// NewFailFastCluster returns a failfast cluster instance.
+//
+// Fast failure, only made a call, failure immediately error. Usually used for non-idempotent write operations,
+// such as adding records.
 func NewFailFastCluster() cluster.Cluster {
 	return &failfastCluster{}
 }
diff --git a/cluster/cluster_impl/failfast_cluster_test.go b/cluster/cluster_impl/failfast_cluster_test.go
index c5ab7cd5410ea312e082f8064c13b2356c9b4bb4..77e8e9c5da73bfc8bcf08dbd90351bfd23d7e651 100644
--- a/cluster/cluster_impl/failfast_cluster_test.go
+++ b/cluster/cluster_impl/failfast_cluster_test.go
@@ -19,6 +19,7 @@ package cluster_impl
 
 import (
 	"context"
+	"fmt"
 	"testing"
 )
 
@@ -32,6 +33,7 @@ import (
 	"github.com/apache/dubbo-go/cluster/directory"
 	"github.com/apache/dubbo-go/cluster/loadbalance"
 	"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"
 	"github.com/apache/dubbo-go/protocol/invocation"
@@ -39,11 +41,12 @@ import (
 )
 
 var (
-	failfastUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	failfastUrl, _ = common.NewURL(
+		fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
 )
 
 // registerFailfast register failfastCluster to cluster extension.
-func registerFailfast(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker {
+func registerFailfast(invoker *mock.MockInvoker) protocol.Invoker {
 	extension.SetLoadbalance("random", loadbalance.NewRandomLoadBalance)
 	failfastCluster := NewFailFastCluster()
 
@@ -57,12 +60,12 @@ func registerFailfast(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker
 	return clusterInvoker
 }
 
-func Test_FailfastInvokeSuccess(t *testing.T) {
+func TestFailfastInvokeSuccess(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerFailfast(t, invoker)
+	clusterInvoker := registerFailfast(invoker)
 
 	invoker.EXPECT().GetUrl().Return(failfastUrl).AnyTimes()
 
@@ -77,12 +80,12 @@ func Test_FailfastInvokeSuccess(t *testing.T) {
 	assert.Equal(t, 0, res.tried)
 }
 
-func Test_FailfastInvokeFail(t *testing.T) {
+func TestFailfastInvokeFail(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerFailfast(t, invoker)
+	clusterInvoker := registerFailfast(invoker)
 
 	invoker.EXPECT().GetUrl().Return(failfastUrl).AnyTimes()
 
diff --git a/cluster/cluster_impl/failover_cluster.go b/cluster/cluster_impl/failover_cluster.go
index b16be3bafd43c7de8e2fadd109a73a3ea710e225..d30a743e034dafabad87381cdaa356e7603b74d1 100644
--- a/cluster/cluster_impl/failover_cluster.go
+++ b/cluster/cluster_impl/failover_cluster.go
@@ -31,7 +31,11 @@ func init() {
 	extension.SetCluster(name, NewFailoverCluster)
 }
 
-// NewFailoverCluster ...
+// NewFailoverCluster returns a failover cluster instance
+//
+// Failure automatically switch, when there is a failure,
+// retry the other server (default). Usually used for read operations,
+// but retries can result in longer delays.
 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 6178a05a1226ba629d2456ad6886b02a26288e45..66adabd1043d6e5d770704774dda22ba9e6faebe 100644
--- a/cluster/cluster_impl/failover_cluster_invoker.go
+++ b/cluster/cluster_impl/failover_cluster_invoker.go
@@ -45,52 +45,35 @@ func newFailoverClusterInvoker(directory cluster.Directory) protocol.Invoker {
 }
 
 func (invoker *failoverClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
+	var (
+		result    protocol.Result
+		invoked   []protocol.Invoker
+		providers []string
+	)
 
 	invokers := invoker.directory.List(invocation)
-	err := invoker.checkInvokers(invokers, invocation)
-
-	if err != nil {
+	if err := invoker.checkInvokers(invokers, invocation); err != nil {
 		return &protocol.RPCResult{Err: err}
 	}
 
-	loadbalance := getLoadBalance(invokers[0], invocation)
-
 	methodName := invocation.MethodName()
-	url := invokers[0].GetUrl()
-
-	//get reties
-	retriesConfig := url.GetParam(constant.RETRIES_KEY, constant.DEFAULT_RETRIES)
+	retries := getRetries(invokers, methodName)
+	loadBalance := getLoadBalance(invokers[0], invocation)
 
-	//Get the service method loadbalance config if have
-	if v := url.GetMethodParam(methodName, constant.RETRIES_KEY, ""); len(v) != 0 {
-		retriesConfig = v
-	}
-	retries, err := strconv.Atoi(retriesConfig)
-	if err != nil || retries < 0 {
-		logger.Error("Your retries config is invalid,pls do a check. And will use the default retries configuration instead.")
-		retries = constant.DEFAULT_RETRIES_INT
-	}
-	invoked := []protocol.Invoker{}
-	providers := []string{}
-	var result protocol.Result
-	if retries > len(invokers) {
-		retries = len(invokers)
-	}
 	for i := 0; i <= retries; i++ {
 		//Reselect before retry to avoid a change of candidate `invokers`.
 		//NOTE: if `invokers` changed, then `invoked` also lose accuracy.
 		if i > 0 {
-			err := invoker.checkWhetherDestroyed()
-			if err != nil {
+			if err := invoker.checkWhetherDestroyed(); err != nil {
 				return &protocol.RPCResult{Err: err}
 			}
+
 			invokers = invoker.directory.List(invocation)
-			err = invoker.checkInvokers(invokers, invocation)
-			if err != nil {
+			if err := invoker.checkInvokers(invokers, invocation); err != nil {
 				return &protocol.RPCResult{Err: err}
 			}
 		}
-		ivk := invoker.doSelect(loadbalance, invocation, invokers, invoked)
+		ivk := invoker.doSelect(loadBalance, invocation, invokers, invoked)
 		if ivk == nil {
 			continue
 		}
@@ -100,13 +83,40 @@ func (invoker *failoverClusterInvoker) Invoke(ctx context.Context, invocation pr
 		if result.Error() != nil {
 			providers = append(providers, ivk.GetUrl().Key())
 			continue
-		} else {
-			return result
 		}
+		return result
 	}
+
 	ip, _ := gxnet.GetLocalIP()
-	return &protocol.RPCResult{Err: perrors.Errorf("Failed to invoke the method %v in the service %v. Tried %v times of "+
-		"the providers %v (%v/%v)from the registry %v on the consumer %v using the dubbo version %v. Last error is %v.",
-		methodName, invoker.GetUrl().Service(), retries, providers, len(providers), len(invokers), invoker.directory.GetUrl(), ip, constant.Version, result.Error().Error(),
-	)}
+	invokerSvc := invoker.GetUrl().Service()
+	invokerUrl := invoker.directory.GetUrl()
+	return &protocol.RPCResult{
+		Err: perrors.Errorf("Failed to invoke the method %v in the service %v. Tried %v times of the providers %v (%v/%v)from the registry %v on the consumer %v using the dubbo version %v. Last error is %v.",
+			methodName, invokerSvc, retries, providers, len(providers), len(invokers), invokerUrl, ip, constant.Version, result.Error().Error(),
+		)}
+}
+
+func getRetries(invokers []protocol.Invoker, methodName string) int {
+	if len(invokers) <= 0 {
+		return constant.DEFAULT_RETRIES_INT
+	}
+
+	url := invokers[0].GetUrl()
+	//get reties
+	retriesConfig := url.GetParam(constant.RETRIES_KEY, constant.DEFAULT_RETRIES)
+	//Get the service method loadbalance config if have
+	if v := url.GetMethodParam(methodName, constant.RETRIES_KEY, ""); len(v) != 0 {
+		retriesConfig = v
+	}
+
+	retries, err := strconv.Atoi(retriesConfig)
+	if err != nil || retries < 0 {
+		logger.Error("Your retries config is invalid,pls do a check. And will use the default retries configuration instead.")
+		retries = constant.DEFAULT_RETRIES_INT
+	}
+
+	if retries > len(invokers) {
+		retries = len(invokers)
+	}
+	return retries
 }
diff --git a/cluster/cluster_impl/failover_cluster_test.go b/cluster/cluster_impl/failover_cluster_test.go
index ee7d48f3497772db3143b1ae62a30f66f99faa58..e05b79202cd202334db1c19421e3163ee28bac26 100644
--- a/cluster/cluster_impl/failover_cluster_test.go
+++ b/cluster/cluster_impl/failover_cluster_test.go
@@ -101,7 +101,7 @@ func (bi *MockInvoker) Destroy() {
 
 var count int
 
-func normalInvoke(t *testing.T, successCount int, urlParam url.Values, invocations ...*invocation.RPCInvocation) protocol.Result {
+func normalInvoke(successCount int, urlParam url.Values, invocations ...*invocation.RPCInvocation) protocol.Result {
 	extension.SetLoadbalance("random", loadbalance.NewRandomLoadBalance)
 	failoverCluster := NewFailoverCluster()
 
@@ -119,40 +119,40 @@ func normalInvoke(t *testing.T, successCount int, urlParam url.Values, invocatio
 	return clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 }
 
-func Test_FailoverInvokeSuccess(t *testing.T) {
+func TestFailoverInvokeSuccess(t *testing.T) {
 	urlParams := url.Values{}
-	result := normalInvoke(t, 3, urlParams)
+	result := normalInvoke(3, urlParams)
 	assert.NoError(t, result.Error())
 	count = 0
 }
 
-func Test_FailoverInvokeFail(t *testing.T) {
+func TestFailoverInvokeFail(t *testing.T) {
 	urlParams := url.Values{}
-	result := normalInvoke(t, 4, urlParams)
+	result := normalInvoke(4, urlParams)
 	assert.Errorf(t, result.Error(), "error")
 	count = 0
 }
 
-func Test_FailoverInvoke1(t *testing.T) {
+func TestFailoverInvoke1(t *testing.T) {
 	urlParams := url.Values{}
 	urlParams.Set(constant.RETRIES_KEY, "3")
-	result := normalInvoke(t, 4, urlParams)
+	result := normalInvoke(4, urlParams)
 	assert.NoError(t, result.Error())
 	count = 0
 }
 
-func Test_FailoverInvoke2(t *testing.T) {
+func TestFailoverInvoke2(t *testing.T) {
 	urlParams := url.Values{}
 	urlParams.Set(constant.RETRIES_KEY, "2")
 	urlParams.Set("methods.test."+constant.RETRIES_KEY, "3")
 
 	ivc := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("test"))
-	result := normalInvoke(t, 4, urlParams, ivc)
+	result := normalInvoke(4, urlParams, ivc)
 	assert.NoError(t, result.Error())
 	count = 0
 }
 
-func Test_FailoverDestroy(t *testing.T) {
+func TestFailoverDestroy(t *testing.T) {
 	extension.SetLoadbalance("random", loadbalance.NewRandomLoadBalance)
 	failoverCluster := NewFailoverCluster()
 
@@ -170,5 +170,4 @@ func Test_FailoverDestroy(t *testing.T) {
 	count = 0
 	clusterInvoker.Destroy()
 	assert.Equal(t, false, clusterInvoker.IsAvailable())
-
 }
diff --git a/cluster/cluster_impl/failsafe_cluster.go b/cluster/cluster_impl/failsafe_cluster.go
index 177d24a585b5f72fb0667215beb8d11147cc2922..f708b7fb9108bdd17fec5dc68dc1e4249c8199d4 100644
--- a/cluster/cluster_impl/failsafe_cluster.go
+++ b/cluster/cluster_impl/failsafe_cluster.go
@@ -31,7 +31,10 @@ func init() {
 	extension.SetCluster(failsafe, NewFailsafeCluster)
 }
 
-// NewFailsafeCluster ...
+// NewFailsafeCluster returns a failsafe cluster instance.
+//
+// Failure of security, anomalies, directly ignored. Usually it is
+// used to write audit logs and other operations.
 func NewFailsafeCluster() cluster.Cluster {
 	return &failsafeCluster{}
 }
diff --git a/cluster/cluster_impl/failsafe_cluster_test.go b/cluster/cluster_impl/failsafe_cluster_test.go
index 0bfeb576bd095508ef122c55c1345208c50eb339..d9a716e1ae65a84b605b4b7af1872b3a85dc9369 100644
--- a/cluster/cluster_impl/failsafe_cluster_test.go
+++ b/cluster/cluster_impl/failsafe_cluster_test.go
@@ -19,6 +19,7 @@ package cluster_impl
 
 import (
 	"context"
+	"fmt"
 	"testing"
 )
 
@@ -32,6 +33,7 @@ import (
 	"github.com/apache/dubbo-go/cluster/directory"
 	"github.com/apache/dubbo-go/cluster/loadbalance"
 	"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"
 	"github.com/apache/dubbo-go/protocol/invocation"
@@ -39,11 +41,12 @@ import (
 )
 
 var (
-	failsafeUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	failsafeUrl, _ = common.NewURL(
+		fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
 )
 
 // registerFailsafe register failsafeCluster to cluster extension.
-func registerFailsafe(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker {
+func registerFailsafe(invoker *mock.MockInvoker) protocol.Invoker {
 	extension.SetLoadbalance("random", loadbalance.NewRandomLoadBalance)
 	failsafeCluster := NewFailsafeCluster()
 
@@ -57,12 +60,12 @@ func registerFailsafe(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker
 	return clusterInvoker
 }
 
-func Test_FailSafeInvokeSuccess(t *testing.T) {
+func TestFailSafeInvokeSuccess(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerFailsafe(t, invoker)
+	clusterInvoker := registerFailsafe(invoker)
 
 	invoker.EXPECT().GetUrl().Return(failsafeUrl).AnyTimes()
 
@@ -76,12 +79,12 @@ func Test_FailSafeInvokeSuccess(t *testing.T) {
 	assert.True(t, res.success)
 }
 
-func Test_FailSafeInvokeFail(t *testing.T) {
+func TestFailSafeInvokeFail(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerFailsafe(t, invoker)
+	clusterInvoker := registerFailsafe(invoker)
 
 	invoker.EXPECT().GetUrl().Return(failsafeUrl).AnyTimes()
 
diff --git a/cluster/cluster_impl/forking_cluster.go b/cluster/cluster_impl/forking_cluster.go
index a6f7a7b45475f8a26b9b2027a8b4a2fa4f95d509..0e6cd26882788a1f897d0d4dc8e0d4eb0a9d4218 100644
--- a/cluster/cluster_impl/forking_cluster.go
+++ b/cluster/cluster_impl/forking_cluster.go
@@ -31,7 +31,10 @@ func init() {
 	extension.SetCluster(forking, NewForkingCluster)
 }
 
-// NewForkingCluster ...
+// NewForkingCluster returns a forking cluster instance.
+//
+// Multiple servers are invoked in parallel, returning as soon as one succeeds.
+// Usually it is used for real-time demanding read operations while wasting more service resources.
 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 732569416daea8f878569db143271139b791ceca..a5a3f2ec6605dfb843fab09dff0a53000bbc3298 100644
--- a/cluster/cluster_impl/forking_cluster_invoker.go
+++ b/cluster/cluster_impl/forking_cluster_invoker.go
@@ -46,14 +46,12 @@ func newForkingClusterInvoker(directory cluster.Directory) protocol.Invoker {
 
 // Invoke ...
 func (invoker *forkingClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
-	err := invoker.checkWhetherDestroyed()
-	if err != nil {
+	if err := invoker.checkWhetherDestroyed(); err != nil {
 		return &protocol.RPCResult{Err: err}
 	}
 
 	invokers := invoker.directory.List(invocation)
-	err = invoker.checkInvokers(invokers, invocation)
-	if err != nil {
+	if err := invoker.checkInvokers(invokers, invocation); err != nil {
 		return &protocol.RPCResult{Err: err}
 	}
 
@@ -63,11 +61,9 @@ func (invoker *forkingClusterInvoker) Invoke(ctx context.Context, invocation pro
 	if forks < 0 || forks > len(invokers) {
 		selected = invokers
 	} else {
-		selected = make([]protocol.Invoker, 0)
-		loadbalance := getLoadBalance(invokers[0], invocation)
+		loadBalance := getLoadBalance(invokers[0], invocation)
 		for i := 0; i < forks; i++ {
-			ivk := invoker.doSelect(loadbalance, invocation, invokers, selected)
-			if ivk != nil {
+			if ivk := invoker.doSelect(loadBalance, invocation, invokers, selected); ivk != nil {
 				selected = append(selected, ivk)
 			}
 		}
@@ -77,8 +73,7 @@ func (invoker *forkingClusterInvoker) Invoke(ctx context.Context, invocation pro
 	for _, ivk := range selected {
 		go func(k protocol.Invoker) {
 			result := k.Invoke(ctx, invocation)
-			err := resultQ.Put(result)
-			if err != nil {
+			if err := resultQ.Put(result); err != nil {
 				logger.Errorf("resultQ put failed with exception: %v.\n", err)
 			}
 		}(ivk)
@@ -99,6 +94,5 @@ func (invoker *forkingClusterInvoker) Invoke(ctx context.Context, invocation pro
 	if !ok {
 		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 526b137d71c46c166367ac3b3308f9ad5b941538..a2fa136d312db900f45449c92a59009c6661571c 100644
--- a/cluster/cluster_impl/forking_cluster_test.go
+++ b/cluster/cluster_impl/forking_cluster_test.go
@@ -19,6 +19,7 @@ package cluster_impl
 
 import (
 	"context"
+	"fmt"
 	"strconv"
 	"sync"
 	"testing"
@@ -42,10 +43,11 @@ import (
 )
 
 var (
-	forkingUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	forkingUrl, _ = common.NewURL(
+		fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
 )
 
-func registerForking(t *testing.T, mockInvokers ...*mock.MockInvoker) protocol.Invoker {
+func registerForking(mockInvokers ...*mock.MockInvoker) protocol.Invoker {
 	extension.SetLoadbalance(loadbalance.RoundRobin, loadbalance.NewRoundRobinLoadBalance)
 
 	invokers := []protocol.Invoker{}
@@ -62,7 +64,7 @@ func registerForking(t *testing.T, mockInvokers ...*mock.MockInvoker) protocol.I
 	return clusterInvoker
 }
 
-func Test_ForkingInvokeSuccess(t *testing.T) {
+func TestForkingInvokeSuccess(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
@@ -79,20 +81,20 @@ func Test_ForkingInvokeSuccess(t *testing.T) {
 		invokers = append(invokers, invoker)
 		invoker.EXPECT().IsAvailable().Return(true).AnyTimes()
 		invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(
-			func(invocation protocol.Invocation) protocol.Result {
+			func(protocol.Invocation) protocol.Result {
 				wg.Done()
 				return mockResult
 			})
 	}
 
-	clusterInvoker := registerForking(t, invokers...)
+	clusterInvoker := registerForking(invokers...)
 
 	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Equal(t, mockResult, result)
 	wg.Wait()
 }
 
-func Test_ForkingInvokeTimeout(t *testing.T) {
+func TestForkingInvokeTimeout(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
@@ -108,14 +110,14 @@ func Test_ForkingInvokeTimeout(t *testing.T) {
 		invokers = append(invokers, invoker)
 		invoker.EXPECT().IsAvailable().Return(true).AnyTimes()
 		invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(
-			func(invocation protocol.Invocation) protocol.Result {
+			func(protocol.Invocation) protocol.Result {
 				time.Sleep(2 * time.Second)
 				wg.Done()
 				return mockResult
 			})
 	}
 
-	clusterInvoker := registerForking(t, invokers...)
+	clusterInvoker := registerForking(invokers...)
 
 	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.NotNil(t, result)
@@ -123,7 +125,7 @@ func Test_ForkingInvokeTimeout(t *testing.T) {
 	wg.Wait()
 }
 
-func Test_ForkingInvokeHalfTimeout(t *testing.T) {
+func TestForkingInvokeHalfTimeout(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
@@ -140,13 +142,13 @@ func Test_ForkingInvokeHalfTimeout(t *testing.T) {
 		invoker.EXPECT().IsAvailable().Return(true).AnyTimes()
 		if i == 1 {
 			invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(
-				func(invocation protocol.Invocation) protocol.Result {
+				func(protocol.Invocation) protocol.Result {
 					wg.Done()
 					return mockResult
 				})
 		} else {
 			invoker.EXPECT().Invoke(gomock.Any()).DoAndReturn(
-				func(invocation protocol.Invocation) protocol.Result {
+				func(protocol.Invocation) protocol.Result {
 					time.Sleep(2 * time.Second)
 					wg.Done()
 					return mockResult
@@ -154,7 +156,7 @@ func Test_ForkingInvokeHalfTimeout(t *testing.T) {
 		}
 	}
 
-	clusterInvoker := registerForking(t, invokers...)
+	clusterInvoker := registerForking(invokers...)
 
 	result := clusterInvoker.Invoke(context.Background(), &invocation.RPCInvocation{})
 	assert.Equal(t, mockResult, result)
diff --git a/cluster/cluster_impl/mock_cluster.go b/cluster/cluster_impl/mock_cluster.go
index 943c2add68281d01e320252d07b7d58e27b51283..d887cfb45b9c92c859b1396046c1c1c73d46b295 100644
--- a/cluster/cluster_impl/mock_cluster.go
+++ b/cluster/cluster_impl/mock_cluster.go
@@ -24,7 +24,11 @@ import (
 
 type mockCluster struct{}
 
-// NewMockCluster ...
+// NewMockCluster returns a mock cluster instance.
+//
+// Mock cluster is usually used for service degradation, such as an authentication service.
+// When the service provider is completely hung up, the client does not throw an exception,
+// return an authorization failure through the Mock data instead.
 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 079b688da65b3e6f6595212ad6e93c3b6ecc6504..fcefa52862a39eece98dca8660e62d9ca144e955 100644
--- a/cluster/cluster_impl/registry_aware_cluster.go
+++ b/cluster/cluster_impl/registry_aware_cluster.go
@@ -29,7 +29,7 @@ func init() {
 	extension.SetCluster("registryAware", NewRegistryAwareCluster)
 }
 
-// NewRegistryAwareCluster ...
+// NewRegistryAwareCluster returns a registry aware cluster instance
 func NewRegistryAwareCluster() cluster.Cluster {
 	return &registryAwareCluster{}
 }
diff --git a/cluster/cluster_impl/registry_aware_cluster_test.go b/cluster/cluster_impl/registry_aware_cluster_test.go
index 3d0dcc0159839eb0a08aed842ee084449458c645..74584b44800fce3342956f4237a63ffbbabf5544 100644
--- a/cluster/cluster_impl/registry_aware_cluster_test.go
+++ b/cluster/cluster_impl/registry_aware_cluster_test.go
@@ -33,7 +33,7 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-func Test_RegAwareInvokeSuccess(t *testing.T) {
+func TestRegAwareInvokeSuccess(t *testing.T) {
 
 	regAwareCluster := NewRegistryAwareCluster()
 
diff --git a/cluster/directory.go b/cluster/directory.go
index 5a03b3a4490ce0b3aadece8a9ef43395f845dd12..37f0c3282935bac430d0ae676abc72d60d711c85 100644
--- a/cluster/directory.go
+++ b/cluster/directory.go
@@ -23,7 +23,7 @@ import (
 )
 
 // Directory
-//Extension - Directory
+// Extension - Directory
 type Directory interface {
 	common.Node
 	List(invocation protocol.Invocation) []protocol.Invoker
diff --git a/cluster/directory/base_directory_test.go b/cluster/directory/base_directory_test.go
index 6dc55b39407c9e88d18a65b5ec02fa866571624b..8b60163b79b7120829e51f69238474a127133fb4 100644
--- a/cluster/directory/base_directory_test.go
+++ b/cluster/directory/base_directory_test.go
@@ -19,6 +19,7 @@ package directory
 
 import (
 	"encoding/base64"
+	"fmt"
 	"testing"
 )
 
@@ -33,19 +34,20 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
+var (
+	url, _ = common.NewURL(
+		fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
+	anyUrl, _ = common.NewURL(fmt.Sprintf("condition://%s/com.foo.BarService", constant.ANYHOST_VALUE))
+)
+
 func TestNewBaseDirectory(t *testing.T) {
-	url, _ := common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
 	directory := NewBaseDirectory(&url)
-
 	assert.NotNil(t, directory)
-
 	assert.Equal(t, url, directory.GetUrl())
 	assert.Equal(t, &url, directory.GetDirectoryUrl())
-
 }
 
 func TestBuildRouterChain(t *testing.T) {
-	url, _ := common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
 	directory := NewBaseDirectory(&url)
 
 	assert.NotNil(t, directory)
@@ -62,9 +64,8 @@ func TestBuildRouterChain(t *testing.T) {
 }
 
 func getRouteUrl(rule string) *common.URL {
-	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
-	url.AddParam("rule", rule)
-	url.AddParam("force", "true")
-	url.AddParam(constant.ROUTER_KEY, "router")
+	anyUrl.AddParam("rule", rule)
+	anyUrl.AddParam("force", "true")
+	anyUrl.AddParam(constant.ROUTER_KEY, "router")
 	return &url
 }
diff --git a/cluster/directory/static_directory_test.go b/cluster/directory/static_directory_test.go
index c50c9a4063bd1a372c27e47687cbf63850f76cef..8e75a2c2535058f605c3e9bb6d6a01f9ff91032a 100644
--- a/cluster/directory/static_directory_test.go
+++ b/cluster/directory/static_directory_test.go
@@ -32,7 +32,7 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-func Test_StaticDirList(t *testing.T) {
+func TestStaticDirList(t *testing.T) {
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
 		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
@@ -45,7 +45,7 @@ func Test_StaticDirList(t *testing.T) {
 	assert.Len(t, list, 10)
 }
 
-func Test_StaticDirDestroy(t *testing.T) {
+func TestStaticDirDestroy(t *testing.T) {
 	invokers := []protocol.Invoker{}
 	for i := 0; i < 10; i++ {
 		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
diff --git a/cluster/loadbalance.go b/cluster/loadbalance.go
index fb3641a77377eabbd692729a32e2c0c096282f18..a5b344a4952d338e0f481028b3835116f1743773 100644
--- a/cluster/loadbalance.go
+++ b/cluster/loadbalance.go
@@ -22,7 +22,7 @@ import (
 )
 
 // LoadBalance
-//Extension - 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 492434431f7382545cb747fa3611c6b18279fa4d..84fbb268c7a8ec32f007a734e2d6da56ef3c6d25 100644
--- a/cluster/loadbalance/consistent_hash.go
+++ b/cluster/loadbalance/consistent_hash.go
@@ -60,6 +60,8 @@ type ConsistentHashLoadBalance struct {
 }
 
 // NewConsistentHashLoadBalance creates NewConsistentHashLoadBalance
+//
+// The same parameters of the request is always sent to the same provider.
 func NewConsistentHashLoadBalance() cluster.LoadBalance {
 	return &ConsistentHashLoadBalance{}
 }
diff --git a/cluster/loadbalance/least_active.go b/cluster/loadbalance/least_active.go
index e7c41aac93e8d3dfcef5d49fa486483bd045f569..37ad91c3ed6b44370820a989b7af8ccaa82c48a2 100644
--- a/cluster/loadbalance/least_active.go
+++ b/cluster/loadbalance/least_active.go
@@ -28,7 +28,7 @@ import (
 )
 
 const (
-	// LeastActive ...
+	// LeastActive is used to set the load balance extension
 	LeastActive = "leastactive"
 )
 
@@ -39,7 +39,9 @@ func init() {
 type leastActiveLoadBalance struct {
 }
 
-// NewLeastActiveLoadBalance ...
+// NewLeastActiveLoadBalance returns a least active load balance.
+//
+// A random mechanism based on actives, actives means the number of a consumer's requests have been sent to provider but not yet got response.
 func NewLeastActiveLoadBalance() cluster.LoadBalance {
 	return &leastActiveLoadBalance{}
 }
diff --git a/cluster/loadbalance/least_active_test.go b/cluster/loadbalance/least_active_test.go
index 54e57e930f17008cf6d767ef47c0e754ac85d8f7..34be17a4f311a374eefc56ba76885eef2a23645a 100644
--- a/cluster/loadbalance/least_active_test.go
+++ b/cluster/loadbalance/least_active_test.go
@@ -28,6 +28,7 @@ import (
 
 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"
 )
@@ -37,7 +38,7 @@ func TestLeastActiveSelect(t *testing.T) {
 
 	var invokers []protocol.Invoker
 
-	url, _ := common.NewURL("dubbo://192.168.1.0:20000/org.apache.demo.HelloService")
+	url, _ := common.NewURL(fmt.Sprintf("dubbo://%s:%d/org.apache.demo.HelloService", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
 	invokers = append(invokers, protocol.NewBaseInvoker(url))
 	i := loadBalance.Select(invokers, &invocation.RPCInvocation{})
 	assert.True(t, i.GetUrl().URLEqual(url))
diff --git a/cluster/loadbalance/random.go b/cluster/loadbalance/random.go
index 56f13631b653ed070dae7def5bea97d924141209..cdde1b41fb8e986d9923681dc4ab075496ac810e 100644
--- a/cluster/loadbalance/random.go
+++ b/cluster/loadbalance/random.go
@@ -38,7 +38,9 @@ func init() {
 type randomLoadBalance struct {
 }
 
-// NewRandomLoadBalance ...
+// NewRandomLoadBalance returns a random load balance instance.
+//
+// Set random probabilities by weight, and the request will be sent to provider randomly.
 func NewRandomLoadBalance() cluster.LoadBalance {
 	return &randomLoadBalance{}
 }
diff --git a/cluster/loadbalance/random_test.go b/cluster/loadbalance/random_test.go
index ff876f4aef8d229e8041594aaaa096f3ad5b1834..88392de52c93579dd4def3da2d60b415b601b21e 100644
--- a/cluster/loadbalance/random_test.go
+++ b/cluster/loadbalance/random_test.go
@@ -36,7 +36,7 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-func Test_RandomlbSelect(t *testing.T) {
+func TestRandomlbSelect(t *testing.T) {
 	randomlb := NewRandomLoadBalance()
 
 	invokers := []protocol.Invoker{}
@@ -53,7 +53,7 @@ func Test_RandomlbSelect(t *testing.T) {
 	randomlb.Select(invokers, &invocation.RPCInvocation{})
 }
 
-func Test_RandomlbSelectWeight(t *testing.T) {
+func TestRandomlbSelectWeight(t *testing.T) {
 	randomlb := NewRandomLoadBalance()
 
 	invokers := []protocol.Invoker{}
@@ -84,7 +84,7 @@ func Test_RandomlbSelectWeight(t *testing.T) {
 	})
 }
 
-func Test_RandomlbSelectWarmup(t *testing.T) {
+func TestRandomlbSelectWarmup(t *testing.T) {
 	randomlb := NewRandomLoadBalance()
 
 	invokers := []protocol.Invoker{}
diff --git a/cluster/loadbalance/round_robin.go b/cluster/loadbalance/round_robin.go
index 4d039999677aefb1093071666a845279dc357ce9..c44b239dbcbcc744f47ca3c97128f92567e32a78 100644
--- a/cluster/loadbalance/round_robin.go
+++ b/cluster/loadbalance/round_robin.go
@@ -52,7 +52,9 @@ func init() {
 
 type roundRobinLoadBalance struct{}
 
-// NewRoundRobinLoadBalance ...
+// NewRoundRobinLoadBalance returns a round robin load balance
+//
+// Use the weight's common advisory to determine round robin ratio
 func NewRoundRobinLoadBalance() cluster.LoadBalance {
 	return &roundRobinLoadBalance{}
 }
diff --git a/cluster/loadbalance/round_robin_test.go b/cluster/loadbalance/round_robin_test.go
index 1517f2a20b473af57cc23e61b988aa5a6a04de31..5354bae458605ff56ec8a9b35d36730ecdc0babb 100644
--- a/cluster/loadbalance/round_robin_test.go
+++ b/cluster/loadbalance/round_robin_test.go
@@ -29,6 +29,7 @@ import (
 
 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"
 )
@@ -38,7 +39,8 @@ func TestRoundRobinSelect(t *testing.T) {
 
 	var invokers []protocol.Invoker
 
-	url, _ := common.NewURL("dubbo://192.168.1.0:20000/org.apache.demo.HelloService")
+	url, _ := common.NewURL(fmt.Sprintf("dubbo://%s:%d/org.apache.demo.HelloService",
+		constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
 	invokers = append(invokers, protocol.NewBaseInvoker(url))
 	i := loadBalance.Select(invokers, &invocation.RPCInvocation{})
 	assert.True(t, i.GetUrl().URLEqual(url))
diff --git a/cluster/loadbalance/util.go b/cluster/loadbalance/util.go
index 9f36ad9379a3a09a4a058f6179e3e537b9e105bc..b6c013852bf55ce7eb67e4fa18802a938141d283 100644
--- a/cluster/loadbalance/util.go
+++ b/cluster/loadbalance/util.go
@@ -26,7 +26,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// GetWeight ...
+// GetWeight gets weight for load balance strategy
 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/chain/chain_test.go b/cluster/router/chain/chain_test.go
index 0cb47c4a185fe19b5f70ea4db2b80aab2f1aada5..c7a75f3d8608ecb7a95dcf33027e71b61d7f00f5 100644
--- a/cluster/router/chain/chain_test.go
+++ b/cluster/router/chain/chain_test.go
@@ -42,10 +42,16 @@ import (
 	"github.com/apache/dubbo-go/remoting/zookeeper"
 )
 
+const (
+	path     = "/dubbo/config/dubbo/test-condition.condition-router"
+	zkPrefix = "zookeeper://127.0.0.1:"
+	anyUrl   = "condition://0.0.0.0/com.foo.BarService"
+)
+
 func TestNewRouterChain(t *testing.T) {
 	ts, z, _, err := zookeeper.NewMockZookeeperClient("test", 15*time.Second)
 	assert.NoError(t, err)
-	err = z.Create("/dubbo/config/dubbo/test-condition.condition-router")
+	err = z.Create(path)
 	assert.NoError(t, err)
 
 	testyml := `enabled: true
@@ -55,12 +61,12 @@ conditions:
   - => host != 172.22.3.91
 `
 
-	_, err = z.Conn.Set("/dubbo/config/dubbo/test-condition.condition-router", []byte(testyml), 0)
+	_, err = z.Conn.Set(path, []byte(testyml), 0)
 	assert.NoError(t, err)
 	defer ts.Stop()
 	defer z.Close()
 
-	zkUrl, _ := common.NewURL("zookeeper://127.0.0.1:" + strconv.Itoa(ts.Servers[0].Port))
+	zkUrl, _ := common.NewURL(zkPrefix + strconv.Itoa(ts.Servers[0].Port))
 	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
@@ -92,10 +98,10 @@ func TestNewRouterChainURLNil(t *testing.T) {
 	assert.NotNil(t, chain)
 }
 
-func TestRouterChain_AddRouters(t *testing.T) {
+func TestRouterChainAddRouters(t *testing.T) {
 	ts, z, _, err := zookeeper.NewMockZookeeperClient("test", 15*time.Second)
 	assert.NoError(t, err)
-	err = z.Create("/dubbo/config/dubbo/test-condition.condition-router")
+	err = z.Create(path)
 	assert.NoError(t, err)
 
 	testyml := `enabled: true
@@ -105,12 +111,12 @@ conditions:
   - => host != 172.22.3.91
 `
 
-	_, err = z.Conn.Set("/dubbo/config/dubbo/test-condition.condition-router", []byte(testyml), 0)
+	_, err = z.Conn.Set(path, []byte(testyml), 0)
 	assert.NoError(t, err)
 	defer ts.Stop()
 	defer z.Close()
 
-	zkUrl, _ := common.NewURL("zookeeper://127.0.0.1:" + strconv.Itoa(ts.Servers[0].Port))
+	zkUrl, _ := common.NewURL(zkPrefix + strconv.Itoa(ts.Servers[0].Port))
 	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
@@ -131,12 +137,12 @@ conditions:
 	assert.Equal(t, 3, len(chain.routers))
 }
 
-func TestRouterChain_Route(t *testing.T) {
+func TestRouterChainRoute(t *testing.T) {
 	ts, z, _, err := zookeeper.NewMockZookeeperClient("test", 15*time.Second)
 	defer ts.Stop()
 	defer z.Close()
 
-	zkUrl, _ := common.NewURL("zookeeper://127.0.0.1:" + strconv.Itoa(ts.Servers[0].Port))
+	zkUrl, _ := common.NewURL(zkPrefix + strconv.Itoa(ts.Servers[0].Port))
 	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
@@ -158,10 +164,10 @@ func TestRouterChain_Route(t *testing.T) {
 	assert.Equal(t, 1, len(finalInvokers))
 }
 
-func TestRouterChain_Route_AppRouter(t *testing.T) {
+func TestRouterChainRouteAppRouter(t *testing.T) {
 	ts, z, _, err := zookeeper.NewMockZookeeperClient("test", 15*time.Second)
 	assert.NoError(t, err)
-	err = z.Create("/dubbo/config/dubbo/test-condition.condition-router")
+	err = z.Create(path)
 	assert.NoError(t, err)
 
 	testyml := `enabled: true
@@ -171,12 +177,12 @@ conditions:
   - => host = 1.1.1.1 => host != 1.2.3.4
 `
 
-	_, err = z.Conn.Set("/dubbo/config/dubbo/test-condition.condition-router", []byte(testyml), 0)
+	_, err = z.Conn.Set(path, []byte(testyml), 0)
 	assert.NoError(t, err)
 	defer ts.Stop()
 	defer z.Close()
 
-	zkUrl, _ := common.NewURL("zookeeper://127.0.0.1:" + strconv.Itoa(ts.Servers[0].Port))
+	zkUrl, _ := common.NewURL(zkPrefix + strconv.Itoa(ts.Servers[0].Port))
 	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
@@ -200,7 +206,7 @@ func TestRouterChain_Route_NoRoute(t *testing.T) {
 	defer ts.Stop()
 	defer z.Close()
 
-	zkUrl, _ := common.NewURL("zookeeper://127.0.0.1:" + strconv.Itoa(ts.Servers[0].Port))
+	zkUrl, _ := common.NewURL(zkPrefix + strconv.Itoa(ts.Servers[0].Port))
 	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
@@ -223,7 +229,7 @@ func TestRouterChain_Route_NoRoute(t *testing.T) {
 }
 
 func getConditionNoRouteUrl(applicationKey string) *common.URL {
-	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
+	url, _ := common.NewURL(anyUrl)
 	url.AddParam("application", applicationKey)
 	url.AddParam("force", "true")
 	rule := base64.URLEncoding.EncodeToString([]byte("host = 1.1.1.1 => host != 1.2.3.4"))
@@ -232,7 +238,7 @@ func getConditionNoRouteUrl(applicationKey string) *common.URL {
 }
 
 func getConditionRouteUrl(applicationKey string) *common.URL {
-	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
+	url, _ := common.NewURL(anyUrl)
 	url.AddParam("application", applicationKey)
 	url.AddParam("force", "true")
 	rule := base64.URLEncoding.EncodeToString([]byte("host = 1.1.1.1 => host = 1.2.3.4"))
@@ -241,7 +247,7 @@ func getConditionRouteUrl(applicationKey string) *common.URL {
 }
 
 func getRouteUrl(applicationKey string) *common.URL {
-	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
+	url, _ := common.NewURL(anyUrl)
 	url.AddParam("application", applicationKey)
 	url.AddParam("force", "true")
 	return &url
diff --git a/cluster/router/condition/app_router_test.go b/cluster/router/condition/app_router_test.go
index e99307625baf34fa6b744f168ff4e6cb8e042502..f37a483e8468bc57d3ce1e73172ccf9a05bc29f0 100644
--- a/cluster/router/condition/app_router_test.go
+++ b/cluster/router/condition/app_router_test.go
@@ -37,6 +37,10 @@ import (
 	"github.com/apache/dubbo-go/remoting/zookeeper"
 )
 
+const (
+	path = "/dubbo/config/dubbo/test-condition.condition-router"
+)
+
 func TestNewAppRouter(t *testing.T) {
 
 	testYML := `enabled: true
@@ -47,10 +51,10 @@ conditions:
 `
 	ts, z, _, err := zookeeper.NewMockZookeeperClient("test", 15*time.Second)
 	assert.NoError(t, err)
-	err = z.Create("/dubbo/config/dubbo/test-condition.condition-router")
+	err = z.Create(path)
 	assert.NoError(t, err)
 
-	_, err = z.Conn.Set("/dubbo/config/dubbo/test-condition.condition-router", []byte(testYML), 0)
+	_, err = z.Conn.Set(path, []byte(testYML), 0)
 	assert.NoError(t, err)
 	defer ts.Stop()
 	defer z.Close()
@@ -93,10 +97,10 @@ conditions:
 `
 	ts, z, _, err := zookeeper.NewMockZookeeperClient("test", 15*time.Second)
 	assert.NoError(t, err)
-	err = z.Create("/dubbo/config/dubbo/test-condition.condition-router")
+	err = z.Create(path)
 	assert.NoError(t, err)
 
-	_, err = z.Conn.Set("/dubbo/config/dubbo/test-condition.condition-router", []byte(testYML), 0)
+	_, err = z.Conn.Set(path, []byte(testYML), 0)
 	assert.NoError(t, err)
 	defer ts.Stop()
 	defer z.Close()
@@ -130,10 +134,10 @@ conditions:
 `
 	ts, z, _, err := zookeeper.NewMockZookeeperClient("test", 15*time.Second)
 	assert.NoError(t, err)
-	err = z.Create("/dubbo/config/dubbo/test-condition.condition-router")
+	err = z.Create(path)
 	assert.NoError(t, err)
 
-	_, err = z.Conn.Set("/dubbo/config/dubbo/test-condition.condition-router", []byte(testYML), 0)
+	_, err = z.Conn.Set(path, []byte(testYML), 0)
 	assert.NoError(t, err)
 	defer ts.Stop()
 	defer z.Close()
diff --git a/cluster/router/condition/factory_test.go b/cluster/router/condition/factory_test.go
index 99cec34096a55d3c2a967b63afdf5f6d0a77279a..a826cafb85ee1a30ac568db34e10dd2c9c9e87d0 100644
--- a/cluster/router/condition/factory_test.go
+++ b/cluster/router/condition/factory_test.go
@@ -38,6 +38,8 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
+const anyUrl = "condition://0.0.0.0/com.foo.BarService"
+
 type MockInvoker struct {
 	url          common.URL
 	available    bool
@@ -59,21 +61,21 @@ func (bi *MockInvoker) GetUrl() common.URL {
 }
 
 func getRouteUrl(rule string) *common.URL {
-	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
+	url, _ := common.NewURL(anyUrl)
 	url.AddParam("rule", rule)
 	url.AddParam("force", "true")
 	return &url
 }
 
 func getRouteUrlWithForce(rule, force string) *common.URL {
-	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
+	url, _ := common.NewURL(anyUrl)
 	url.AddParam("rule", rule)
 	url.AddParam("force", force)
 	return &url
 }
 
 func getRouteUrlWithNoForce(rule string) *common.URL {
-	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
+	url, _ := common.NewURL(anyUrl)
 	url.AddParam("rule", rule)
 	return &url
 }
@@ -116,7 +118,7 @@ func (bi *MockInvoker) Destroy() {
 	bi.available = false
 }
 
-func TestRoute_matchWhen(t *testing.T) {
+func TestRouteMatchWhen(t *testing.T) {
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("=> host = 1.2.3.4"))
 	router, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule))
@@ -149,7 +151,7 @@ func TestRoute_matchWhen(t *testing.T) {
 	assert.Equal(t, true, matchWhen6)
 }
 
-func TestRoute_matchFilter(t *testing.T) {
+func TestRouteMatchFilter(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
 	t.Logf("The local ip is %s", localIP)
 	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService?default.serialization=fastjson")
@@ -184,7 +186,7 @@ func TestRoute_matchFilter(t *testing.T) {
 
 }
 
-func TestRoute_methodRoute(t *testing.T) {
+func TestRouteMethodRoute(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().NewRouter(getRouteUrl(rule))
@@ -207,7 +209,7 @@ func TestRoute_methodRoute(t *testing.T) {
 
 }
 
-func TestRoute_ReturnFalse(t *testing.T) {
+func TestRouteReturnFalse(t *testing.T) {
 	url, _ := common.NewURL("")
 	localIP, _ := gxnet.GetLocalIP()
 	invokers := []protocol.Invoker{NewMockInvoker(url, 1), NewMockInvoker(url, 2), NewMockInvoker(url, 3)}
@@ -219,7 +221,7 @@ func TestRoute_ReturnFalse(t *testing.T) {
 	assert.Equal(t, 0, len(fileredInvokers))
 }
 
-func TestRoute_ReturnEmpty(t *testing.T) {
+func TestRouteReturnEmpty(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
 	url, _ := common.NewURL("")
 	invokers := []protocol.Invoker{NewMockInvoker(url, 1), NewMockInvoker(url, 2), NewMockInvoker(url, 3)}
@@ -231,7 +233,7 @@ func TestRoute_ReturnEmpty(t *testing.T) {
 	assert.Equal(t, 0, len(fileredInvokers))
 }
 
-func TestRoute_ReturnAll(t *testing.T) {
+func TestRouteReturnAll(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
 	urlString := "dubbo://" + localIP + "/com.foo.BarService"
 	dubboURL, _ := common.NewURL(urlString)
@@ -247,7 +249,7 @@ func TestRoute_ReturnAll(t *testing.T) {
 	assert.Equal(t, invokers, fileredInvokers)
 }
 
-func TestRoute_HostFilter(t *testing.T) {
+func TestRouteHostFilter(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
 	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
 	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
@@ -266,7 +268,7 @@ func TestRoute_HostFilter(t *testing.T) {
 	assert.Equal(t, invoker3, fileredInvokers[1])
 }
 
-func TestRoute_Empty_HostFilter(t *testing.T) {
+func TestRouteEmptyHostFilter(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
 	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
 	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
@@ -285,7 +287,7 @@ func TestRoute_Empty_HostFilter(t *testing.T) {
 	assert.Equal(t, invoker3, fileredInvokers[1])
 }
 
-func TestRoute_False_HostFilter(t *testing.T) {
+func TestRouteFalseHostFilter(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
 	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
 	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
@@ -304,7 +306,7 @@ func TestRoute_False_HostFilter(t *testing.T) {
 	assert.Equal(t, invoker3, fileredInvokers[1])
 }
 
-func TestRoute_Placeholder(t *testing.T) {
+func TestRoutePlaceholder(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
 	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
 	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
@@ -323,7 +325,7 @@ func TestRoute_Placeholder(t *testing.T) {
 	assert.Equal(t, invoker3, fileredInvokers[1])
 }
 
-func TestRoute_NoForce(t *testing.T) {
+func TestRouteNoForce(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
 	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
 	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
@@ -340,7 +342,7 @@ func TestRoute_NoForce(t *testing.T) {
 	assert.Equal(t, invokers, fileredInvokers)
 }
 
-func TestRoute_Force(t *testing.T) {
+func TestRouteForce(t *testing.T) {
 	localIP, _ := gxnet.GetLocalIP()
 	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService")
 	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
diff --git a/cluster/router/healthcheck/default_health_check_test.go b/cluster/router/healthcheck/default_health_check_test.go
index 74aa3940743a012f907cfe3d8811a618f07ff800..8a95d9a7e8dffdc3f30f94c76274a729837fc133 100644
--- a/cluster/router/healthcheck/default_health_check_test.go
+++ b/cluster/router/healthcheck/default_health_check_test.go
@@ -37,7 +37,7 @@ func TestDefaultHealthChecker_IsHealthy(t *testing.T) {
 	defer protocol.CleanAllStatus()
 	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
 	hc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
-	invoker := NewMockInvoker(url, 1)
+	invoker := NewMockInvoker(url)
 	healthy := hc.IsHealthy(invoker)
 	assert.True(t, healthy)
 
diff --git a/cluster/router/healthcheck/factory_test.go b/cluster/router/healthcheck/factory_test.go
index a9d94da7c37f0e0c9640de1386998a85823e80a6..c3a26a93896e185f0dea3732ca5afcf7687ad5ea 100644
--- a/cluster/router/healthcheck/factory_test.go
+++ b/cluster/router/healthcheck/factory_test.go
@@ -35,7 +35,7 @@ type MockInvoker struct {
 	url common.URL
 }
 
-func NewMockInvoker(url common.URL, successCount int) *MockInvoker {
+func NewMockInvoker(url common.URL) *MockInvoker {
 	return &MockInvoker{
 		url: url,
 	}
diff --git a/cluster/router/healthcheck/health_check_route_test.go b/cluster/router/healthcheck/health_check_route_test.go
index 759ef93dbeb8d91a82eefd59060afbe8a10a4440..7bfffea705bfedade9d1d13ac7e9c380651335dd 100644
--- a/cluster/router/healthcheck/health_check_route_test.go
+++ b/cluster/router/healthcheck/health_check_route_test.go
@@ -44,9 +44,9 @@ func TestHealthCheckRouter_Route(t *testing.T) {
 	hcr, _ := NewHealthCheckRouter(&consumerURL)
 
 	var invokers []protocol.Invoker
-	invoker1 := NewMockInvoker(url1, 1)
-	invoker2 := NewMockInvoker(url2, 1)
-	invoker3 := NewMockInvoker(url3, 1)
+	invoker1 := NewMockInvoker(url1)
+	invoker2 := NewMockInvoker(url2)
+	invoker3 := NewMockInvoker(url3)
 	invokers = append(invokers, invoker1, invoker2, invoker3)
 	inv := invocation.NewRPCInvocation("test", nil, nil)
 	res := hcr.Route(invokers, &consumerURL, inv)
diff --git a/common/constant/default.go b/common/constant/default.go
index 45fc38f13e05a45e650cffcfe50177d71c8f797e..c1c404e089ea90899d2b599b01cd5980c3e92ab1 100644
--- a/common/constant/default.go
+++ b/common/constant/default.go
@@ -43,6 +43,7 @@ const (
 	DEFAULT_FAILBACK_TASKS     = 100
 	DEFAULT_REST_CLIENT        = "resty"
 	DEFAULT_REST_SERVER        = "go-restful"
+	DEFAULT_PORT               = 20000
 )
 
 const (
@@ -58,6 +59,7 @@ const (
 const (
 	ANY_VALUE           = "*"
 	ANYHOST_VALUE       = "0.0.0.0"
+	LOCAL_HOST_VALUE    = "192.168.1.1"
 	REMOVE_VALUE_PREFIX = "-"
 )
 
diff --git a/common/constant/key.go b/common/constant/key.go
index 18d7f3de3d5f878583312cfcaeef24e31a7a58ef..a61073de78e1c6ed5cedeb034be8ce2d3b1fb96e 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -127,6 +127,7 @@ const (
 	CONFIG_CLUSTER_KEY    = "config.cluster"
 	CONFIG_CHECK_KEY      = "config.check"
 	CONFIG_TIMEOUT_KET    = "config.timeout"
+	CONFIG_LOG_DIR_KEY    = "config.logDir"
 	CONFIG_VERSION_KEY    = "configVersion"
 	COMPATIBLE_CONFIG_KEY = "compatible_config"
 )
@@ -163,6 +164,10 @@ const (
 	ZOOKEEPER_KEY = "zookeeper"
 )
 
+const (
+	ETCDV3_KEY = "etcdv3"
+)
+
 const (
 	TRACING_REMOTE_SPAN_CTX = "tracing.remote.span.ctx"
 )
@@ -281,6 +286,4 @@ const (
 
 	// SERVICE_DISCOVERY_KEY indicate which service discovery instance will be used
 	SERVICE_DISCOVERY_KEY = "service_discovery"
-	LANGUAGE_KEY          = "language"
-	GO_LANG               = "golang"
 )
diff --git a/common/extension/auth.go b/common/extension/auth.go
index 7caae00e84fd80666ff79b599e12f8516e23209c..4fca0a8e8c255456720df9e4fd9852295715b160 100644
--- a/common/extension/auth.go
+++ b/common/extension/auth.go
@@ -32,7 +32,7 @@ func SetAuthenticator(name string, fcn func() filter.Authenticator) {
 }
 
 // GetAuthenticator finds the Authenticator with @name
-// if not found, it will panic
+// Panic if not found
 func GetAuthenticator(name string) filter.Authenticator {
 	if authenticators[name] == nil {
 		panic("authenticator for " + name + " is not existing, make sure you have import the package.")
@@ -46,7 +46,7 @@ func SetAccesskeyStorages(name string, fcn func() filter.AccessKeyStorage) {
 }
 
 // GetAccesskeyStorages finds the storage with the @name.
-// If not found, it will panic.
+// Panic if not found
 func GetAccesskeyStorages(name string) filter.AccessKeyStorage {
 	if accesskeyStorages[name] == nil {
 		panic("accesskeyStorages 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 3cbced8d3bbcdb3dc7f9af800fa36681d6dc063d..5a2c52f32d070f5ec03bdae0b3cd47f869c28171 100644
--- a/common/extension/config_center.go
+++ b/common/extension/config_center.go
@@ -27,7 +27,7 @@ var (
 )
 
 // SetConfigCenter sets the DynamicConfiguration with @name
-func SetConfigCenter(name string, v func(config *common.URL) (config_center.DynamicConfiguration, error)) {
+func SetConfigCenter(name string, v func(*common.URL) (config_center.DynamicConfiguration, error)) {
 	configCenters[name] = v
 }
 
diff --git a/common/extension/event_dispatcher.go b/common/extension/event_dispatcher.go
index a543910cc1f212a85bc3c5751f59c81fc991cfa2..f0503e05422844e129a81212beed6af414612b6b 100644
--- a/common/extension/event_dispatcher.go
+++ b/common/extension/event_dispatcher.go
@@ -19,7 +19,9 @@ package extension
 
 import (
 	"sync"
+)
 
+import (
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/common/observer"
 )
@@ -34,21 +36,26 @@ var (
 	dispatchers = make(map[string]func() observer.EventDispatcher, 8)
 )
 
-// SetEventDispatcher by name
+// SetEventDispatcher, actually, it doesn't really init the global dispatcher
 func SetEventDispatcher(name string, v func() observer.EventDispatcher) {
 	dispatchers[name] = v
 }
 
-// SetAndInitGlobalDispatcher
+// SetAndInitGlobalDispatcher will actually init the global dispatcher
+// if there is already a global dispatcher,
+// it will be override
+// if the dispatcher with the name not found, it will panic
 func SetAndInitGlobalDispatcher(name string) {
 	if len(name) == 0 {
 		name = "direct"
 	}
 	if globalEventDispatcher != nil {
-		logger.Warnf("EventDispatcher already init. It will be replaced")
+		logger.Warnf("EventDispatcher has been initialized. It will be replaced")
 	}
+
 	if dp, ok := dispatchers[name]; !ok || dp == nil {
-		panic("EventDispatcher for " + name + " is not existing, make sure you have import the package.")
+		panic("EventDispatcher for " + name + " is not found, make sure you have import the package, " +
+			"like import _ github.com/apache/dubbo-go/common/observer/dispatcher ")
 	}
 	globalEventDispatcher = dispatchers[name]()
 }
diff --git a/common/extension/event_dispatcher_test.go b/common/extension/event_dispatcher_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..472360cea5a04c2cd70f0df6ea4db23f6be88f1a
--- /dev/null
+++ b/common/extension/event_dispatcher_test.go
@@ -0,0 +1,111 @@
+/*
+ * 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 (
+	"reflect"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+import (
+	"github.com/apache/dubbo-go/common/observer"
+)
+
+func TestSetAndInitGlobalDispatcher(t *testing.T) {
+	mock := &mockEventDispatcher{}
+	SetEventDispatcher("mock", func() observer.EventDispatcher {
+		return mock
+	})
+
+	SetAndInitGlobalDispatcher("mock")
+	dispatcher := GetGlobalDispatcher()
+	assert.NotNil(t, dispatcher)
+	assert.Equal(t, mock, dispatcher)
+
+	mock1 := &mockEventDispatcher{}
+
+	SetEventDispatcher("mock1", func() observer.EventDispatcher {
+		return mock1
+	})
+
+	SetAndInitGlobalDispatcher("mock1")
+	dispatcher = GetGlobalDispatcher()
+	assert.NotNil(t, dispatcher)
+	assert.Equal(t, mock1, dispatcher)
+}
+
+func TestAddEventListener(t *testing.T) {
+	AddEventListener(func() observer.EventListener {
+		return &mockEventListener{}
+	})
+
+	AddEventListener(func() observer.EventListener {
+		return &mockEventListener{}
+	})
+
+	assert.Equal(t, 2, len(initEventListeners))
+}
+
+type mockEventListener struct {
+}
+
+func (m mockEventListener) GetPriority() int {
+	panic("implement me")
+}
+
+func (m mockEventListener) OnEvent(e observer.Event) error {
+	panic("implement me")
+}
+
+func (m mockEventListener) GetEventType() reflect.Type {
+	panic("implement me")
+}
+
+type mockEventDispatcher struct {
+}
+
+func (m mockEventDispatcher) AddEventListener(listener observer.EventListener) {
+	panic("implement me")
+}
+
+func (m mockEventDispatcher) AddEventListeners(listenersSlice []observer.EventListener) {
+	panic("implement me")
+}
+
+func (m mockEventDispatcher) RemoveEventListener(listener observer.EventListener) {
+	panic("implement me")
+}
+
+func (m mockEventDispatcher) RemoveEventListeners(listenersSlice []observer.EventListener) {
+	panic("implement me")
+}
+
+func (m mockEventDispatcher) GetAllEventListeners() []observer.EventListener {
+	panic("implement me")
+}
+
+func (m mockEventDispatcher) RemoveAllEventListeners() {
+	panic("implement me")
+}
+
+func (m mockEventDispatcher) Dispatch(event observer.Event) {
+	panic("implement me")
+}
diff --git a/common/extension/metadata_service.go b/common/extension/metadata_service.go
index 93ff40aa763100ece3b557598e24eeb8f81454a9..1823273b8f7f86b2d96abf990359e14b569abddb 100644
--- a/common/extension/metadata_service.go
+++ b/common/extension/metadata_service.go
@@ -19,7 +19,9 @@ package extension
 
 import (
 	"fmt"
+)
 
+import (
 	"github.com/apache/dubbo-go/metadata/service"
 )
 
@@ -28,10 +30,13 @@ var (
 	metadataServiceInsMap = make(map[string]func() (service.MetadataService, error), 2)
 )
 
+// SetMetadataService will store the msType => creator pair
 func SetMetadataService(msType string, creator func() (service.MetadataService, error)) {
 	metadataServiceInsMap[msType] = creator
 }
 
+// GetMetadataService will create a MetadataService instance
+// it will panic if msType not found
 func GetMetadataService(msType string) (service.MetadataService, error) {
 	if creator, ok := metadataServiceInsMap[msType]; ok {
 		return creator()
diff --git a/common/extension/metadata_service_proxy_factory.go b/common/extension/metadata_service_proxy_factory.go
index 35f63c5fa9a15916739f32e7c1810c04e7ed4b2c..e8c9e73d7362a83843f3cb6c52c0f3bd15ab1cc8 100644
--- a/common/extension/metadata_service_proxy_factory.go
+++ b/common/extension/metadata_service_proxy_factory.go
@@ -19,7 +19,9 @@ package extension
 
 import (
 	"fmt"
+)
 
+import (
 	"github.com/apache/dubbo-go/metadata/service"
 )
 
@@ -27,10 +29,13 @@ var (
 	metadataServiceProxyFactoryMap = make(map[string]func() service.MetadataServiceProxyFactory)
 )
 
+// SetMetadataServiceProxyFactory store the name-creator pair
 func SetMetadataServiceProxyFactory(name string, creator func() service.MetadataServiceProxyFactory) {
 	metadataServiceProxyFactoryMap[name] = creator
 }
 
+// GetMetadataServiceProxyFactory will create an instance.
+// it will panic if the factory with name not found
 func GetMetadataServiceProxyFactory(name string) service.MetadataServiceProxyFactory {
 	if f, ok := metadataServiceProxyFactoryMap[name]; ok {
 		return f()
diff --git a/common/extension/registry.go b/common/extension/registry.go
index 291a7a7fc2cae07c9228043acae7cc0ed5459a1f..542a2206c0bdda658c4ba363e939bbc569b2b49e 100644
--- a/common/extension/registry.go
+++ b/common/extension/registry.go
@@ -34,7 +34,7 @@ func SetRegistry(name string, v func(config *common.URL) (registry.Registry, err
 // GetRegistry finds the registry extension with @name
 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.")
+		panic("registry for " + name + " does not exist. please make sure that you have imported the package `github.com/apache/dubbo-go/registry/" + name + "`.")
 	}
 	return registrys[name](config)
 
diff --git a/common/extension/service_discovery.go b/common/extension/service_discovery.go
index 456b14c83dcab4189ea287f2e9f3329109e538c3..0227920dc64a7b5f6ad1939fcccbb7384c43f68d 100644
--- a/common/extension/service_discovery.go
+++ b/common/extension/service_discovery.go
@@ -42,7 +42,7 @@ func SetServiceDiscovery(protocol string, creator func(name string) (registry.Se
 func GetServiceDiscovery(protocol string, name string) (registry.ServiceDiscovery, error) {
 	creator, ok := discoveryCreatorMap[protocol]
 	if !ok {
-		return nil, perrors.New("Could not find the service discovery with name: " + name)
+		return nil, perrors.New("Could not find the service discovery with discovery protocol: " + protocol)
 	}
 	return creator(name)
 }
diff --git a/common/extension/service_instance_customizer.go b/common/extension/service_instance_customizer.go
index a0e443aff5eb4e0ce403a0568c110a79e888d76a..3ebb3e40f5851ad4799e7cee5966edd77cea2f9e 100644
--- a/common/extension/service_instance_customizer.go
+++ b/common/extension/service_instance_customizer.go
@@ -19,7 +19,9 @@ package extension
 
 import (
 	"sort"
+)
 
+import (
 	"github.com/apache/dubbo-go/registry"
 )
 
@@ -35,15 +37,20 @@ func AddCustomizers(cus registry.ServiceInstanceCustomizer) {
 }
 
 // GetCustomizers will return the sorted customizer
+// the result won't be nil
 func GetCustomizers() []registry.ServiceInstanceCustomizer {
 	return customizers
 }
 
 type customizerSlice []registry.ServiceInstanceCustomizer
 
+// nolint
 func (c customizerSlice) Len() int {
 	return len(c)
 }
 
-func (c customizerSlice) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
+// nolint
+func (c customizerSlice) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
+
+// nolint
 func (c customizerSlice) Less(i, j int) bool { return c[i].GetPriority() < c[j].GetPriority() }
diff --git a/common/extension/service_instance_selector_factory.go b/common/extension/service_instance_selector_factory.go
index 3ba3db46e65ed01a5417075d998209ae39df38ec..7776a408d8ea3849907a4b12f5464aaa0e1e96aa 100644
--- a/common/extension/service_instance_selector_factory.go
+++ b/common/extension/service_instance_selector_factory.go
@@ -29,10 +29,13 @@ var (
 	serviceInstanceSelectorMappings = make(map[string]func() instance.ServiceInstanceSelector)
 )
 
+// nolint
 func SetServiceInstanceSelector(name string, f func() instance.ServiceInstanceSelector) {
 	serviceInstanceSelectorMappings[name] = f
 }
 
+// GetServiceInstanceSelector will create an instance
+// it will panic if selector with the @name not found
 func GetServiceInstanceSelector(name string) (instance.ServiceInstanceSelector, error) {
 	serviceInstanceSelector, ok := serviceInstanceSelectorMappings[name]
 	if !ok {
diff --git a/common/extension/service_name_mapping.go b/common/extension/service_name_mapping.go
index cd2630198ec142c6d168453c939c004bde940998..9e5aac52f90fd3fb68a342a91c7562c60e9c808c 100644
--- a/common/extension/service_name_mapping.go
+++ b/common/extension/service_name_mapping.go
@@ -17,7 +17,9 @@
 
 package extension
 
-import "github.com/apache/dubbo-go/metadata/mapping"
+import (
+	"github.com/apache/dubbo-go/metadata/mapping"
+)
 
 var (
 	globalNameMappingCreator func() mapping.ServiceNameMapping
diff --git a/common/observer/dispatcher/direct_event_dispatcher.go b/common/observer/dispatcher/direct_event_dispatcher.go
index 2b7567b47ed40caa8867901ff0a05e0a2497cd31..a2d334ce2ca9461a8e14e28bb0f3ecf21971751f 100644
--- a/common/observer/dispatcher/direct_event_dispatcher.go
+++ b/common/observer/dispatcher/direct_event_dispatcher.go
@@ -36,26 +36,31 @@ func init() {
 // Align with 2.7.5
 // Dispatcher event to listener direct
 type DirectEventDispatcher struct {
-	observer.BaseListenable
+	observer.BaseListener
 }
 
 // NewDirectEventDispatcher ac constructor of DirectEventDispatcher
 func NewDirectEventDispatcher() observer.EventDispatcher {
-	return &DirectEventDispatcher{}
+	return &DirectEventDispatcher{
+		BaseListener: observer.NewBaseListener(),
+	}
 }
 
 // Dispatch event directly
+// it lookup the listener by event's type.
+// if listener not found, it just return and do nothing
 func (ded *DirectEventDispatcher) Dispatch(event observer.Event) {
 	if event == nil {
 		logger.Warnf("[DirectEventDispatcher] dispatch event nil")
 		return
 	}
 	eventType := reflect.TypeOf(event).Elem()
-	value, loaded := ded.ListenersCache.Load(eventType)
+	ded.Mutex.RLock()
+	defer ded.Mutex.RUnlock()
+	listenersSlice, loaded := ded.ListenersCache[eventType]
 	if !loaded {
 		return
 	}
-	listenersSlice := value.([]observer.EventListener)
 	for _, listener := range listenersSlice {
 		if err := listener.OnEvent(event); err != nil {
 			logger.Warnf("[DirectEventDispatcher] dispatch event error:%v", err)
diff --git a/common/observer/dispatcher/direct_event_dispatcher_test.go b/common/observer/dispatcher/direct_event_dispatcher_test.go
index 355c930a9e86dbe6e82adc2795f8590c15a473c2..12facbb9c4bd1b33fa071a50beae87b77e1be968 100644
--- a/common/observer/dispatcher/direct_event_dispatcher_test.go
+++ b/common/observer/dispatcher/direct_event_dispatcher_test.go
@@ -29,7 +29,9 @@ import (
 
 func TestDirectEventDispatcher_Dispatch(t *testing.T) {
 	ded := NewDirectEventDispatcher()
-	ded.AddEventListener(&TestEventListener{})
+	ded.AddEventListener(&TestEventListener{
+		BaseListener: observer.NewBaseListener(),
+	})
 	ded.AddEventListener(&TestEventListener1{})
 	ded.Dispatch(&TestEvent{})
 	ded.Dispatch(nil)
@@ -40,7 +42,7 @@ type TestEvent struct {
 }
 
 type TestEventListener struct {
-	observer.BaseListenable
+	observer.BaseListener
 	observer.EventListener
 }
 
diff --git a/common/observer/event.go b/common/observer/event.go
index d78179043e8a2059e1d5fd15878fe32d7596321e..209a50c78a36c13d789f6f9fbc81a73a5d9a535f 100644
--- a/common/observer/event.go
+++ b/common/observer/event.go
@@ -58,6 +58,8 @@ func (b *BaseEvent) String() string {
 	return fmt.Sprintf("BaseEvent[source = %#v]", b.Source)
 }
 
+// NewBaseEvent create an BaseEvent instance
+// and the Timestamp will be current timestamp
 func NewBaseEvent(source interface{}) *BaseEvent {
 	return &BaseEvent{
 		Source:    source,
diff --git a/common/observer/listenable.go b/common/observer/listenable.go
index 7b64aa8f2d263793c7aa4dc5e294466c48cd7b36..887f7a377d31fbb29f5b696f295c3dde07fb8daf 100644
--- a/common/observer/listenable.go
+++ b/common/observer/listenable.go
@@ -33,28 +33,32 @@ type Listenable interface {
 	RemoveAllEventListeners()
 }
 
-// BaseListenable base listenable
-type BaseListenable struct {
+// BaseListener base listenable
+type BaseListener struct {
 	Listenable
-	ListenersCache sync.Map
-	Mutex          sync.Mutex
+	ListenersCache map[reflect.Type][]EventListener
+	Mutex          sync.RWMutex
 }
 
-// NewBaseListenable a constructor of base listenable
-func NewBaseListenable() Listenable {
-	return &BaseListenable{}
+// NewBaseListener a constructor of base listenable
+func NewBaseListener() BaseListener {
+	return BaseListener{
+		ListenersCache: make(map[reflect.Type][]EventListener, 8),
+	}
 }
 
 // AddEventListener add event listener
-func (bl *BaseListenable) AddEventListener(listener EventListener) {
+func (bl *BaseListener) AddEventListener(listener EventListener) {
 	eventType := listener.GetEventType()
 	if eventType.Kind() == reflect.Ptr {
 		eventType = eventType.Elem()
 	}
 	bl.Mutex.Lock()
 	defer bl.Mutex.Unlock()
-	value, loaded := bl.ListenersCache.LoadOrStore(eventType, make([]EventListener, 0, 8))
-	listenersSlice := value.([]EventListener)
+	listenersSlice, loaded := bl.ListenersCache[eventType]
+	if !loaded {
+		listenersSlice = make([]EventListener, 0, 8)
+	}
 	// return if listenersSlice already has this listener
 	if loaded && containListener(listenersSlice, listener) {
 		return
@@ -63,59 +67,62 @@ func (bl *BaseListenable) AddEventListener(listener EventListener) {
 	sort.Slice(listenersSlice, func(i, j int) bool {
 		return listenersSlice[i].GetPriority() < listenersSlice[j].GetPriority()
 	})
-	bl.ListenersCache.Store(eventType, listenersSlice)
+	bl.ListenersCache[eventType] = listenersSlice
 }
 
 // AddEventListeners add the slice of event listener
-func (bl *BaseListenable) AddEventListeners(listenersSlice []EventListener) {
+func (bl *BaseListener) AddEventListeners(listenersSlice []EventListener) {
 	for _, listener := range listenersSlice {
 		bl.AddEventListener(listener)
 	}
 }
 
 // RemoveEventListener remove the event listener
-func (bl *BaseListenable) RemoveEventListener(listener EventListener) {
+func (bl *BaseListener) RemoveEventListener(listener EventListener) {
 	eventType := listener.GetEventType()
 	if eventType.Kind() == reflect.Ptr {
 		eventType = eventType.Elem()
 	}
 	bl.Mutex.Lock()
 	defer bl.Mutex.Unlock()
-	value, loaded := bl.ListenersCache.Load(eventType)
+	listenersSlice, loaded := bl.ListenersCache[eventType]
 	if !loaded {
 		return
 	}
-	listenersSlice := value.([]EventListener)
 	for i, l := range listenersSlice {
 		if l == listener {
 			listenersSlice = append(listenersSlice[:i], listenersSlice[i+1:]...)
 		}
 	}
-	bl.ListenersCache.Store(eventType, listenersSlice)
+	bl.ListenersCache[eventType] = listenersSlice
 }
 
 // RemoveEventListeners remove the slice of event listener
-func (bl *BaseListenable) RemoveEventListeners(listenersSlice []EventListener) {
+// it will iterate all listener and remove it one by one
+func (bl *BaseListener) RemoveEventListeners(listenersSlice []EventListener) {
 	for _, listener := range listenersSlice {
 		bl.RemoveEventListener(listener)
 	}
 }
 
 // RemoveAllEventListeners remove all
-func (bl *BaseListenable) RemoveAllEventListeners() {
+// using Lock
+func (bl *BaseListener) RemoveAllEventListeners() {
 	bl.Mutex.Lock()
 	defer bl.Mutex.Unlock()
-	bl.ListenersCache = sync.Map{}
+	bl.ListenersCache = make(map[reflect.Type][]EventListener)
 }
 
-// GetAllEventListeners get all
-func (bl *BaseListenable) GetAllEventListeners() []EventListener {
+// GetAllEventListeners get all listener
+// using RLock
+func (bl *BaseListener) GetAllEventListeners() []EventListener {
 	allListenersSlice := make([]EventListener, 0, 16)
-	bl.ListenersCache.Range(func(_, value interface{}) bool {
-		listenersSlice := value.([]EventListener)
+
+	bl.Mutex.RLock()
+	defer bl.Mutex.RUnlock()
+	for _, listenersSlice := range bl.ListenersCache {
 		allListenersSlice = append(allListenersSlice, listenersSlice...)
-		return true
-	})
+	}
 	sort.Slice(allListenersSlice, func(i, j int) bool {
 		return allListenersSlice[i].GetPriority() < allListenersSlice[j].GetPriority()
 	})
@@ -123,6 +130,8 @@ func (bl *BaseListenable) GetAllEventListeners() []EventListener {
 }
 
 // containListener true if contain listener
+// it's not thread safe
+// usually it should be use in lock scope
 func containListener(listenersSlice []EventListener, listener EventListener) bool {
 	for _, loadListener := range listenersSlice {
 		if loadListener == listener {
diff --git a/common/observer/listenable_test.go b/common/observer/listenable_test.go
index df46bfc2ba47f6e447074b44208a809949f7ae3d..5a03382a937fe925b6e17b495d066b86c8d2161d 100644
--- a/common/observer/listenable_test.go
+++ b/common/observer/listenable_test.go
@@ -28,7 +28,8 @@ import (
 
 func TestListenable(t *testing.T) {
 	el := &TestEventListener{}
-	b := &BaseListenable{}
+	bl := NewBaseListener()
+	b := &bl
 	b.AddEventListener(el)
 	b.AddEventListener(el)
 	al := b.GetAllEventListeners()
diff --git a/common/rpc_service.go b/common/rpc_service.go
index 1127e6c018204ee287ba3edfb50b30688a052dd5..6ca0e827cb21a4065468c3f180cecdaab0afb555 100644
--- a/common/rpc_service.go
+++ b/common/rpc_service.go
@@ -343,6 +343,12 @@ func suiteMethod(method reflect.Method) *MethodType {
 		argsType           []reflect.Type
 	)
 
+	// this method is in RPCService
+	// we force users must implement RPCService interface in their provider
+	// and RPCService has only one method "Reference"
+	// In general, this method should not be exported to client
+	// so we ignore this method
+	// see RPCService
 	if mname == "Reference" {
 		return nil
 	}
diff --git a/common/rpc_service_test.go b/common/rpc_service_test.go
index 19a1d7b03b48d16d9d75b649d603d5d22ee7ba56..2311205d0ec0c2fd4642a4d8639c0bf871fe1d17 100644
--- a/common/rpc_service_test.go
+++ b/common/rpc_service_test.go
@@ -137,7 +137,7 @@ func TestSuiteMethod(t *testing.T) {
 	assert.True(t, ok)
 	methodType := suiteMethod(method)
 	method = methodType.Method()
-	assert.Equal(t, "func(*event.TestService, context.Context, interface {}, interface {}, interface {}) error", method.Type.String())
+	assert.Equal(t, "func(*common.TestService, context.Context, interface {}, interface {}, interface {}) error", method.Type.String())
 	at := methodType.ArgsType()
 	assert.Equal(t, "interface {}", at[0].String())
 	assert.Equal(t, "interface {}", at[1].String())
@@ -151,7 +151,7 @@ func TestSuiteMethod(t *testing.T) {
 	assert.True(t, ok)
 	methodType = suiteMethod(method)
 	method = methodType.Method()
-	assert.Equal(t, "func(*event.TestService, interface {}, interface {}, interface {}) (interface {}, error)", method.Type.String())
+	assert.Equal(t, "func(*common.TestService, interface {}, interface {}, interface {}) (interface {}, error)", method.Type.String())
 	at = methodType.ArgsType()
 	assert.Equal(t, "interface {}", at[0].String())
 	assert.Equal(t, "interface {}", at[1].String())
@@ -164,7 +164,7 @@ func TestSuiteMethod(t *testing.T) {
 	assert.True(t, ok)
 	methodType = suiteMethod(method)
 	method = methodType.Method()
-	assert.Equal(t, "func(*event.TestService) error", method.Type.String())
+	assert.Equal(t, "func(*common.TestService) error", method.Type.String())
 	at = methodType.ArgsType()
 	assert.Equal(t, 0, len(at))
 	assert.Nil(t, methodType.CtxType())
diff --git a/common/url.go b/common/url.go
index 10bbf8ff210d61101a5f64015533cc11c44bee85..e0e15739daa926f02280dc69e70ed38f673c1ae5 100644
--- a/common/url.go
+++ b/common/url.go
@@ -36,6 +36,7 @@ import (
 
 import (
 	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
 )
 
 // ///////////////////////////////
@@ -177,7 +178,12 @@ func WithToken(token string) option {
 		if len(token) > 0 {
 			value := token
 			if strings.ToLower(token) == "true" || strings.ToLower(token) == "default" {
-				value = uuid.NewV4().String()
+				u, err := uuid.NewV4()
+				if err != nil {
+					logger.Errorf("could not generator UUID: %v", err)
+					return
+				}
+				value = u.String()
 			}
 			url.SetParam(constant.TOKEN_KEY, value)
 		}
@@ -651,16 +657,21 @@ func mergeNormalParam(mergedUrl *URL, referenceUrl *URL, paramKeys []string) []f
 	return methodConfigMergeFcn
 }
 
+// URLSlice will be used to sort URL instance
+// Instances will be order by URL.String()
 type URLSlice []URL
 
+// nolint
 func (s URLSlice) Len() int {
 	return len(s)
 }
 
+// nolint
 func (s URLSlice) Less(i, j int) bool {
 	return s[i].String() < s[j].String()
 }
 
+// nolint
 func (s URLSlice) Swap(i, j int) {
 	s[i], s[j] = s[j], s[i]
 }
diff --git a/common/url_test.go b/common/url_test.go
index 2372de520e88b0949023e88cec64871736dd6aa0..4d9dff9f373f5d2250deb577621cead8c991cf4d 100644
--- a/common/url_test.go
+++ b/common/url_test.go
@@ -118,6 +118,33 @@ func TestURL_URLEqual(t *testing.T) {
 	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))
+
+	// urlGroupAnyValue's group is *
+	urlGroupAnyValue, 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)
+	assert.True(t, u3.URLEqual(urlGroupAnyValue))
+
+	// test for enabled
+	urlEnabledEmpty, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=*&version=2.6.0&enabled=")
+	assert.NoError(t, err)
+	assert.True(t, u3.URLEqual(urlEnabledEmpty))
+
+	urlEnabledFalse, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=*&version=2.6.0&enabled=1")
+	assert.NoError(t, err)
+	assert.False(t, u3.URLEqual(urlEnabledFalse))
+
+	urlEnabledTrue, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=*&version=2.6.0&enabled=true")
+	assert.NoError(t, err)
+	assert.True(t, u3.URLEqual(urlEnabledTrue))
+
+	urlEnabledAny, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=*&version=2.6.0&enabled=*")
+	assert.NoError(t, err)
+	assert.True(t, u3.URLEqual(urlEnabledAny))
+
+	// test for category
+	categoryAny, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=*&version=2.6.0&enabled=*&category=*")
+	assert.NoError(t, err)
+	assert.True(t, categoryAny.URLEqual(u3))
 }
 
 func TestURL_GetParam(t *testing.T) {
diff --git a/config/application_config.go b/config/application_config.go
index af6637c4e08df0d7160f10881bd1fe588b95f607..ef99664fa298c28365ed7acc54d0c18a88c9b5c2 100644
--- a/config/application_config.go
+++ b/config/application_config.go
@@ -25,9 +25,9 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
-// ApplicationConfig ...
+// ApplicationConfig is a configuration for current application, whether the application is a provider or a consumer
 type ApplicationConfig struct {
-	Organization string `yaml:"organization"  json:"organization,omitempty" property:"organization"`
+	Organization string `yaml:"organization" json:"organization,omitempty" property:"organization"`
 	Name         string `yaml:"name" json:"name,omitempty" property:"name"`
 	Module       string `yaml:"module" json:"module,omitempty" property:"module"`
 	Version      string `yaml:"version" json:"version,omitempty" property:"version"`
@@ -37,22 +37,12 @@ type ApplicationConfig struct {
 	MetadataType string `default:"local" yaml:"metadataType" json:"metadataType,omitempty" property:"metadataType"`
 }
 
-// Prefix ...
+// nolint
 func (*ApplicationConfig) Prefix() string {
 	return constant.DUBBO + ".application."
 }
 
-// Id ...
-func (c *ApplicationConfig) Id() string {
-	return ""
-}
-
-// SetId ...
-func (c *ApplicationConfig) SetId(id string) {
-
-}
-
-// UnmarshalYAML ...
+// UnmarshalYAML unmarshals the ApplicationConfig by @unmarshal function
 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 f04a09f498133a84be4043aada7c5821dfe98b56..46ff5fb174b9204b00c7d7a0369615ca377fd2d4 100644
--- a/config/base_config.go
+++ b/config/base_config.go
@@ -40,14 +40,14 @@ type multiConfiger interface {
 	Prefix() string
 }
 
-// BaseConfig is the event configuration for provider and consumer
+// BaseConfig is the common configuration for provider and consumer
 type BaseConfig struct {
-	ConfigCenterConfig *ConfigCenterConfig                `yaml:"config_center" json:"config_center,omitempty"`
-	Remotes            map[string]*RemoteConfig           `yaml:"remote" json:"remote,omitempty"`
-	ServiceDiscoveries map[string]*ServiceDiscoveryConfig `yaml:"service_discovery" json:"service_discovery,omitempty"`
+	ConfigCenterConfig *ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"`
 
-	Registry   *RegistryConfig            `yaml:"registry" json:"registry,omitempty" property:"registry"`
-	Registries map[string]*RegistryConfig `yaml:"registries" json:"registries,omitempty" property:"registries"`
+	// since 1.5.0 version
+	Remotes              map[string]*RemoteConfig           `yaml:"remote" json:"remote,omitempty"`
+	ServiceDiscoveries   map[string]*ServiceDiscoveryConfig `yaml:"service_discovery" json:"service_discovery,omitempty"`
+	MetadataReportConfig *MetadataReportConfig              `yaml:"metadata_report" json:"metadata_report,omitempty" property:"metadata_report"`
 
 	// application config
 	ApplicationConfig *ApplicationConfig `yaml:"application" json:"application,omitempty" property:"application"`
@@ -60,6 +60,7 @@ type BaseConfig struct {
 	fileStream          *bytes.Buffer
 }
 
+// nolint
 func (c *BaseConfig) GetServiceDiscoveries(name string) (config *ServiceDiscoveryConfig, ok bool) {
 	config, ok = c.ServiceDiscoveries[name]
 	return
@@ -88,7 +89,6 @@ func (c *BaseConfig) startConfigCenter() error {
 }
 
 func (c *BaseConfig) prepareEnvironment() error {
-
 	factory := extension.GetConfigCenterFactory(c.ConfigCenterConfig.Protocol)
 	dynamicConfig, err := factory.GetDynamicConfiguration(c.configCenterUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(dynamicConfig)
@@ -342,7 +342,7 @@ func (c *BaseConfig) freshInternalConfig(config *config.InmemoryConfiguration) {
 	setFieldValue(val, reflect.Value{}, config)
 }
 
-// SetFatherConfig ...
+// SetFatherConfig sets father config by @fatherConfig
 func (c *BaseConfig) SetFatherConfig(fatherConfig interface{}) {
 	c.fatherConfig = fatherConfig
 }
diff --git a/config/base_config_test.go b/config/base_config_test.go
index f36d7190c379d7d190af3fd2b2314b3b4b10c3f0..ea53ca5208cd0fdee4ab2fb22f5c895a524381aa 100644
--- a/config/base_config_test.go
+++ b/config/base_config_test.go
@@ -56,6 +56,7 @@ func Test_refresh(t *testing.T) {
 				Owner:        "dubbo",
 				Environment:  "test"},
 		},
+
 		Registries: map[string]*RegistryConfig{
 			"shanghai_reg2": {
 				Protocol:   "mock",
@@ -82,6 +83,7 @@ func Test_refresh(t *testing.T) {
 				Password:   "pwd1",
 			},
 		},
+
 		References: map[string]*ReferenceConfig{
 			"MockService": {
 				InterfaceName: "com.MockService",
@@ -152,6 +154,7 @@ func Test_appExternal_refresh(t *testing.T) {
 				Owner:        "dubbo",
 				Environment:  "test"},
 		},
+
 		Registries: map[string]*RegistryConfig{
 			"shanghai_reg2": {
 				Protocol:   "mock",
@@ -240,6 +243,7 @@ func Test_appExternalWithoutId_refresh(t *testing.T) {
 				Owner:        "dubbo",
 				Environment:  "test"},
 		},
+
 		Registries: map[string]*RegistryConfig{
 			"shanghai_reg2": {
 				Protocol:   "mock",
@@ -266,6 +270,7 @@ func Test_appExternalWithoutId_refresh(t *testing.T) {
 				Password:   "pwd1",
 			},
 		},
+
 		References: map[string]*ReferenceConfig{
 			"MockService": {
 				InterfaceName: "com.MockService",
@@ -319,6 +324,7 @@ func Test_refresh_singleRegistry(t *testing.T) {
 	father := &ConsumerConfig{
 		Check: &[]bool{true}[0],
 		BaseConfig: BaseConfig{
+
 			ApplicationConfig: &ApplicationConfig{
 				Organization: "dubbo_org",
 				Name:         "dubbo",
@@ -327,8 +333,10 @@ func Test_refresh_singleRegistry(t *testing.T) {
 				Owner:        "dubbo",
 				Environment:  "test"},
 		},
+
 		Registries: map[string]*RegistryConfig{},
 		Registry:   &RegistryConfig{},
+
 		References: map[string]*ReferenceConfig{
 			"MockService": {
 				InterfaceName: "com.MockService",
@@ -392,6 +400,7 @@ func Test_refreshProvider(t *testing.T) {
 				Owner:        "dubbo",
 				Environment:  "test"},
 		},
+
 		Registries: map[string]*RegistryConfig{
 			"shanghai_reg2": {
 				Protocol:   "mock",
@@ -418,6 +427,7 @@ func Test_refreshProvider(t *testing.T) {
 				Password:   "pwd1",
 			},
 		},
+
 		Services: map[string]*ServiceConfig{
 			"MockService": {
 				InterfaceName: "com.MockService",
diff --git a/config/config_center_config.go b/config/config_center_config.go
index 40b9b6517186a8a4f7956db3d23f0a1cdfbdc8cb..c9133dc26df0b05e3bb61df0f612d0e2914e98bb 100644
--- a/config/config_center_config.go
+++ b/config/config_center_config.go
@@ -31,7 +31,13 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
-// ConfigCenterConfig ...
+// ConfigCenterConfig is configuration for config center
+//
+// ConfigCenter also introduced concepts of namespace and group to better manage Key-Value pairs by group,
+// those configs are already built-in in many professional third-party configuration centers.
+// In most cases, namespace is used to isolate different tenants, while group is used to divide the key set from one tenant into groups.
+//
+// ConfigCenter has currently supported Zookeeper, Nacos, Etcd, Consul, Apollo
 type ConfigCenterConfig struct {
 	context       context.Context
 	Protocol      string `required:"true"  yaml:"protocol"  json:"protocol,omitempty"`
@@ -40,6 +46,7 @@ type ConfigCenterConfig struct {
 	Group         string `default:"dubbo" yaml:"group" json:"group,omitempty"`
 	Username      string `yaml:"username" json:"username,omitempty"`
 	Password      string `yaml:"password" json:"password,omitempty"`
+	LogDir        string `yaml:"log_dir" json:"log_dir,omitempty"`
 	ConfigFile    string `default:"dubbo.properties" yaml:"config_file"  json:"config_file,omitempty"`
 	Namespace     string `default:"dubbo" yaml:"namespace"  json:"namespace,omitempty"`
 	AppConfigFile string `default:"dubbo.properties" yaml:"app_config_file"  json:"app_config_file,omitempty"`
@@ -48,7 +55,7 @@ type ConfigCenterConfig struct {
 	timeout       time.Duration
 }
 
-// UnmarshalYAML ...
+// UnmarshalYAML unmarshals the ConfigCenterConfig by @unmarshal function
 func (c *ConfigCenterConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
@@ -60,12 +67,13 @@ func (c *ConfigCenterConfig) UnmarshalYAML(unmarshal func(interface{}) error) er
 	return nil
 }
 
-// GetUrlMap ...
+// GetUrlMap gets url map from ConfigCenterConfig
 func (c *ConfigCenterConfig) GetUrlMap() url.Values {
 	urlMap := url.Values{}
 	urlMap.Set(constant.CONFIG_NAMESPACE_KEY, c.Namespace)
 	urlMap.Set(constant.CONFIG_GROUP_KEY, c.Group)
 	urlMap.Set(constant.CONFIG_CLUSTER_KEY, c.Cluster)
 	urlMap.Set(constant.CONFIG_APP_ID_KEY, c.AppId)
+	urlMap.Set(constant.CONFIG_LOG_DIR_KEY, c.LogDir)
 	return urlMap
 }
diff --git a/config/config_loader.go b/config/config_loader.go
index 90eb354cf53fe8009b73f67d35e0827e4b11ecbc..89a32771dc09c963ba2270eb9b42eba61c815036 100644
--- a/config/config_loader.go
+++ b/config/config_loader.go
@@ -42,10 +42,8 @@ var (
 	providerConfig *ProviderConfig
 	// baseConfig = providerConfig.BaseConfig or consumerConfig
 	baseConfig *BaseConfig
-	// baseConfigOnce is used to make sure that we only create it once.
-	baseConfigOnce sync.Once
 
-	// configAccessMutex is used to make sure that BaseConfig.xxxxConfig will only be created once if needed.
+	// configAccessMutex is used to make sure that xxxxConfig will only be created once if needed.
 	// it should be used combine with double-check to avoid the race condition
 	configAccessMutex sync.Mutex
 
@@ -69,6 +67,8 @@ func init() {
 		log.Printf("[consumerInit] %#v", errCon)
 		consumerConfig = nil
 	} else {
+		// Even though baseConfig has been initialized, we override it
+		// because we think read from config file is correct config
 		baseConfig = &consumerConfig.BaseConfig
 	}
 
@@ -76,6 +76,8 @@ func init() {
 		log.Printf("[providerInit] %#v", errPro)
 		providerConfig = nil
 	} else {
+		// Even though baseConfig has been initialized, we override it
+		// because we think read from config file is correct config
 		baseConfig = &providerConfig.BaseConfig
 	}
 }
@@ -219,11 +221,11 @@ func Load() {
 	// init router
 	initRouter()
 
-	// event part
+	// init the global event dispatcher
 	extension.SetAndInitGlobalDispatcher(GetBaseConfig().EventDispatcherType)
 
 	// start the metadata report if config set
-	if err := startMetadataReport(GetApplicationConfig().MetadataType, GetProviderConfig().MetadataReportConfig); err != nil {
+	if err := startMetadataReport(GetApplicationConfig().MetadataType, GetBaseConfig().MetadataReportConfig); err != nil {
 		logger.Errorf("Provider starts metadata report error, and the error is {%#v}", err)
 		return
 	}
@@ -285,7 +287,6 @@ func GetApplicationConfig() *ApplicationConfig {
 // if not found, create new one
 func GetProviderConfig() ProviderConfig {
 	if providerConfig == nil {
-		logger.Warnf("providerConfig is nil! we will try to create one")
 		if providerConfig == nil {
 			return ProviderConfig{}
 		}
@@ -308,9 +309,10 @@ func GetConsumerConfig() ConsumerConfig {
 }
 
 func GetBaseConfig() *BaseConfig {
-
 	if baseConfig == nil {
-		baseConfigOnce.Do(func() {
+		configAccessMutex.Lock()
+		defer configAccessMutex.Unlock()
+		if baseConfig == nil {
 			baseConfig = &BaseConfig{
 				MetricConfig:       &MetricConfig{},
 				ConfigCenterConfig: &ConfigCenterConfig{},
@@ -318,7 +320,7 @@ func GetBaseConfig() *BaseConfig {
 				ApplicationConfig:  &ApplicationConfig{},
 				ServiceDiscoveries: make(map[string]*ServiceDiscoveryConfig, 0),
 			}
-		})
+		}
 	}
 	return baseConfig
 }
diff --git a/config/config_loader_test.go b/config/config_loader_test.go
index f653f5e7598756514fd1e50dd2077329cbb3c9c0..a239621dd0e43fb940e6e94ea87df62b9123cd26 100644
--- a/config/config_loader_test.go
+++ b/config/config_loader_test.go
@@ -254,12 +254,14 @@ func mockInitProviderWithSingleRegistry() {
 				Owner:        "dubbo",
 				Environment:  "test"},
 		},
+
 		Registry: &RegistryConfig{
 			Address:  "mock://127.0.0.1:2181",
 			Username: "user1",
 			Password: "pwd1",
 		},
 		Registries: map[string]*RegistryConfig{},
+
 		Services: map[string]*ServiceConfig{
 			"MockService": {
 				InterfaceName: "com.MockService",
diff --git a/config/consumer_config.go b/config/consumer_config.go
index fd3d30e6fca2d537da47cce79134e749060f511e..f8b671bf3cf8304d57211f2f8b7c7c35f2aa6b9e 100644
--- a/config/consumer_config.go
+++ b/config/consumer_config.go
@@ -38,7 +38,7 @@ import (
 // consumerConfig
 /////////////////////////
 
-// ConsumerConfig ...
+// ConsumerConfig is Consumer default configuration
 type ConsumerConfig struct {
 	BaseConfig `yaml:",inline"`
 	Filter     string `yaml:"filter" json:"filter,omitempty" property:"filter"`
@@ -46,6 +46,9 @@ type ConsumerConfig struct {
 	Connect_Timeout string `default:"100ms"  yaml:"connect_timeout" json:"connect_timeout,omitempty" property:"connect_timeout"`
 	ConnectTimeout  time.Duration
 
+	Registry   *RegistryConfig            `yaml:"registry" json:"registry,omitempty" property:"registry"`
+	Registries map[string]*RegistryConfig `yaml:"registries" json:"registries,omitempty" property:"registries"`
+
 	Request_Timeout string `yaml:"request_timeout" default:"5s" json:"request_timeout,omitempty" property:"request_timeout"`
 	RequestTimeout  time.Duration
 	ProxyFactory    string `yaml:"proxy_factory" default:"default" json:"proxy_factory,omitempty" property:"proxy_factory"`
@@ -58,7 +61,7 @@ type ConsumerConfig struct {
 	ConfigType     map[string]string           `yaml:"config_type" json:"config_type,omitempty" property:"config_type"`
 }
 
-// UnmarshalYAML ...
+// UnmarshalYAML unmarshals the ConsumerConfig by @unmarshal function
 func (c *ConsumerConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
@@ -70,17 +73,17 @@ func (c *ConsumerConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
 	return nil
 }
 
-// Prefix ...
+// nolint
 func (*ConsumerConfig) Prefix() string {
 	return constant.ConsumerConfigPrefix
 }
 
-// SetConsumerConfig ...
+// SetConsumerConfig sets consumerConfig by @c
 func SetConsumerConfig(c ConsumerConfig) {
 	consumerConfig = &c
 }
 
-// ConsumerInit ...
+// ConsumerInit loads config file to init consumer config
 func ConsumerInit(confConFile string) error {
 	if confConFile == "" {
 		return perrors.Errorf("application configure(consumer) file name is nil")
diff --git a/config/generic_service.go b/config/generic_service.go
index b66e399f9e5f467e51c8eccf465f926ac44299d5..a3332afe04de1c9b32db42d18ed2590e4188be35 100644
--- a/config/generic_service.go
+++ b/config/generic_service.go
@@ -19,18 +19,18 @@ package config
 
 import "context"
 
-// GenericService ...
+// GenericService uses for generic invoke for service call
 type GenericService struct {
 	Invoke       func(ctx context.Context, req []interface{}) (interface{}, error) `dubbo:"$invoke"`
 	referenceStr string
 }
 
-// NewGenericService ...
+// NewGenericService returns a GenericService instance
 func NewGenericService(referenceStr string) *GenericService {
 	return &GenericService{referenceStr: referenceStr}
 }
 
-// Reference ...
+// Reference gets referenceStr from GenericService
 func (u *GenericService) Reference() string {
 	return u.referenceStr
 }
diff --git a/config/graceful_shutdown.go b/config/graceful_shutdown.go
index 382f05c8d57c4363108873433fd03565d03b9a50..aa102f35e9048dbc6fbcb10db19cb802b2f3147b 100644
--- a/config/graceful_shutdown.go
+++ b/config/graceful_shutdown.go
@@ -52,7 +52,7 @@ import (
  * We define them by using 'package build' feature https://golang.org/pkg/go/build/
  */
 
-// GracefulShutdownInit ...
+// nolint
 func GracefulShutdownInit() {
 
 	signals := make(chan os.Signal, 1)
@@ -83,7 +83,7 @@ func GracefulShutdownInit() {
 	}()
 }
 
-// BeforeShutdown ...
+// BeforeShutdown provides processing flow before shutdown
 func BeforeShutdown() {
 
 	destroyAllRegistries()
@@ -126,10 +126,8 @@ func destroyConsumerProtocols(consumerProtocols *gxset.HashSet) {
 	}
 }
 
-/**
- * destroy the provider's protocol.
- * if the protocol is consumer's protocol too, we will keep it.
- */
+// destroyProviderProtocols destroys the provider's protocol.
+// if the protocol is consumer's protocol too, we will keep it
 func destroyProviderProtocols(consumerProtocols *gxset.HashSet) {
 
 	logger.Info("Graceful shutdown --- Destroy provider's protocols. ")
@@ -215,9 +213,7 @@ func totalTimeout() time.Duration {
 	return timeout
 }
 
-/*
- * we can not get the protocols from consumerConfig because some protocol don't have configuration, like jsonrpc.
- */
+// we can not get the protocols from consumerConfig because some protocol don't have configuration, like jsonrpc.
 func getConsumerProtocols() *gxset.HashSet {
 	result := gxset.NewSet()
 	if consumerConfig == nil || consumerConfig.References == nil {
diff --git a/config/graceful_shutdown_config.go b/config/graceful_shutdown_config.go
index 6bbabebf2538effcbbe4bddc50857acf5f962a61..87175166b7011e27985eac404819a1aba3522e49 100644
--- a/config/graceful_shutdown_config.go
+++ b/config/graceful_shutdown_config.go
@@ -31,7 +31,7 @@ const (
 	defaultStepTimeout = 10 * time.Second
 )
 
-// ShutdownConfig ...
+// ShutdownConfig is used as configuration for graceful shutdown
 type ShutdownConfig struct {
 	/*
 	 * Total timeout. Even though we don't release all resources,
@@ -58,12 +58,12 @@ type ShutdownConfig struct {
 	RequestsFinished bool
 }
 
-// Prefix ...
+// nolint
 func (config *ShutdownConfig) Prefix() string {
 	return constant.ShutdownConfigPrefix
 }
 
-// GetTimeout ...
+// nolint
 func (config *ShutdownConfig) GetTimeout() time.Duration {
 	result, err := time.ParseDuration(config.Timeout)
 	if err != nil {
@@ -74,7 +74,7 @@ func (config *ShutdownConfig) GetTimeout() time.Duration {
 	return result
 }
 
-// GetStepTimeout ...
+// nolint
 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 8ad79ffa62ceed4096c60bfb9139b7ff1586808e..6f1fa982a30125096c553e65c13bae1a413ea141 100644
--- a/config/graceful_shutdown_signal_darwin.go
+++ b/config/graceful_shutdown_signal_darwin.go
@@ -23,12 +23,12 @@ import (
 )
 
 var (
-	// ShutdownSignals ...
+	// ShutdownSignals receives shutdown signals to process
 	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}
 
-	// DumpHeapShutdownSignals ...
+	// DumpHeapShutdownSignals receives shutdown signals to process
 	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 8ad79ffa62ceed4096c60bfb9139b7ff1586808e..6f1fa982a30125096c553e65c13bae1a413ea141 100644
--- a/config/graceful_shutdown_signal_linux.go
+++ b/config/graceful_shutdown_signal_linux.go
@@ -23,12 +23,12 @@ import (
 )
 
 var (
-	// ShutdownSignals ...
+	// ShutdownSignals receives shutdown signals to process
 	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}
 
-	// DumpHeapShutdownSignals ...
+	// DumpHeapShutdownSignals receives shutdown signals to process
 	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 815a05ecb20a8fc202debaf6f39d699845cd689e..3136e5ae15081f026e8a6e602a5174e1d396abf7 100644
--- a/config/graceful_shutdown_signal_windows.go
+++ b/config/graceful_shutdown_signal_windows.go
@@ -23,11 +23,11 @@ import (
 )
 
 var (
-	// ShutdownSignals ...
+	// ShutdownSignals receives shutdown signals to process
 	ShutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL,
 		syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
 		syscall.SIGABRT}
 
-	// DumpHeapShutdownSignals ...
+	// DumpHeapShutdownSignals receives shutdown signals to process
 	DumpHeapShutdownSignals = []os.Signal{syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP, syscall.SIGABRT}
 )
diff --git a/config/instance/metedata_report.go b/config/instance/metadata_report.go
similarity index 100%
rename from config/instance/metedata_report.go
rename to config/instance/metadata_report.go
diff --git a/config/instance/metadata_report_test.go b/config/instance/metadata_report_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..51780a53f6d7e80e5c7d7a15917aee629b000e1c
--- /dev/null
+++ b/config/instance/metadata_report_test.go
@@ -0,0 +1,85 @@
+/*
+ * 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 instance
+
+import (
+	"testing"
+)
+
+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/metadata/identifier"
+	"github.com/apache/dubbo-go/metadata/report"
+	"github.com/apache/dubbo-go/metadata/report/factory"
+)
+
+func TestGetMetadataReportInstance(t *testing.T) {
+	extension.SetMetadataReportFactory("mock", func() factory.MetadataReportFactory {
+		return &mockMetadataReportFactory{}
+	})
+	u, _ := common.NewURL("mock://127.0.0.1")
+	rpt := GetMetadataReportInstance(&u)
+	assert.NotNil(t, rpt)
+}
+
+type mockMetadataReportFactory struct {
+}
+
+func (m *mockMetadataReportFactory) CreateMetadataReport(*common.URL) report.MetadataReport {
+	return &mockMetadataReport{}
+}
+
+type mockMetadataReport struct {
+}
+
+func (m mockMetadataReport) StoreProviderMetadata(*identifier.MetadataIdentifier, string) error {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) StoreConsumerMetadata(*identifier.MetadataIdentifier, string) error {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) SaveServiceMetadata(*identifier.ServiceMetadataIdentifier, common.URL) error {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) RemoveServiceMetadata(*identifier.ServiceMetadataIdentifier) error {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) GetExportedURLs(*identifier.ServiceMetadataIdentifier) []string {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) SaveSubscribedData(*identifier.SubscriberMetadataIdentifier, []common.URL) error {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) GetSubscribedURLs(*identifier.SubscriberMetadataIdentifier) []string {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) GetServiceDefinition(*identifier.MetadataIdentifier) string {
+	panic("implement me")
+}
diff --git a/config/interfaces/config_reader.go b/config/interfaces/config_reader.go
index 8b79a17d8903ffe888204875c12feed669cb2f9b..b23f989cc29b42de349d1d80ae594de32ab4abbd 100644
--- a/config/interfaces/config_reader.go
+++ b/config/interfaces/config_reader.go
@@ -19,7 +19,7 @@ package interfaces
 
 import "bytes"
 
-// ConfigReader
+// ConfigReader is used to read config from consumer or provider
 type ConfigReader interface {
 	ReadConsumerConfig(reader *bytes.Buffer) error
 	ReadProviderConfig(reader *bytes.Buffer) error
diff --git a/config/metadata_report_config.go b/config/metadata_report_config.go
index 9999371ab887fbf7d3c5857aea02b1dd4faad2da..6d319e5ecb8007e06dcf790fff145bfab754df3d 100644
--- a/config/metadata_report_config.go
+++ b/config/metadata_report_config.go
@@ -32,7 +32,7 @@ import (
 	"github.com/apache/dubbo-go/config/instance"
 )
 
-// MethodConfig ...
+// MethodConfig is method level configuration
 type MetadataReportConfig struct {
 	Protocol  string            `required:"true"  yaml:"protocol"  json:"protocol,omitempty"`
 	RemoteRef string            `required:"true"  yaml:"remote_ref"  json:"remote_ref,omitempty"`
@@ -40,12 +40,12 @@ type MetadataReportConfig struct {
 	Group     string            `yaml:"group" json:"group,omitempty" property:"group"`
 }
 
-// Prefix ...
+// nolint
 func (c *MetadataReportConfig) Prefix() string {
 	return constant.MetadataReportPrefix
 }
 
-// UnmarshalYAML ...
+// UnmarshalYAML unmarshal the MetadataReportConfig by @unmarshal function
 func (c *MetadataReportConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return perrors.WithStack(err)
@@ -57,7 +57,7 @@ func (c *MetadataReportConfig) UnmarshalYAML(unmarshal func(interface{}) error)
 	return nil
 }
 
-// ToUrl ...
+// nolint
 func (c *MetadataReportConfig) ToUrl() (*common.URL, error) {
 	urlMap := make(url.Values)
 
diff --git a/config/method_config.go b/config/method_config.go
index 8f196d9e2c03071a663db03cb185fb9106d6484a..e64773eb135b2f9ec55377bded815147e2e192af 100644
--- a/config/method_config.go
+++ b/config/method_config.go
@@ -42,7 +42,7 @@ type MethodConfig struct {
 	RequestTimeout              string `yaml:"timeout"  json:"timeout,omitempty" property:"timeout"`
 }
 
-// Prefix ...
+// nolint
 func (c *MethodConfig) Prefix() string {
 	if len(c.InterfaceId) != 0 {
 		return constant.DUBBO + "." + c.InterfaceName + "." + c.InterfaceId + "." + c.Name + "."
@@ -51,7 +51,7 @@ func (c *MethodConfig) Prefix() string {
 	return constant.DUBBO + "." + c.InterfaceName + "." + c.Name + "."
 }
 
-// UnmarshalYAML ...
+// UnmarshalYAML unmarshals the MethodConfig by @unmarshal function
 func (c *MethodConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
diff --git a/config/mock_rpcservice.go b/config/mock_rpcservice.go
index 6c43699128247bf0ec483eb83f879bf4c3b67a37..1e21b252f5cf094c3bd103e3624fbcb2e2b1e2b1 100644
--- a/config/mock_rpcservice.go
+++ b/config/mock_rpcservice.go
@@ -21,20 +21,20 @@ import (
 	"context"
 )
 
-// MockService ...
+// MockService mocks the rpc service for test
 type MockService struct{}
 
-// Reference ...
+// Reference mocks the Reference method
 func (*MockService) Reference() string {
 	return "MockService"
 }
 
-// GetUser ...
+// GetUser mocks the GetUser method
 func (*MockService) GetUser(ctx context.Context, itf []interface{}, str *struct{}) error {
 	return nil
 }
 
-// GetUser1 ...
+// GetUser1 mocks the GetUser1 method
 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 33de976bc6f5bf7341ddcff8d51c505cf23bbccd..cee5b7aa7518ff55a15d05de4733cefbbc9c0a1c 100644
--- a/config/protocol_config.go
+++ b/config/protocol_config.go
@@ -25,14 +25,14 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
-// ProtocolConfig ...
+// ProtocolConfig is protocol configuration
 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 ...
+// nolint
 func (c *ProtocolConfig) Prefix() string {
 	return constant.ProtocolConfigPrefix
 }
diff --git a/config/provider_config.go b/config/provider_config.go
index 99c532a383ad75285edc7e7200f6edbeac936f9d..9d8a2429d2fc1d88b01c436ae96d55bcd1c729aa 100644
--- a/config/provider_config.go
+++ b/config/provider_config.go
@@ -35,22 +35,23 @@ import (
 // providerConfig
 /////////////////////////
 
-// ProviderConfig ...
+// ProviderConfig is the default configuration of service provider
 type ProviderConfig struct {
-	BaseConfig   `yaml:",inline"`
-	Filter       string `yaml:"filter" json:"filter,omitempty" property:"filter"`
-	ProxyFactory string `yaml:"proxy_factory" default:"default" json:"proxy_factory,omitempty" property:"proxy_factory"`
-	// metadata-report
-	MetadataReportConfig *MetadataReportConfig      `yaml:"metadata_report" json:"metadata_report,omitempty" property:"metadata_report"`
-	Services             map[string]*ServiceConfig  `yaml:"services" json:"services,omitempty" property:"services"`
-	Protocols            map[string]*ProtocolConfig `yaml:"protocols" json:"protocols,omitempty" property:"protocols"`
-	ProtocolConf         interface{}                `yaml:"protocol_conf" json:"protocol_conf,omitempty" property:"protocol_conf" `
-	FilterConf           interface{}                `yaml:"filter_conf" json:"filter_conf,omitempty" property:"filter_conf" `
-	ShutdownConfig       *ShutdownConfig            `yaml:"shutdown_conf" json:"shutdown_conf,omitempty" property:"shutdown_conf" `
-	ConfigType           map[string]string          `yaml:"config_type" json:"config_type,omitempty" property:"config_type"`
+	BaseConfig     `yaml:",inline"`
+	Filter         string                     `yaml:"filter" json:"filter,omitempty" property:"filter"`
+	ProxyFactory   string                     `yaml:"proxy_factory" default:"default" json:"proxy_factory,omitempty" property:"proxy_factory"`
+	Services       map[string]*ServiceConfig  `yaml:"services" json:"services,omitempty" property:"services"`
+	Protocols      map[string]*ProtocolConfig `yaml:"protocols" json:"protocols,omitempty" property:"protocols"`
+	ProtocolConf   interface{}                `yaml:"protocol_conf" json:"protocol_conf,omitempty" property:"protocol_conf" `
+	FilterConf     interface{}                `yaml:"filter_conf" json:"filter_conf,omitempty" property:"filter_conf" `
+	ShutdownConfig *ShutdownConfig            `yaml:"shutdown_conf" json:"shutdown_conf,omitempty" property:"shutdown_conf" `
+	ConfigType     map[string]string          `yaml:"config_type" json:"config_type,omitempty" property:"config_type"`
+
+	Registry   *RegistryConfig            `yaml:"registry" json:"registry,omitempty" property:"registry"`
+	Registries map[string]*RegistryConfig `yaml:"registries" json:"registries,omitempty" property:"registries"`
 }
 
-// UnmarshalYAML ...
+// UnmarshalYAML unmarshals the ProviderConfig by @unmarshal function
 func (c *ProviderConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
@@ -62,17 +63,17 @@ func (c *ProviderConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
 	return nil
 }
 
-// Prefix ...
+// nolint
 func (*ProviderConfig) Prefix() string {
 	return constant.ProviderConfigPrefix
 }
 
-// SetProviderConfig ...
+// SetProviderConfig sets provider config by @p
 func SetProviderConfig(p ProviderConfig) {
 	providerConfig = &p
 }
 
-// ProviderInit ...
+// ProviderInit loads config file to init provider config
 func ProviderInit(confProFile string) error {
 	if len(confProFile) == 0 {
 		return perrors.Errorf("application configure(provider) file name is nil")
diff --git a/config/reference_config.go b/config/reference_config.go
index e935c7646d7ba9d7a75fed3bed68c88ed7ed104d..748b2d403fe315f879c817c4e0a4cf3197d807da 100644
--- a/config/reference_config.go
+++ b/config/reference_config.go
@@ -39,7 +39,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// ReferenceConfig ...
+// ReferenceConfig is the configuration of service consumer
 type ReferenceConfig struct {
 	context        context.Context
 	pxy            *proxy.Proxy
@@ -67,7 +67,7 @@ type ReferenceConfig struct {
 	ForceTag       bool   `yaml:"force.tag"  json:"force.tag,omitempty" property:"force.tag"`
 }
 
-// Prefix ...
+// nolint
 func (c *ReferenceConfig) Prefix() string {
 	return constant.ReferenceConfigPrefix + c.InterfaceName + "."
 }
@@ -77,7 +77,7 @@ func NewReferenceConfig(id string, ctx context.Context) *ReferenceConfig {
 	return &ReferenceConfig{id: id, context: ctx}
 }
 
-// UnmarshalYAML ...
+// UnmarshalYAML unmarshals the ReferenceConfig by @unmarshal function
 func (c *ReferenceConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	type rf ReferenceConfig
 	raw := rf{} // Put your defaults here
@@ -171,7 +171,7 @@ func (c *ReferenceConfig) Implement(v common.RPCService) {
 	c.pxy.Implement(v)
 }
 
-// GetRPCService ...
+// GetRPCService gets RPCService from proxy
 func (c *ReferenceConfig) GetRPCService() common.RPCService {
 	return c.pxy.Get()
 }
diff --git a/config/reference_config_test.go b/config/reference_config_test.go
index faaa461a75a5c887f6fa1cc568d7e809c42a6ac4..05b386f75e2b1fc062783e1de224a49329fda1fb 100644
--- a/config/reference_config_test.go
+++ b/config/reference_config_test.go
@@ -47,6 +47,7 @@ func doInitConsumer() {
 				Owner:        "dubbo",
 				Environment:  "test"},
 		},
+
 		Registries: map[string]*RegistryConfig{
 			"shanghai_reg1": {
 				Protocol:   "mock",
@@ -81,6 +82,7 @@ func doInitConsumer() {
 				Password:   "pwd1",
 			},
 		},
+
 		References: map[string]*ReferenceConfig{
 			"MockService": {
 				id: "MockProvider",
@@ -146,12 +148,14 @@ func doInitConsumerWithSingleRegistry() {
 				Owner:        "dubbo",
 				Environment:  "test"},
 		},
+
 		Registry: &RegistryConfig{
 			Address:  "mock://27.0.0.1:2181",
 			Username: "user1",
 			Password: "pwd1",
 		},
 		Registries: map[string]*RegistryConfig{},
+
 		References: map[string]*ReferenceConfig{
 			"MockService": {
 				Params: map[string]string{
diff --git a/config/registry_config.go b/config/registry_config.go
index e877a2c19dd0c4dabdce9f7ee65c2404b82d615e..ef527c827e9dac4cd2762f579d30254e9e51150f 100644
--- a/config/registry_config.go
+++ b/config/registry_config.go
@@ -33,7 +33,7 @@ import (
 	"github.com/apache/dubbo-go/common/logger"
 )
 
-// RegistryConfig ...
+// RegistryConfig is the configuration of the registry center
 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
@@ -47,7 +47,7 @@ type RegistryConfig struct {
 	Params     map[string]string `yaml:"params" json:"params,omitempty" property:"params"`
 }
 
-// UnmarshalYAML ...
+// UnmarshalYAML unmarshals the RegistryConfig by @unmarshal function
 func (c *RegistryConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
@@ -59,7 +59,7 @@ func (c *RegistryConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
 	return nil
 }
 
-// Prefix ...
+// nolint
 func (*RegistryConfig) Prefix() string {
 	return constant.RegistryConfigPrefix + "|" + constant.SingleRegistryConfigPrefix
 }
diff --git a/config/remote_config.go b/config/remote_config.go
index 4d17cc1c41c8033d550be7b2f0159485eabcec62..5e0330c571715d99e63688ee944c61f8e48117bb 100644
--- a/config/remote_config.go
+++ b/config/remote_config.go
@@ -19,10 +19,16 @@ package config
 
 import (
 	"time"
+)
 
+import (
 	"github.com/apache/dubbo-go/common/logger"
 )
 
+// RemoteConfig: usually we need some middleware, including nacos, zookeeper
+// this represents an instance of this middleware
+// so that other module, like config center, registry could reuse the config
+// but now, only metadata report, metadata service, service discovery use this structure
 type RemoteConfig struct {
 	Address    string            `yaml:"address" json:"address,omitempty"`
 	TimeoutStr string            `default:"5s" yaml:"timeout" json:"timeout,omitempty"`
@@ -31,6 +37,8 @@ type RemoteConfig struct {
 	Params     map[string]string `yaml:"params" json:"address,omitempty"`
 }
 
+// Timeout return timeout duration.
+// if the configure is invalid, or missing, the default value 5s will be returned
 func (rc *RemoteConfig) Timeout() time.Duration {
 	if res, err := time.ParseDuration(rc.TimeoutStr); err == nil {
 		return res
diff --git a/config/remote_config_test.go b/config/remote_config_test.go
index 99facb7dda98ba46ac7b5a6f86de070de8ca3d78..82535fd60b932aecb7c6c3ee8206130fad9e7161 100644
--- a/config/remote_config_test.go
+++ b/config/remote_config_test.go
@@ -19,7 +19,8 @@ package config
 
 import (
 	"testing"
-
+)
+import (
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/config/service.go b/config/service.go
index b7e7dc2a425b42363d570fc37a70e2e5094e7d9d..b746141dd0d55f8e306d9f4d13de2b9021c70272 100644
--- a/config/service.go
+++ b/config/service.go
@@ -36,17 +36,17 @@ func SetProviderService(service common.RPCService) {
 	proServices[service.Reference()] = service
 }
 
-// GetConsumerService ...
+// GetConsumerService gets ConsumerService by @name
 func GetConsumerService(name string) common.RPCService {
 	return conServices[name]
 }
 
-// GetProviderService ...
+// GetProviderService gets ProviderService by @name
 func GetProviderService(name string) common.RPCService {
 	return proServices[name]
 }
 
-// GetCallback ...
+// GetCallback gets CallbackResponse by @name
 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 43c53bc9c2b596a9270c2e1e0c0ccfa71bb15ee4..57fce028fa59893979fc6f50671fe8681770a2b8 100644
--- a/config/service_config.go
+++ b/config/service_config.go
@@ -44,9 +44,7 @@ import (
 	"github.com/apache/dubbo-go/protocol/protocolwrapper"
 )
 
-// ServiceConfig is a newest structure to support Dubbo 2.7.5
-// But I think it's not very necessary,
-// we should think about how to reuse current ProviderConfig rather than use this
+// ServiceConfig is the configuration of the service provider
 type ServiceConfig struct {
 	context                     context.Context
 	id                          string
@@ -86,12 +84,12 @@ type ServiceConfig struct {
 	exporters     []protocol.Exporter
 }
 
-// Prefix ...
+// Prefix returns dubbo.service.${interface}.
 func (c *ServiceConfig) Prefix() string {
 	return constant.ServiceConfigPrefix + c.InterfaceName + "."
 }
 
-// UnmarshalYAML ...
+// UnmarshalYAML unmarshals the ServiceConfig by @unmarshal function
 func (c *ServiceConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := defaults.Set(c); err != nil {
 		return err
@@ -143,7 +141,7 @@ func getRandomPort(protocolConfigs []*ProtocolConfig) *list.List {
 	return ports
 }
 
-// Export ...
+// Export exports the service
 func (c *ServiceConfig) Export() error {
 	// TODO: config center start here
 
@@ -251,7 +249,7 @@ func (c *ServiceConfig) Unexport() {
 	c.unexported.Store(true)
 }
 
-// Implement ...
+// Implement only store the @s and return
 func (c *ServiceConfig) Implement(s common.RPCService) {
 	c.rpcService = s
 }
diff --git a/config/service_config_test.go b/config/service_config_test.go
index 949566f82a30e92c049dcf7b4063e26397df0a3c..7630d5845e6770ec269bb2e07876bc7ba0d18329 100644
--- a/config/service_config_test.go
+++ b/config/service_config_test.go
@@ -42,40 +42,6 @@ func doInitProvider() {
 				Owner:        "dubbo",
 				Environment:  "test"},
 		},
-		Registries: map[string]*RegistryConfig{
-			"shanghai_reg1": {
-				Protocol:   "mock",
-				TimeoutStr: "2s",
-				Group:      "shanghai_idc",
-				Address:    "127.0.0.1:2181",
-				Username:   "user1",
-				Password:   "pwd1",
-			},
-			"shanghai_reg2": {
-				Protocol:   "mock",
-				TimeoutStr: "2s",
-				Group:      "shanghai_idc",
-				Address:    "127.0.0.2:2181",
-				Username:   "user1",
-				Password:   "pwd1",
-			},
-			"hangzhou_reg1": {
-				Protocol:   "mock",
-				TimeoutStr: "2s",
-				Group:      "hangzhou_idc",
-				Address:    "127.0.0.3:2181",
-				Username:   "user1",
-				Password:   "pwd1",
-			},
-			"hangzhou_reg2": {
-				Protocol:   "mock",
-				TimeoutStr: "2s",
-				Group:      "hangzhou_idc",
-				Address:    "127.0.0.4:2181",
-				Username:   "user1",
-				Password:   "pwd1",
-			},
-		},
 		Services: map[string]*ServiceConfig{
 			"MockService": {
 				InterfaceName: "com.MockService",
@@ -128,6 +94,42 @@ func doInitProvider() {
 				exported: new(atomic.Bool),
 			},
 		},
+
+		Registries: map[string]*RegistryConfig{
+			"shanghai_reg1": {
+				Protocol:   "mock",
+				TimeoutStr: "2s",
+				Group:      "shanghai_idc",
+				Address:    "127.0.0.1:2181",
+				Username:   "user1",
+				Password:   "pwd1",
+			},
+			"shanghai_reg2": {
+				Protocol:   "mock",
+				TimeoutStr: "2s",
+				Group:      "shanghai_idc",
+				Address:    "127.0.0.2:2181",
+				Username:   "user1",
+				Password:   "pwd1",
+			},
+			"hangzhou_reg1": {
+				Protocol:   "mock",
+				TimeoutStr: "2s",
+				Group:      "hangzhou_idc",
+				Address:    "127.0.0.3:2181",
+				Username:   "user1",
+				Password:   "pwd1",
+			},
+			"hangzhou_reg2": {
+				Protocol:   "mock",
+				TimeoutStr: "2s",
+				Group:      "hangzhou_idc",
+				Address:    "127.0.0.4:2181",
+				Username:   "user1",
+				Password:   "pwd1",
+			},
+		},
+
 		Protocols: map[string]*ProtocolConfig{
 			"mock": {
 				Name: "mock",
diff --git a/config_center/configuration_listener.go b/config_center/configuration_listener.go
index 541cc09286bb83fa5b66db3745e45ad0a9df5e2f..97fd9c70923f5c921ce2ca2b4028a71ea2b49e27 100644
--- a/config_center/configuration_listener.go
+++ b/config_center/configuration_listener.go
@@ -27,6 +27,7 @@ import (
 
 // ConfigurationListener for changing listener's event
 type ConfigurationListener interface {
+	// Process the notification event once there's any change happens on the config
 	Process(*ConfigChangeEvent)
 }
 
diff --git a/config_center/dynamic_configuration_test.go b/config_center/dynamic_configuration_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8b5a8d7cc5afea8559d563f82f5b2dd80c51488e
--- /dev/null
+++ b/config_center/dynamic_configuration_test.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 config_center
+
+import (
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+)
+
+func TestWithTimeout(t *testing.T) {
+	fa := WithTimeout(12 * time.Second)
+	opt := &Options{}
+	fa(opt)
+	assert.Equal(t, 12*time.Second, opt.Timeout)
+}
+
+func TestGetRuleKey(t *testing.T) {
+	url, err := common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider?interface=test&group=groupA&version=0")
+	assert.NoError(t, err)
+	assert.Equal(t, "test:0:groupA", GetRuleKey(url))
+}
diff --git a/config_center/nacos/client.go b/config_center/nacos/client.go
index d3373e249bf99873dd3aa05b7488b0e7f38730ec..3b432819f43327888ade3da5303e445d6a2ef0fe 100644
--- a/config_center/nacos/client.go
+++ b/config_center/nacos/client.go
@@ -18,6 +18,7 @@
 package nacos
 
 import (
+	"path/filepath"
 	"strconv"
 	"strings"
 	"sync"
@@ -36,7 +37,8 @@ import (
 	"github.com/apache/dubbo-go/common/logger"
 )
 
-const logDir = "logs/nacos/log"
+// Nacos Log dir, it can be override when creating client by config_center.log_dir
+var logDir = filepath.Join("logs", "nacos", "log")
 
 // NacosClient Nacos client
 type NacosClient struct {
@@ -87,6 +89,7 @@ func ValidateNacosClient(container nacosClientFacade, opts ...option) error {
 	}
 
 	url := container.GetUrl()
+	logDir = url.GetParam(constant.CONFIG_LOG_DIR_KEY, logDir)
 
 	if container.NacosClient() == nil {
 		//in dubbo ,every registry only connect one node ,so this is []string{r.Address}
diff --git a/config_center/nacos/client_test.go b/config_center/nacos/client_test.go
index ef63eeff6ddf4e5cd6fa2ba7da7996b3dbed94ac..d5e351e2bbf7d78301926c8394d07183f18bb678 100644
--- a/config_center/nacos/client_test.go
+++ b/config_center/nacos/client_test.go
@@ -53,3 +53,62 @@ func Test_newNacosClient(t *testing.T) {
 	<-c.client.Done()
 	c.Destroy()
 }
+
+func Test_setNacosClient(t *testing.T) {
+	server := mockCommonNacosServer()
+	nacosURL := server.Listener.Addr().String()
+	registryUrl, _ := common.NewURL(nacosURL)
+	c := &nacosDynamicConfiguration{
+		url:  &registryUrl,
+		done: make(chan struct{}),
+	}
+	var client *NacosClient
+	client = &NacosClient{
+		name:       nacosClientName,
+		NacosAddrs: []string{nacosURL},
+		Timeout:    15 * time.Second,
+		exit:       make(chan struct{}),
+		onceClose: func() {
+			close(client.exit)
+		},
+	}
+	c.SetNacosClient(client)
+	err := ValidateNacosClient(c, WithNacosName(nacosClientName))
+	assert.NoError(t, err)
+	c.wg.Add(1)
+	go HandleClientRestart(c)
+	go func() {
+		// c.client.Close() and <-c.client.Done() have order requirements.
+		// If c.client.Close() is called first.It is possible that "go HandleClientRestart(c)"
+		// sets c.client to nil before calling c.client.Done().
+		time.Sleep(time.Second)
+		c.client.Close()
+	}()
+	<-c.client.Done()
+	c.Destroy()
+}
+
+func Test_newNacosClient_connectError(t *testing.T) {
+	nacosURL := "registry://127.0.0.1:8888"
+	registryUrl, err := common.NewURL(nacosURL)
+	assert.NoError(t, err)
+	c := &nacosDynamicConfiguration{
+		url:  &registryUrl,
+		done: make(chan struct{}),
+	}
+	err = ValidateNacosClient(c, WithNacosName(nacosClientName))
+	assert.NoError(t, err)
+	c.wg.Add(1)
+	go HandleClientRestart(c)
+	go func() {
+		// c.client.Close() and <-c.client.Done() have order requirements.
+		// If c.client.Close() is called first.It is possible that "go HandleClientRestart(c)"
+		// sets c.client to nil before calling c.client.Done().
+		time.Sleep(time.Second)
+		c.client.Close()
+	}()
+	<-c.client.Done()
+	// let client do retry
+	time.Sleep(5 * time.Second)
+	c.Destroy()
+}
diff --git a/config_center/nacos/impl.go b/config_center/nacos/impl.go
index b4a7a5467978404387c0c9667dc308a2e68d59ed..bbf707b93811663d0a259c6704e1008bfa91c5c1 100644
--- a/config_center/nacos/impl.go
+++ b/config_center/nacos/impl.go
@@ -38,9 +38,14 @@ import (
 
 const (
 	nacosClientName = "nacos config_center"
-	maxKeysNum      = 9999
+	// the number is a little big tricky
+	// it will be used in query which looks up all keys with the target group
+	// now, one key represents one application
+	// so only a group has more than 9999 applications will failed
+	maxKeysNum = 9999
 )
 
+// nacosDynamicConfiguration is the implementation of DynamicConfiguration based on nacos
 type nacosDynamicConfiguration struct {
 	url          *common.URL
 	rootPath     string
@@ -125,7 +130,7 @@ func (n *nacosDynamicConfiguration) GetConfigKeysByGroup(group string) (*gxset.H
 		return result, perrors.WithMessage(err, "can not find the client config")
 	}
 	for _, itm := range page.PageItems {
-		result.Add(itm.Appname)
+		result.Add(itm.DataId)
 	}
 	return result, nil
 }
diff --git a/config_center/nacos/impl_test.go b/config_center/nacos/impl_test.go
index b0a54b8d37fd060671651f4fffcbdb192527bcea..03fc6772e70d623575575c8522508ae4fff12a04 100644
--- a/config_center/nacos/impl_test.go
+++ b/config_center/nacos/impl_test.go
@@ -72,12 +72,13 @@ func initNacosData(t *testing.T) (*nacosDynamicConfiguration, error) {
 	server := mockCommonNacosServer()
 	nacosURL := strings.ReplaceAll(server.URL, "http", "registry")
 	regurl, _ := common.NewURL(nacosURL)
-	nacosConfiguration, err := newNacosDynamicConfiguration(&regurl)
+	factory := &nacosDynamicConfigurationFactory{}
+	nacosConfiguration, err := factory.GetDynamicConfiguration(&regurl)
 	assert.NoError(t, err)
 
 	nacosConfiguration.SetParser(&parser.DefaultConfigurationParser{})
 
-	return nacosConfiguration, err
+	return nacosConfiguration.(*nacosDynamicConfiguration), err
 }
 
 func Test_GetConfig(t *testing.T) {
@@ -93,7 +94,7 @@ func TestNacosDynamicConfiguration_GetConfigKeysByGroup(t *testing.T) {
 {
     "PageItems": [
         {
-            "Content": "application"
+            "dataId": "application"
         }
     ]
 }
diff --git a/config_center/nacos/listener.go b/config_center/nacos/listener.go
index de74cff8f64683a47278825b670352a04b69b791..fdf5a20d2ff4b97c1e0de40c8b5a0e573214fea4 100644
--- a/config_center/nacos/listener.go
+++ b/config_center/nacos/listener.go
@@ -46,7 +46,9 @@ func (n *nacosDynamicConfiguration) addListener(key string, listener config_cent
 				go callback(listener, namespace, group, dataId, data)
 			},
 		})
-		logger.Errorf("nacos : listen config fail, error:%v ", err)
+		if err != nil {
+			logger.Errorf("nacos : listen config fail, error:%v ", err)
+		}
 		newListener := make(map[config_center.ConfigurationListener]context.CancelFunc)
 		newListener[listener] = cancel
 		n.keyListeners.Store(key, newListener)
diff --git a/config_center/parser/configuration_parser_test.go b/config_center/parser/configuration_parser_test.go
index 7a59ea9b48b8b8d2a84735a416bcba1bb9ec8652..3ba10f73a4549181f37b89aedd4aedf4612bd7d4 100644
--- a/config_center/parser/configuration_parser_test.go
+++ b/config_center/parser/configuration_parser_test.go
@@ -32,3 +32,58 @@ func TestDefaultConfigurationParser_Parser(t *testing.T) {
 	assert.Equal(t, 2, len(m))
 	assert.Equal(t, "172.0.0.1", m["dubbo.registry.address"])
 }
+
+func TestDefaultConfigurationParser_appItemToUrls_ParserToUrls(t *testing.T) {
+	parser := &DefaultConfigurationParser{}
+	content := `configVersion: 2.7.1
+scope: application
+key: org.apache.dubbo-go.mockService
+enabled: true
+configs:
+- type: application
+  enabled: true
+  addresses:
+  - 0.0.0.0
+  providerAddresses: []
+  services:
+  - org.apache.dubbo-go.mockService
+  applications: []
+  parameters:
+    cluster: mock1
+  side: provider`
+	urls, err := parser.ParseToUrls(content)
+	assert.NoError(t, err)
+	assert.Equal(t, 1, len(urls))
+	assert.Equal(t, "org.apache.dubbo-go.mockService", urls[0].GetParam("application", ""))
+	assert.Equal(t, "mock1", urls[0].GetParam("cluster", ""))
+	assert.Equal(t, "override", urls[0].Protocol)
+	assert.Equal(t, "0.0.0.0", urls[0].Location)
+}
+
+func TestDefaultConfigurationParser_serviceItemToUrls_ParserToUrls(t *testing.T) {
+	parser := &DefaultConfigurationParser{}
+	content := `configVersion: 2.7.1
+scope: notApplication
+key: groupA/test:1
+enabled: true
+configs:
+- type: application
+  enabled: true
+  addresses:
+  - 0.0.0.0
+  providerAddresses: []
+  services:
+  - org.apache.dubbo-go.mockService
+  applications: []
+  parameters:
+    cluster: mock1
+  side: provider`
+	urls, err := parser.ParseToUrls(content)
+	assert.NoError(t, err)
+	assert.Equal(t, 1, len(urls))
+	assert.Equal(t, "groupA", urls[0].GetParam("group", ""))
+	assert.Equal(t, "/test", urls[0].Path)
+	assert.Equal(t, "mock1", urls[0].GetParam("cluster", ""))
+	assert.Equal(t, "override", urls[0].Protocol)
+	assert.Equal(t, "0.0.0.0", urls[0].Location)
+}
diff --git a/config_center/zookeeper/impl.go b/config_center/zookeeper/impl.go
index 0a1ce35306dab98363ca475cd5d1b0648e924b90..ef579eb2d11cf5f5bafb132c3e201c12ee7845c0 100644
--- a/config_center/zookeeper/impl.go
+++ b/config_center/zookeeper/impl.go
@@ -20,11 +20,9 @@ package zookeeper
 import (
 	"strings"
 	"sync"
-	"time"
 )
 
 import (
-	"github.com/dubbogo/go-zookeeper/zk"
 	gxset "github.com/dubbogo/gost/container/set"
 	perrors "github.com/pkg/errors"
 )
@@ -81,32 +79,6 @@ func newZookeeperDynamicConfiguration(url *common.URL) (*zookeeperDynamicConfigu
 
 }
 
-func newMockZookeeperDynamicConfiguration(url *common.URL, opts ...zookeeper.Option) (*zk.TestCluster, *zookeeperDynamicConfiguration, error) {
-	c := &zookeeperDynamicConfiguration{
-		url:      url,
-		rootPath: "/" + url.GetParam(constant.CONFIG_NAMESPACE_KEY, config_center.DEFAULT_GROUP) + "/config",
-	}
-	var (
-		tc  *zk.TestCluster
-		err error
-	)
-	tc, c.client, _, err = zookeeper.NewMockZookeeperClient("test", 15*time.Second, opts...)
-	if err != nil {
-		logger.Errorf("mock zookeeper client start error ,error message is %v", err)
-		return tc, c, err
-	}
-	c.wg.Add(1)
-	go zookeeper.HandleClientRestart(c)
-
-	c.listener = zookeeper.NewZkEventListener(c.client)
-	c.cacheListener = NewCacheListener(c.rootPath)
-
-	err = c.client.Create(c.rootPath)
-	go c.listener.ListenServiceEvent(url, c.rootPath, c.cacheListener)
-	return tc, c, err
-
-}
-
 func (c *zookeeperDynamicConfiguration) AddListener(key string, listener config_center.ConfigurationListener, opions ...config_center.Option) {
 	c.cacheListener.AddListener(key, listener)
 }
diff --git a/config_center/zookeeper/impl_test.go b/config_center/zookeeper/impl_test.go
index 30389122a3a06ee260f2ed8b21057523137995d5..cfeba07a87e2534dc60e9ca2235550c1136bd978 100644
--- a/config_center/zookeeper/impl_test.go
+++ b/config_center/zookeeper/impl_test.go
@@ -18,6 +18,7 @@ package zookeeper
 
 import (
 	"fmt"
+	"strconv"
 	"sync"
 	"testing"
 )
@@ -30,16 +31,28 @@ import (
 
 import (
 	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/config_center"
 	"github.com/apache/dubbo-go/config_center/parser"
 )
 
 func initZkData(group string, t *testing.T) (*zk.TestCluster, *zookeeperDynamicConfiguration) {
-	regurl, _ := common.NewURL("registry://127.0.0.1:1111")
-	ts, reg, err := newMockZookeeperDynamicConfiguration(&regurl)
-	reg.SetParser(&parser.DefaultConfigurationParser{})
-
+	ts, err := zk.StartTestCluster(1, nil, nil)
+	assert.NoError(t, err)
+	assert.NotNil(t, ts.Servers[0])
+	urlString := "registry://127.0.0.1:" + strconv.Itoa(ts.Servers[0].Port)
+	regurl, err := common.NewURL(urlString)
+	assert.NoError(t, err)
+	regurl.AddParam(constant.REGISTRY_TIMEOUT_KEY, "15s")
+	zkFactory := &zookeeperDynamicConfigurationFactory{}
+	reg, err := zkFactory.GetDynamicConfiguration(&regurl)
+	zreg, ok := reg.(*zookeeperDynamicConfiguration)
+	assert.True(t, ok)
 	assert.NoError(t, err)
+	assert.True(t, zreg.IsAvailable())
+	assert.Equal(t, zreg.GetUrl(), regurl)
+	assert.True(t, zreg.RestartCallBack())
+	zreg.SetParser(&parser.DefaultConfigurationParser{})
 
 	data := `
 	dubbo.consumer.request_timeout=5s
@@ -63,20 +76,20 @@ func initZkData(group string, t *testing.T) (*zk.TestCluster, *zookeeperDynamicC
 	dubbo.service.com.ikurento.user.UserProvider.cluster=failover
 `
 	if group != "" {
-		err = reg.client.Create(reg.rootPath + "/dubbo/dubbo.properties")
+		err = zreg.client.Create(zreg.rootPath + "/dubbo/dubbo.properties")
 		assert.NoError(t, err)
 
-		_, err = reg.client.Conn.Set(reg.rootPath+"/dubbo/dubbo.properties", []byte(data), 0)
+		_, err = zreg.client.Conn.Set(zreg.rootPath+"/dubbo/dubbo.properties", []byte(data), 0)
 		assert.NoError(t, err)
 	} else {
-		err = reg.client.Create(reg.rootPath + "/dubbo.properties")
+		err = zreg.client.Create(zreg.rootPath + "/dubbo.properties")
 		assert.NoError(t, err)
 
-		_, err = reg.client.Conn.Set(reg.rootPath+"/dubbo.properties", []byte(data), 0)
+		_, err = zreg.client.Conn.Set(zreg.rootPath+"/dubbo.properties", []byte(data), 0)
 		assert.NoError(t, err)
 	}
 
-	return ts, reg
+	return ts, zreg
 }
 
 func Test_GetConfig(t *testing.T) {
@@ -87,6 +100,12 @@ func Test_GetConfig(t *testing.T) {
 	m, err := reg.Parser().Parse(configs)
 	assert.NoError(t, err)
 	assert.Equal(t, "5s", m["dubbo.consumer.request_timeout"])
+	configs, err = reg.GetProperties("dubbo.properties")
+	assert.Error(t, err)
+	configs, err = reg.GetInternalProperty("dubbo.properties")
+	assert.Error(t, err)
+	configs, err = reg.GetRule("dubbo.properties")
+	assert.Error(t, err)
 }
 
 func Test_AddListener(t *testing.T) {
diff --git a/doc/pic/arch/dubbo-go-ext.png b/doc/pic/arch/dubbo-go-ext.png
index a5285c95570afa13212f7ee6eac5510f20243c3c..d065ef4d8e28e507b2ee36fd8c6c6928ab7c9b5d 100644
Binary files a/doc/pic/arch/dubbo-go-ext.png and b/doc/pic/arch/dubbo-go-ext.png differ
diff --git a/filter/access_key.go b/filter/access_key.go
index 40d4157b31d13ed8fd8b1ba8cc9d16b53638ac6a..4801d64fe46461424c5dac5aef2eebc719ee19c4 100644
--- a/filter/access_key.go
+++ b/filter/access_key.go
@@ -22,6 +22,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// AccessKeyPair stores the basic attributes for authentication.
 type AccessKeyPair struct {
 	AccessKey    string `yaml:"accessKey"   json:"accessKey,omitempty" property:"accessKey"`
 	SecretKey    string `yaml:"secretKey"   json:"secretKey,omitempty" property:"secretKey"`
@@ -31,8 +32,7 @@ type AccessKeyPair struct {
 	Options      string `yaml:"options"   json:"options,omitempty" property:"options"`
 }
 
-// AccessKeyStorage
-// This SPI Extension support us to store our AccessKeyPair or load AccessKeyPair from other
+// AccessKeyStorage supports 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
index ac2c8601d4a0d2e5ae3aed56415d9d23856cb502..71f659d4918293e2eb05b8b7a72b6db1cece42ba 100644
--- a/filter/authenticator.go
+++ b/filter/authenticator.go
@@ -22,14 +22,13 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// Authenticator
+// Authenticator defines how an Authenticator works.
+// Custom Authenticator must be set by calling auth.SetAuthenticator before use.
 type Authenticator interface {
 
-	// Sign
-	// give a sign to request
+	// Sign adds signature to the invocation
 	Sign(protocol.Invocation, *common.URL) error
 
-	// Authenticate
-	// verify the signature of the request is valid or not
+	// Authenticate verifies the signature of the request
 	Authenticate(protocol.Invocation, *common.URL) error
 }
diff --git a/filter/filter.go b/filter/filter.go
index c069510498c7ac68b2bb2169dfe7132a4ef63229..d20ca72c345c6812f4bce6df5dbaf683429a9874 100644
--- a/filter/filter.go
+++ b/filter/filter.go
@@ -24,9 +24,11 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// Filter
+// Filter interface defines the functions of a filter
 // Extension - Filter
 type Filter interface {
+	// Invoke is the core function of a filter, it determins the process of the filter
 	Invoke(context.Context, protocol.Invoker, protocol.Invocation) protocol.Result
+	// OnResponse updates the results from Invoke and then returns the modified results.
 	OnResponse(context.Context, protocol.Result, protocol.Invoker, protocol.Invocation) protocol.Result
 }
diff --git a/filter/filter_impl/active_filter.go b/filter/filter_impl/active_filter.go
index 23f2c8e25609dff89392107251715fe6f5175f09..795de968b57207830cc15fc8a0476bfdc3d2cb43 100644
--- a/filter/filter_impl/active_filter.go
+++ b/filter/filter_impl/active_filter.go
@@ -39,11 +39,11 @@ func init() {
 	extension.SetFilter(active, GetActiveFilter)
 }
 
-// ActiveFilter ...
+// ActiveFilter tracks the requests status
 type ActiveFilter struct {
 }
 
-// Invoke ...
+// Invoke starts to record the requests status
 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))
@@ -51,7 +51,7 @@ func (ef *ActiveFilter) Invoke(ctx context.Context, invoker protocol.Invoker, in
 	return invoker.Invoke(ctx, invocation)
 }
 
-// OnResponse ...
+// OnResponse update the active count base on the request result.
 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 {
@@ -64,7 +64,7 @@ func (ef *ActiveFilter) OnResponse(ctx context.Context, result protocol.Result,
 	return result
 }
 
-// GetActiveFilter ...
+// GetActiveFilter creates ActiveFilter instance
 func GetActiveFilter() filter.Filter {
 	return &ActiveFilter{}
 }
diff --git a/filter/filter_impl/auth/accesskey_storage.go b/filter/filter_impl/auth/accesskey_storage.go
index 5adb9d9ee37329228d1d02dc8802deeede68d327..90d3efb5ad897b874c89745740637804808b5133 100644
--- a/filter/filter_impl/auth/accesskey_storage.go
+++ b/filter/filter_impl/auth/accesskey_storage.go
@@ -25,13 +25,11 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// DefaultAccesskeyStorage
-// The default implementation of AccesskeyStorage
+// DefaultAccesskeyStorage is the default implementation of AccesskeyStorage
 type DefaultAccesskeyStorage struct {
 }
 
-// GetAccessKeyPair
-// get AccessKeyPair from url by the key "accessKeyId" and "secretAccessKey"
+// GetAccessKeyPair retrieves 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, ""),
@@ -43,6 +41,7 @@ func init() {
 	extension.SetAccesskeyStorages(constant.DEFAULT_ACCESS_KEY_STORAGE, GetDefaultAccesskeyStorage)
 }
 
+// GetDefaultAccesskeyStorage initiates an empty DefaultAccesskeyStorage
 func GetDefaultAccesskeyStorage() filter.AccessKeyStorage {
 	return &DefaultAccesskeyStorage{}
 }
diff --git a/filter/filter_impl/auth/consumer_sign.go b/filter/filter_impl/auth/consumer_sign.go
index 062744771acf8ccd505265875a103d24afeb06af..945cf3e6e7e728042b5422174162dd5aded50361 100644
--- a/filter/filter_impl/auth/consumer_sign.go
+++ b/filter/filter_impl/auth/consumer_sign.go
@@ -29,8 +29,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// ConsumerSignFilter
-// This filter is working for signing the request on consumer side
+// ConsumerSignFilter signs the request on consumer side
 type ConsumerSignFilter struct {
 }
 
@@ -38,6 +37,7 @@ func init() {
 	extension.SetFilter(constant.CONSUMER_SIGN_FILTER, getConsumerSignFilter)
 }
 
+// Invoke retrieves the configured Authenticator to add signature to invocation
 func (csf *ConsumerSignFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	logger.Infof("invoking ConsumerSign filter.")
 	url := invoker.GetUrl()
@@ -52,6 +52,7 @@ func (csf *ConsumerSignFilter) Invoke(ctx context.Context, invoker protocol.Invo
 	return invoker.Invoke(ctx, invocation)
 }
 
+// OnResponse dummy process, returns the result directly
 func (csf *ConsumerSignFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	return result
 }
diff --git a/filter/filter_impl/auth/default_authenticator.go b/filter/filter_impl/auth/default_authenticator.go
index 2b8d55927807407f350ecc6cfc28b6913a6d1a81..5b86fc148e42b6364bcb0752c31bfbbc3cfa2b9d 100644
--- a/filter/filter_impl/auth/default_authenticator.go
+++ b/filter/filter_impl/auth/default_authenticator.go
@@ -37,13 +37,11 @@ func init() {
 	extension.SetAuthenticator(constant.DEFAULT_AUTHENTICATOR, GetDefaultAuthenticator)
 }
 
-// DefaultAuthenticator
-// The default implemetation of Authenticator
+// DefaultAuthenticator is the default implementation of Authenticator
 type DefaultAuthenticator struct {
 }
 
-// Sign
-// add the signature for the invocation
+// Sign adds the signature to the invocation
 func (authenticator *DefaultAuthenticator) Sign(invocation protocol.Invocation, url *common.URL) error {
 	currentTimeMillis := strconv.Itoa(int(time.Now().Unix() * 1000))
 
@@ -84,8 +82,7 @@ func getSignature(url *common.URL, invocation protocol.Invocation, secrectKey st
 	return signature, nil
 }
 
-// Authenticate
-// This method verifies whether the signature sent by the requester is correct
+// Authenticate 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, "")
 
@@ -122,6 +119,7 @@ func getAccessKeyPair(invocation protocol.Invocation, url *common.URL) (*filter.
 	}
 }
 
+// GetDefaultAuthenticator creates an empty DefaultAuthenticator instance
 func GetDefaultAuthenticator() filter.Authenticator {
 	return &DefaultAuthenticator{}
 }
diff --git a/filter/filter_impl/auth/provider_auth.go b/filter/filter_impl/auth/provider_auth.go
index 0d5772e5508894111a88443bfe2d1b02ebfac54a..d5f5db300d4e7c94978d5d52e32f741f7d27bb48 100644
--- a/filter/filter_impl/auth/provider_auth.go
+++ b/filter/filter_impl/auth/provider_auth.go
@@ -29,8 +29,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// ProviderAuthFilter
-// This filter is used to verify the correctness of the signature on provider side
+// ProviderAuthFilter verifies the correctness of the signature on provider side
 type ProviderAuthFilter struct {
 }
 
@@ -38,6 +37,7 @@ func init() {
 	extension.SetFilter(constant.PROVIDER_AUTH_FILTER, getProviderAuthFilter)
 }
 
+// Invoke retrieves the configured Authenticator to verify the signature in an invocation
 func (paf *ProviderAuthFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	logger.Infof("invoking providerAuth filter.")
 	url := invoker.GetUrl()
@@ -55,6 +55,7 @@ func (paf *ProviderAuthFilter) Invoke(ctx context.Context, invoker protocol.Invo
 	return invoker.Invoke(ctx, invocation)
 }
 
+// OnResponse dummy process, returns the result directly
 func (paf *ProviderAuthFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	return result
 }
diff --git a/filter/filter_impl/auth/sign_util.go b/filter/filter_impl/auth/sign_util.go
index 043a549a849dde66712e1bef389dd91a024660df..45170bb8117284275a87a3a57d14ce68d6cc4e9c 100644
--- a/filter/filter_impl/auth/sign_util.go
+++ b/filter/filter_impl/auth/sign_util.go
@@ -26,12 +26,12 @@ import (
 	"strings"
 )
 
-// Sign
-// get a signature string with given information, such as metadata or parameters
+// Sign gets a signature string with given bytes
 func Sign(metadata, key string) string {
 	return doSign([]byte(metadata), key)
 }
 
+// SignWithParams returns a signature with giving params and metadata.
 func SignWithParams(params []interface{}, metadata, key string) (string, error) {
 	if params == nil || len(params) == 0 {
 		return Sign(metadata, key), nil
@@ -61,6 +61,7 @@ func doSign(bytes []byte, key string) string {
 	return base64.URLEncoding.EncodeToString(signature)
 }
 
+// IsEmpty verify whether the inputted string is empty
 func IsEmpty(s string, allowSpace bool) bool {
 	if len(s) == 0 {
 		return true
diff --git a/filter/filter_impl/echo_filter.go b/filter/filter_impl/echo_filter.go
index a12800a21a8ebe4545b4a8b5bd0f8a30c1462105..7da5ec7029ea698b1bf1a14ad36123fbec3aacf7 100644
--- a/filter/filter_impl/echo_filter.go
+++ b/filter/filter_impl/echo_filter.go
@@ -38,13 +38,13 @@ func init() {
 	extension.SetFilter(ECHO, GetFilter)
 }
 
-// EchoFilter
+// EchoFilter health check
 // 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{}
 
-// Invoke ...
+// Invoke response to the callers with its first argument.
 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()))
@@ -58,7 +58,7 @@ func (ef *EchoFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invo
 	return invoker.Invoke(ctx, invocation)
 }
 
-// OnResponse ...
+// OnResponse dummy process, returns the result directly
 func (ef *EchoFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker,
 	_ protocol.Invocation) protocol.Result {
 
diff --git a/filter/filter_impl/execute_limit_filter.go b/filter/filter_impl/execute_limit_filter.go
index 434c378045456eb13317e0a48630ebd33f244c05..bfc5096ca089867f6e6234089e387d3f9b48a3aa 100644
--- a/filter/filter_impl/execute_limit_filter.go
+++ b/filter/filter_impl/execute_limit_filter.go
@@ -45,9 +45,8 @@ func init() {
 	extension.SetFilter(name, GetExecuteLimitFilter)
 }
 
+// ExecuteLimitFilter  will limit the number of in-progress request and it's thread-safe.
 /**
- * ExecuteLimitFilter
- * The filter will limit the number of in-progress request and it's thread-safe.
  * example:
  * "UserProvider":
  *   registry: "hangzhouzk"
@@ -80,7 +79,7 @@ type ExecuteState struct {
 	concurrentCount int64
 }
 
-// Invoke ...
+// Invoke judges whether the current processing requests over the threshold
 func (ef *ExecuteLimitFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	methodConfigPrefix := "methods." + invocation.MethodName() + "."
 	ivkURL := invoker.GetUrl()
@@ -122,7 +121,7 @@ func (ef *ExecuteLimitFilter) Invoke(ctx context.Context, invoker protocol.Invok
 	return invoker.Invoke(ctx, invocation)
 }
 
-// OnResponse ...
+// OnResponse dummy process, returns the result directly
 func (ef *ExecuteLimitFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker, _ protocol.Invocation) protocol.Result {
 	return result
 }
@@ -138,7 +137,7 @@ func (state *ExecuteState) decrease() {
 var executeLimitOnce sync.Once
 var executeLimitFilter *ExecuteLimitFilter
 
-// GetExecuteLimitFilter ...
+// GetExecuteLimitFilter returns the singleton ExecuteLimitFilter instance
 func GetExecuteLimitFilter() filter.Filter {
 	executeLimitOnce.Do(func() {
 		executeLimitFilter = &ExecuteLimitFilter{
diff --git a/filter/filter_impl/generic_filter.go b/filter/filter_impl/generic_filter.go
index 9bc131ef8903942b84df2b8fc14fd11143d1a7b6..3f4d714e6b0cbdf48f5e1afce3222a18857041f9 100644
--- a/filter/filter_impl/generic_filter.go
+++ b/filter/filter_impl/generic_filter.go
@@ -50,7 +50,7 @@ func init() {
 // GenericFilter ...
 type GenericFilter struct{}
 
-// Invoke ...
+// Invoke turns the parameters to map for generic method
 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()
@@ -73,13 +73,13 @@ func (ef *GenericFilter) Invoke(ctx context.Context, invoker protocol.Invoker, i
 	return invoker.Invoke(ctx, invocation)
 }
 
-// OnResponse ...
+// OnResponse dummy process, returns the result directly
 func (ef *GenericFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker,
 	_ protocol.Invocation) protocol.Result {
 	return result
 }
 
-// GetGenericFilter ...
+// GetGenericFilter returns GenericFilter instance
 func GetGenericFilter() filter.Filter {
 	return &GenericFilter{}
 }
diff --git a/filter/filter_impl/graceful_shutdown_filter.go b/filter/filter_impl/graceful_shutdown_filter.go
index 95e625b2d56895a4d57823e4e0e2e7d1d5e90a08..4a4e8ce466edabe82815b99244404ac024d73b26 100644
--- a/filter/filter_impl/graceful_shutdown_filter.go
+++ b/filter/filter_impl/graceful_shutdown_filter.go
@@ -53,6 +53,7 @@ type gracefulShutdownFilter struct {
 	shutdownConfig *config.ShutdownConfig
 }
 
+// Invoke adds the requests count and block the new requests if application is closing
 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.")
@@ -62,6 +63,7 @@ func (gf *gracefulShutdownFilter) Invoke(ctx context.Context, invoker protocol.I
 	return invoker.Invoke(ctx, invocation)
 }
 
+// OnResponse reduces the number of active processes then return the process 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.
diff --git a/filter/filter_impl/hystrix_filter.go b/filter/filter_impl/hystrix_filter.go
index 4c872bed3e7fef8eca47f51422525a4918d6c1d8..711ef71c44192c5a1d76783a3b3d4cbd0b97632c 100644
--- a/filter/filter_impl/hystrix_filter.go
+++ b/filter/filter_impl/hystrix_filter.go
@@ -55,14 +55,14 @@ var (
 
 //The filter in the server end of dubbo-go can't get the invoke result for now,
 //this filter ONLY works in CLIENT end (consumer side) temporarily
-//Only after the callService logic is integrated into the filter chain of server end can this filter be used,
+//Only after the callService logic is integrated into the filter chain of server end then the filter can be used,
 //which will be done soon
 func init() {
 	extension.SetFilter(HYSTRIX_CONSUMER, GetHystrixFilterConsumer)
 	extension.SetFilter(HYSTRIX_PROVIDER, GetHystrixFilterProvider)
 }
 
-// HystrixFilterError ...
+// HystrixFilterError implements error interface
 type HystrixFilterError struct {
 	err           error
 	failByHystrix bool
@@ -72,12 +72,12 @@ func (hfError *HystrixFilterError) Error() string {
 	return hfError.err.Error()
 }
 
-// FailByHystrix ...
+// FailByHystrix returns whether the fails causing by Hystrix
 func (hfError *HystrixFilterError) FailByHystrix() bool {
 	return hfError.failByHystrix
 }
 
-// NewHystrixFilterError ...
+// NewHystrixFilterError return a HystrixFilterError instance
 func NewHystrixFilterError(err error, failByHystrix bool) error {
 	return &HystrixFilterError{
 		err:           err,
@@ -92,7 +92,7 @@ type HystrixFilter struct {
 	ifNewMap sync.Map
 }
 
-// Invoke ...
+// Invoke is an implentation of filter, provides Hystrix pattern latency and fault tolerance
 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())
 
@@ -154,12 +154,12 @@ func (hf *HystrixFilter) Invoke(ctx context.Context, invoker protocol.Invoker, i
 	return result
 }
 
-// OnResponse ...
+// OnResponse dummy process, returns the result directly
 func (hf *HystrixFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	return result
 }
 
-// GetHystrixFilterConsumer ...
+// GetHystrixFilterConsumer returns HystrixFilter instance for consumer
 func GetHystrixFilterConsumer() filter.Filter {
 	//When first called, load the config in
 	consumerConfigOnce.Do(func() {
@@ -170,7 +170,7 @@ func GetHystrixFilterConsumer() filter.Filter {
 	return &HystrixFilter{COrP: true}
 }
 
-// GetHystrixFilterProvider ...
+// GetHystrixFilterProvider returns HystrixFilter instance for provider
 func GetHystrixFilterProvider() filter.Filter {
 	providerConfigOnce.Do(func() {
 		if err := initHystrixConfigProvider(); err != nil {
diff --git a/filter/filter_impl/token_filter.go b/filter/filter_impl/token_filter.go
index 8ec3929b6ddc8dcfa430204cd22d2f6d297c59d3..23742c66e94d9ecfc09d004441a54aad86ef049e 100644
--- a/filter/filter_impl/token_filter.go
+++ b/filter/filter_impl/token_filter.go
@@ -42,10 +42,10 @@ func init() {
 	extension.SetFilter(TOKEN, GetTokenFilter)
 }
 
-// TokenFilter ...
+// TokenFilter will verify if the token is valid
 type TokenFilter struct{}
 
-// Invoke ...
+// Invoke verifies the incoming token with the service configured token
 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 {
@@ -61,7 +61,7 @@ func (tf *TokenFilter) Invoke(ctx context.Context, invoker protocol.Invoker, inv
 	return invoker.Invoke(ctx, invocation)
 }
 
-// OnResponse ...
+// OnResponse dummy process, returns the result directly
 func (tf *TokenFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	return result
 }
diff --git a/filter/filter_impl/tps/tps_limit_fix_window_strategy.go b/filter/filter_impl/tps/tps_limit_fix_window_strategy.go
index a9c2ac15a417ffa6ff8f5b8d78d5c6a94877db30..7419a4576122d4db334969b0711666b5b2816e60 100644
--- a/filter/filter_impl/tps/tps_limit_fix_window_strategy.go
+++ b/filter/filter_impl/tps/tps_limit_fix_window_strategy.go
@@ -39,8 +39,8 @@ func init() {
 	extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, creator)
 }
 
+// FixedWindowTpsLimitStrategyImpl implements the TPS limit strategy base on requests count during the interval
 /**
- * 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
@@ -65,7 +65,8 @@ type FixedWindowTpsLimitStrategyImpl struct {
 	timestamp int64
 }
 
-// IsAllowable ...
+// IsAllowable determines if the requests over the TPS limit within the interval.
+// It is not thread-safe.
 func (impl *FixedWindowTpsLimitStrategyImpl) IsAllowable() bool {
 
 	current := time.Now().UnixNano()
@@ -82,6 +83,7 @@ func (impl *FixedWindowTpsLimitStrategyImpl) IsAllowable() bool {
 
 type fixedWindowStrategyCreator struct{}
 
+// Create returns a FixedWindowTpsLimitStrategyImpl instance with pre-configured limit rate and interval
 func (creator *fixedWindowStrategyCreator) Create(rate int, interval int) filter.TpsLimitStrategy {
 	return &FixedWindowTpsLimitStrategyImpl{
 		rate:      int32(rate),
diff --git a/filter/filter_impl/tps/tps_limit_sliding_window_strategy.go b/filter/filter_impl/tps/tps_limit_sliding_window_strategy.go
index a781cc7bfbf297d0b9cf84ca0aa9dcfbbef7e14b..cbbba19fff65be222cb895dcbe9b2e4d02082985 100644
--- a/filter/filter_impl/tps/tps_limit_sliding_window_strategy.go
+++ b/filter/filter_impl/tps/tps_limit_sliding_window_strategy.go
@@ -32,8 +32,8 @@ func init() {
 	extension.SetTpsLimitStrategy("slidingWindow", &slidingWindowStrategyCreator{})
 }
 
+// SlidingWindowTpsLimitStrategyImpl implements a thread-safe TPS limit strategy base on requests count.
 /**
- * SlidingWindowTpsLimitStrategyImpl
  * it's thread-safe.
  * "UserProvider":
  *   registry: "hangzhouzk"
@@ -54,7 +54,8 @@ type SlidingWindowTpsLimitStrategyImpl struct {
 	queue    *list.List
 }
 
-// IsAllowable ...
+// IsAllowable determins whether the number of requests within the time window overs the threshold
+// It is thread-safe.
 func (impl *SlidingWindowTpsLimitStrategyImpl) IsAllowable() bool {
 	impl.mutex.Lock()
 	defer impl.mutex.Unlock()
@@ -84,6 +85,7 @@ func (impl *SlidingWindowTpsLimitStrategyImpl) IsAllowable() bool {
 
 type slidingWindowStrategyCreator struct{}
 
+// Create returns SlidingWindowTpsLimitStrategyImpl instance with configured limit rate and interval
 func (creator *slidingWindowStrategyCreator) Create(rate int, interval int) filter.TpsLimitStrategy {
 	return &SlidingWindowTpsLimitStrategyImpl{
 		rate:     rate,
diff --git a/filter/filter_impl/tps/tps_limit_thread_safe_fix_window_strategy.go b/filter/filter_impl/tps/tps_limit_thread_safe_fix_window_strategy.go
index 16624836e6397df5adda3f2aa5a80966721a97fb..f78cd8211cd076dcab84759e2bf784d080c72a1c 100644
--- a/filter/filter_impl/tps/tps_limit_thread_safe_fix_window_strategy.go
+++ b/filter/filter_impl/tps/tps_limit_thread_safe_fix_window_strategy.go
@@ -32,10 +32,9 @@ func init() {
 	})
 }
 
+// ThreadSafeFixedWindowTpsLimitStrategyImpl is the thread-safe implementation.
+// It's also a thread-safe decorator of FixedWindowTpsLimitStrategyImpl
 /**
- * ThreadSafeFixedWindowTpsLimitStrategyImpl
- * it's the thread-safe implementation.
- * Also, it's a thread-safe decorator of FixedWindowTpsLimitStrategyImpl
  * "UserProvider":
  *   registry: "hangzhouzk"
  *   protocol : "dubbo"
@@ -53,7 +52,7 @@ type ThreadSafeFixedWindowTpsLimitStrategyImpl struct {
 	fixedWindow *FixedWindowTpsLimitStrategyImpl
 }
 
-// IsAllowable ...
+// IsAllowable implements thread-safe then run the FixedWindowTpsLimitStrategy
 func (impl *ThreadSafeFixedWindowTpsLimitStrategyImpl) IsAllowable() bool {
 	impl.mutex.Lock()
 	defer impl.mutex.Unlock()
@@ -64,6 +63,7 @@ type threadSafeFixedWindowStrategyCreator struct {
 	fixedWindowStrategyCreator *fixedWindowStrategyCreator
 }
 
+// Create returns ThreadSafeFixedWindowTpsLimitStrategyImpl instance
 func (creator *threadSafeFixedWindowStrategyCreator) Create(rate int, interval int) filter.TpsLimitStrategy {
 	fixedWindowStrategy := creator.fixedWindowStrategyCreator.Create(rate, interval).(*FixedWindowTpsLimitStrategyImpl)
 	return &ThreadSafeFixedWindowTpsLimitStrategyImpl{
diff --git a/filter/filter_impl/tps/tps_limiter_method_service.go b/filter/filter_impl/tps/tps_limiter_method_service.go
index 2d44c688ebd460f60a49da0f148fd7c6e2b79f50..5761579a38a22500d54193a9564170cc0215cf0f 100644
--- a/filter/filter_impl/tps/tps_limiter_method_service.go
+++ b/filter/filter_impl/tps/tps_limiter_method_service.go
@@ -44,9 +44,8 @@ func init() {
 	extension.SetTpsLimiter(name, GetMethodServiceTpsLimiter)
 }
 
+// MethodServiceTpsLimiterImpl allows developer to config both method-level and service-level tps limiter.
 /**
- * MethodServiceTpsLimiterImpl
- * This implementation allows developer to config both method-level and service-level tps limiter.
  * for example:
  * "UserProvider":
  *   registry: "hangzhouzk"
diff --git a/filter/filter_impl/tps_limit_filter.go b/filter/filter_impl/tps_limit_filter.go
index fa78288f9678d67d0eb0d025a83b75493f7fda80..ea1e3bc15e1952799227d712db114ff790527720 100644
--- a/filter/filter_impl/tps_limit_filter.go
+++ b/filter/filter_impl/tps_limit_filter.go
@@ -39,8 +39,8 @@ func init() {
 	extension.SetFilter(TpsLimitFilterKey, GetTpsLimitFilter)
 }
 
+// TpsLimitFilter filters the requests by TPS
 /**
- * TpsLimitFilter
  * if you wish to use the TpsLimiter, please add the configuration into your service provider configuration:
  * for example:
  * "UserProvider":
@@ -56,7 +56,7 @@ func init() {
 type TpsLimitFilter struct {
 }
 
-// Invoke ...
+// Invoke gets the configured limter to impose TPS limiting
 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, "")
@@ -72,13 +72,13 @@ func (t TpsLimitFilter) Invoke(ctx context.Context, invoker protocol.Invoker, in
 	return invoker.Invoke(ctx, invocation)
 }
 
-// OnResponse ...
+// OnResponse dummy process, returns the result directly
 func (t TpsLimitFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker,
 	_ protocol.Invocation) protocol.Result {
 	return result
 }
 
-// GetTpsLimitFilter ...
+// GetTpsLimitFilter returns an TpsLimitFilter instance.
 func GetTpsLimitFilter() filter.Filter {
 	return &TpsLimitFilter{}
 }
diff --git a/filter/handler/rejected_execution_handler_only_log.go b/filter/handler/rejected_execution_handler_only_log.go
index fe9cf4869f16e1d7c136e7f48e4138d046fcb057..52ac1765f78172c0062de8884198e759b8d494ca 100644
--- a/filter/handler/rejected_execution_handler_only_log.go
+++ b/filter/handler/rejected_execution_handler_only_log.go
@@ -44,8 +44,8 @@ func init() {
 var onlyLogHandlerInstance *OnlyLogRejectedExecutionHandler
 var onlyLogHandlerOnce sync.Once
 
+// OnlyLogRejectedExecutionHandler implements the RejectedExecutionHandler
 /**
- * OnlyLogRejectedExecutionHandler
  * This implementation only logs the invocation info.
  * it always return en error inside the result.
  * "UserProvider":
diff --git a/filter/rejected_execution_handler.go b/filter/rejected_execution_handler.go
index 9855bd5354d0582bffaae177dfe8d8ddb95ed985..3d1e1c1e641a836411ce0f71f97acf5d5a55f6d1 100644
--- a/filter/rejected_execution_handler.go
+++ b/filter/rejected_execution_handler.go
@@ -22,11 +22,11 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// RejectedExecutionHandler defines the handler to handle exceptions from invoking filters.
 /**
- * RejectedExecutionHandler
  * If the invocation cannot pass any validation in filter, like ExecuteLimitFilter and TpsLimitFilter,
  * the implementation will be used.
- * The event case is that sometimes you want to return the default value when the request was rejected.
+ * The common case is that sometimes you want to return the default value when the request was rejected.
  * Or you want to be warned if any request was rejected.
  * In such situation, implement this interface and register it by invoking extension.SetRejectedExecutionHandler.
  */
diff --git a/filter/tps_limit_strategy.go b/filter/tps_limit_strategy.go
index e194f1da06b0599464f0c66f6b7747fc78fbedce..2ee876a0b340ed1f87b94c35b149b548371e2bf9 100644
--- a/filter/tps_limit_strategy.go
+++ b/filter/tps_limit_strategy.go
@@ -17,8 +17,8 @@
 
 package filter
 
+// TpsLimitStrategy defines how to do the TPS limiting in method level.
 /*
- * TpsLimitStrategy
  * please register your implementation by invoking SetTpsLimitStrategy
  * "UserProvider":
  *   registry: "hangzhouzk"
@@ -37,7 +37,7 @@ type TpsLimitStrategy interface {
 	IsAllowable() bool
 }
 
-// TpsLimitStrategyCreator, the creator abstraction for TpsLimitStrategy
+// TpsLimitStrategyCreator is the creator abstraction for TpsLimitStrategy
 type TpsLimitStrategyCreator interface {
 	// Create will create an instance of TpsLimitStrategy
 	// It will be a little hard to understand this method.
diff --git a/filter/tps_limiter.go b/filter/tps_limiter.go
index 531eb098232cd34a467d71882b29858c07f88aef..8385d7b5d84a420b54df6bf51e32a35d17e1b249 100644
--- a/filter/tps_limiter.go
+++ b/filter/tps_limiter.go
@@ -22,8 +22,8 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
+// TpsLimiter defines the Limiter that judge if the TPS overs the threshold
 /*
- * TpsLimiter
  * please register your implementation by invoking SetTpsLimiter
  * The usage, for example:
  * "UserProvider":
diff --git a/go.mod b/go.mod
index 0fc3599813b1cb96a5988119d27d4596f115e386..89d3f9ce2630907d15aa3637f5ab42b51110572c 100644
--- a/go.mod
+++ b/go.mod
@@ -26,24 +26,24 @@ require (
 	github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645
 	github.com/hashicorp/consul v1.5.3
 	github.com/hashicorp/consul/api v1.1.0
+	github.com/hashicorp/vault v0.10.3
 	github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8
 	github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 // indirect
 	github.com/juju/testing v0.0.0-20191001232224-ce9dec17d28b // 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.3.1
+	github.com/nacos-group/nacos-sdk-go v0.3.3-0.20200617023039-50c7537d6a5f
 	github.com/opentracing/opentracing-go v1.1.0
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus/client_golang v1.1.0
-	github.com/satori/go.uuid v1.2.0
+	github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
 	github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect
 	github.com/soheilhy/cmux v0.1.4 // indirect
 	github.com/stretchr/testify v1.5.1
 	github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect
 	github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
 	github.com/zouyx/agollo v0.0.0-20191114083447-dde9fc9f35b8
-	go.etcd.io/bbolt v1.3.4 // indirect
 	go.uber.org/atomic v1.4.0
 	go.uber.org/zap v1.10.0
 	golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
diff --git a/go.sum b/go.sum
index a26694e75f08e37ed963831edbd7700f1f773393..93bca6b976b0acd208ad00a8dd26cab10e766ce8 100644
--- a/go.sum
+++ b/go.sum
@@ -388,8 +388,8 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/nacos-group/nacos-sdk-go v0.3.1 h1:MI7bNDAN5m9UFcRRUTSPfJi4dCQo+TYG85qVB1rCHeg=
-github.com/nacos-group/nacos-sdk-go v0.3.1/go.mod h1:ESKb6yF0gxSc8GuS+0jaMBe+n8rJ5/k4ya6LyFG2xi8=
+github.com/nacos-group/nacos-sdk-go v0.3.3-0.20200617023039-50c7537d6a5f h1:gid5/0AkHvINWK69Fgbidb3BVIXqlf1YEm7wO0NVPsw=
+github.com/nacos-group/nacos-sdk-go v0.3.3-0.20200617023039-50c7537d6a5f/go.mod h1:fti1GlX/EB6RDKvzK/P7Vuibqj0JMPJHQwrcTU1tLXk=
 github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 h1:BQ1HW7hr4IVovMwWg0E0PYcyW8CzqDcVmaew9cujU4s=
 github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk=
 github.com/oklog/run v0.0.0-20180308005104-6934b124db28 h1:Hbr3fbVPXea52oPQeP7KLSxP52g6SFaNY1IqAmUyEW0=
@@ -457,8 +457,8 @@ 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/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=
+github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/shirou/gopsutil v0.0.0-20181107111621-48177ef5f880 h1:1Ge4j/3uB2rxzPWD3TC+daeCw+w91z8UCUL/7WH5gn8=
diff --git a/metadata/definition/definition.go b/metadata/definition/definition.go
index fa195d09d7efe022be9bdf40658e355a44b8705e..dbbc0c8f1685edf1a26ab1fe4ad091c501e76f5f 100644
--- a/metadata/definition/definition.go
+++ b/metadata/definition/definition.go
@@ -42,10 +42,12 @@ type ServiceDefinition struct {
 	Types         []TypeDefinition
 }
 
+// ToBytes convert ServiceDefinition to json string
 func (def *ServiceDefinition) ToBytes() ([]byte, error) {
 	return json.Marshal(def)
 }
 
+// String will iterate all methods and parameters and convert them to json string
 func (def *ServiceDefinition) String() string {
 	var methodStr strings.Builder
 	for _, m := range def.Methods {
@@ -97,13 +99,21 @@ func BuildServiceDefinition(service common.Service, url common.URL) *ServiceDefi
 
 	for k, m := range service.Method() {
 		var paramTypes []string
-		for _, t := range m.ArgsType() {
-			paramTypes = append(paramTypes, t.Kind().String())
+		if len(m.ArgsType()) > 0 {
+			for _, t := range m.ArgsType() {
+				paramTypes = append(paramTypes, t.Kind().String())
+			}
 		}
+
+		var returnType string
+		if m.ReplyType() != nil {
+			returnType = m.ReplyType().Kind().String()
+		}
+
 		methodD := MethodDefinition{
 			Name:           k,
 			ParameterTypes: paramTypes,
-			ReturnType:     m.ReplyType().Kind().String(),
+			ReturnType:     returnType,
 		}
 		sd.Methods = append(sd.Methods, methodD)
 	}
diff --git a/metadata/identifier/base_metadata_identifier.go b/metadata/identifier/base_metadata_identifier.go
index 64290c668f14277a5f2c8b9e7603ca50e7713fd6..2371f7ca02f403a11251b9b0cbb23369b27683e2 100644
--- a/metadata/identifier/base_metadata_identifier.go
+++ b/metadata/identifier/base_metadata_identifier.go
@@ -49,7 +49,7 @@ func joinParams(joinChar string, params []string) string {
 	return joinedStr
 }
 
-// getIdentifierKey will return string format as service:Version:Group:Side:param1:param2...
+// getIdentifierKey returns string that format is service:Version:Group:Side:param1:param2...
 func (mdi *BaseMetadataIdentifier) getIdentifierKey(params ...string) string {
 	return mdi.ServiceInterface +
 		constant.KEY_SEPARATOR + mdi.Version +
@@ -58,7 +58,7 @@ func (mdi *BaseMetadataIdentifier) getIdentifierKey(params ...string) string {
 		joinParams(constant.KEY_SEPARATOR, params)
 }
 
-// getFilePathKey will return string format as metadata/path/Version/Group/Side/param1/param2...
+// getFilePathKey returns string that format is metadata/path/Version/Group/Side/param1/param2...
 func (mdi *BaseMetadataIdentifier) getFilePathKey(params ...string) string {
 	path := serviceToPath(mdi.ServiceInterface)
 
@@ -71,7 +71,7 @@ func (mdi *BaseMetadataIdentifier) getFilePathKey(params ...string) string {
 
 }
 
-// serviceToPath...
+// serviceToPath uss URL encode to decode the @serviceInterface
 func serviceToPath(serviceInterface string) string {
 	if serviceInterface == constant.ANY_VALUE {
 		return ""
@@ -85,7 +85,7 @@ func serviceToPath(serviceInterface string) string {
 
 }
 
-//withPathSeparator...
+// withPathSeparator return "/" + @path
 func withPathSeparator(path string) string {
 	if len(path) != 0 {
 		path = constant.PATH_SEPARATOR + path
diff --git a/metadata/identifier/metadata_identifier.go b/metadata/identifier/metadata_identifier.go
index 18b330ae083d55cf77330d19c144b2d4a6bde862..7e50c4c6b9427bd9d439daa7464d96a2ea94fd39 100644
--- a/metadata/identifier/metadata_identifier.go
+++ b/metadata/identifier/metadata_identifier.go
@@ -23,12 +23,12 @@ type MetadataIdentifier struct {
 	BaseMetadataIdentifier
 }
 
-// GetIdentifierKey will return string format as service:Version:Group:Side:Application
+// GetIdentifierKey returns string that format is service:Version:Group:Side:Application
 func (mdi *MetadataIdentifier) GetIdentifierKey() string {
 	return mdi.BaseMetadataIdentifier.getIdentifierKey(mdi.Application)
 }
 
-// GetFilePathKey will return string format as metadata/path/Version/Group/Side/Application
+// GetFilePathKey returns string that format is metadata/path/Version/Group/Side/Application
 func (mdi *MetadataIdentifier) GetFilePathKey() string {
 	return mdi.BaseMetadataIdentifier.getFilePathKey(mdi.Application)
 }
diff --git a/metadata/identifier/service_metadata_identifier.go b/metadata/identifier/service_metadata_identifier.go
index 7cdb55e53db6fdc6092f17e2688bf8078559cbec..b9e65967e0f707a6efcc9f8ded2ce5dec4f058b8 100644
--- a/metadata/identifier/service_metadata_identifier.go
+++ b/metadata/identifier/service_metadata_identifier.go
@@ -29,6 +29,9 @@ type ServiceMetadataIdentifier struct {
 	BaseMetadataIdentifier
 }
 
+// NewServiceMetadataIdentifier create instance.
+// The ServiceInterface is the @url.Service()
+// other parameters are read from @url
 func NewServiceMetadataIdentifier(url common.URL) *ServiceMetadataIdentifier {
 	return &ServiceMetadataIdentifier{
 		BaseMetadataIdentifier: BaseMetadataIdentifier{
@@ -41,12 +44,12 @@ func NewServiceMetadataIdentifier(url common.URL) *ServiceMetadataIdentifier {
 	}
 }
 
-// GetIdentifierKey will return string format as service:Version:Group:Side:Protocol:"revision"+Revision
+// GetIdentifierKey returns string that format is service:Version:Group:Side:Protocol:"revision"+Revision
 func (mdi *ServiceMetadataIdentifier) GetIdentifierKey() string {
 	return mdi.BaseMetadataIdentifier.getIdentifierKey(mdi.Protocol, constant.KEY_REVISON_PREFIX+mdi.Revision)
 }
 
-// GetFilePathKey will return string format as metadata/path/Version/Group/Side/Protocol/"revision"+Revision
+// GetFilePathKey returns string that format is metadata/path/Version/Group/Side/Protocol/"revision"+Revision
 func (mdi *ServiceMetadataIdentifier) GetFilePathKey() string {
 	return mdi.BaseMetadataIdentifier.getFilePathKey(mdi.Protocol, constant.KEY_REVISON_PREFIX+mdi.Revision)
 }
diff --git a/metadata/identifier/subscribe_metadata_identifier.go b/metadata/identifier/subscribe_metadata_identifier.go
index fa35ab79d66fe39062462e6f5ae43b562a3c6a91..b1e37db971ada56a77bc3b716606b6fc8d137d34 100644
--- a/metadata/identifier/subscribe_metadata_identifier.go
+++ b/metadata/identifier/subscribe_metadata_identifier.go
@@ -23,12 +23,12 @@ type SubscriberMetadataIdentifier struct {
 	MetadataIdentifier
 }
 
-// GetIdentifierKey will return string format as service:Version:Group:Side:Revision
+// GetIdentifierKey returns string that format is service:Version:Group:Side:Revision
 func (mdi *SubscriberMetadataIdentifier) GetIdentifierKey() string {
 	return mdi.BaseMetadataIdentifier.getIdentifierKey(mdi.Revision)
 }
 
-// GetFilePathKey will return string format as metadata/path/Version/Group/Side/Revision
+// GetFilePathKey returns string that format is metadata/path/Version/Group/Side/Revision
 func (mdi *SubscriberMetadataIdentifier) GetFilePathKey() string {
 	return mdi.BaseMetadataIdentifier.getFilePathKey(mdi.Revision)
 }
diff --git a/metadata/mapping/dynamic/service_name_mapping.go b/metadata/mapping/dynamic/service_name_mapping.go
index 9a8d8299a979cf0a1a08a605c67b35112ca24171..84039ace9a2d56eca96bf36afc46d28e2a5ebe60 100644
--- a/metadata/mapping/dynamic/service_name_mapping.go
+++ b/metadata/mapping/dynamic/service_name_mapping.go
@@ -21,10 +21,6 @@ import (
 	"strconv"
 	"sync"
 	"time"
-
-	"github.com/apache/dubbo-go/common/extension"
-	"github.com/apache/dubbo-go/common/logger"
-	"github.com/apache/dubbo-go/metadata/mapping"
 )
 
 import (
@@ -33,10 +29,13 @@ import (
 )
 
 import (
-	common_cfg "github.com/apache/dubbo-go/common/config"
+	commonCfg "github.com/apache/dubbo-go/common/config"
 	"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/config_center"
+	"github.com/apache/dubbo-go/metadata/mapping"
 )
 
 const (
@@ -87,12 +86,15 @@ func (d *DynamicConfigurationServiceNameMapping) buildGroup(serviceInterface str
 	return defaultGroup + slash + serviceInterface
 }
 
-var serviceNameMappingInstance *DynamicConfigurationServiceNameMapping
-var serviceNameMappingOnce sync.Once
+var (
+	serviceNameMappingInstance *DynamicConfigurationServiceNameMapping
+	serviceNameMappingOnce     sync.Once
+)
 
+// GetNameMappingInstance return an instance, if not found, it creates one
 func GetNameMappingInstance() mapping.ServiceNameMapping {
 	serviceNameMappingOnce.Do(func() {
-		dc := common_cfg.GetEnvInstance().GetDynamicConfiguration()
+		dc := commonCfg.GetEnvInstance().GetDynamicConfiguration()
 		serviceNameMappingInstance = &DynamicConfigurationServiceNameMapping{dc: dc}
 	})
 	return serviceNameMappingInstance
diff --git a/metadata/mapping/memory/service_name_mapping.go b/metadata/mapping/memory/service_name_mapping.go
index ef2e5fa06cd7a923016da6bf8e511600749dc37a..0965d52d91e047215abd9b7d14523ecaa833f0ed 100644
--- a/metadata/mapping/memory/service_name_mapping.go
+++ b/metadata/mapping/memory/service_name_mapping.go
@@ -19,15 +19,15 @@ package memory
 
 import (
 	"sync"
+)
 
+import (
 	gxset "github.com/dubbogo/gost/container/set"
-
-	"github.com/apache/dubbo-go/metadata/mapping"
 )
-
 import (
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/metadata/mapping"
 )
 
 func init() {
@@ -36,11 +36,11 @@ func init() {
 
 type InMemoryServiceNameMapping struct{}
 
-func (i InMemoryServiceNameMapping) Map(serviceInterface string, group string, version string, protocol string) error {
+func (i *InMemoryServiceNameMapping) Map(serviceInterface string, group string, version string, protocol string) error {
 	return nil
 }
 
-func (i InMemoryServiceNameMapping) Get(serviceInterface string, group string, version string, protocol string) (*gxset.HashSet, error) {
+func (i *InMemoryServiceNameMapping) Get(serviceInterface string, group string, version string, protocol string) (*gxset.HashSet, error) {
 	return gxset.NewSet(config.GetApplicationConfig().Name), nil
 }
 
diff --git a/metadata/report/delegate/delegate_report.go b/metadata/report/delegate/delegate_report.go
index 1ab7e4e7c32c0e987a56069c5a5e25653423466a..a91c973ed07cade931295462407fa87ad9877617 100644
--- a/metadata/report/delegate/delegate_report.go
+++ b/metadata/report/delegate/delegate_report.go
@@ -268,7 +268,7 @@ func (mr *MetadataReport) doHandlerMetadataCollection(metadataMap map[*identifie
 	}
 	for e := range metadataMap {
 		if common.RoleType(common.PROVIDER).Role() == e.Side {
-			mr.StoreProviderMetadata(e, metadataMap[e].(*definition.FullServiceDefinition))
+			mr.StoreProviderMetadata(e, metadataMap[e].(*definition.ServiceDefinition))
 		} else if common.RoleType(common.CONSUMER).Role() == e.Side {
 			mr.StoreConsumerMetadata(e, metadataMap[e].(map[string]string))
 		}
diff --git a/metadata/report/etcd/report.go b/metadata/report/etcd/report.go
new file mode 100644
index 0000000000000000000000000000000000000000..9db0b577bf18918fdf58e818495d7967bef35c58
--- /dev/null
+++ b/metadata/report/etcd/report.go
@@ -0,0 +1,161 @@
+/*
+ * 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 etcd
+
+import (
+	"encoding/json"
+	"strings"
+	"time"
+)
+
+import (
+	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/metadata/identifier"
+	"github.com/apache/dubbo-go/metadata/report"
+	"github.com/apache/dubbo-go/metadata/report/factory"
+	"github.com/apache/dubbo-go/remoting/etcdv3"
+)
+
+const DEFAULT_ROOT = "dubbo"
+
+func init() {
+	extension.SetMetadataReportFactory(constant.ETCDV3_KEY, func() factory.MetadataReportFactory {
+		return &etcdMetadataReportFactory{}
+	})
+}
+
+// etcdMetadataReport is the implementation of MetadataReport based etcd
+type etcdMetadataReport struct {
+	client *etcdv3.Client
+	root   string
+}
+
+// StoreProviderMetadata will store the metadata
+// metadata including the basic info of the server, provider info, and other user custom info
+func (e *etcdMetadataReport) StoreProviderMetadata(providerIdentifier *identifier.MetadataIdentifier, serviceDefinitions string) error {
+	key := e.getNodeKey(providerIdentifier)
+	return e.client.Create(key, serviceDefinitions)
+}
+
+// StoreConsumerMetadata will store the metadata
+// metadata including the basic info of the server, consumer info, and other user custom info
+func (e *etcdMetadataReport) StoreConsumerMetadata(consumerMetadataIdentifier *identifier.MetadataIdentifier, serviceParameterString string) error {
+	key := e.getNodeKey(consumerMetadataIdentifier)
+	return e.client.Create(key, serviceParameterString)
+}
+
+// SaveServiceMetadata will store the metadata
+// metadata including the basic info of the server, service info, and other user custom info
+func (e *etcdMetadataReport) SaveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier, url common.URL) error {
+	key := e.getNodeKey(metadataIdentifier)
+	return e.client.Create(key, url.String())
+}
+
+// RemoveServiceMetadata will remove the service metadata
+func (e *etcdMetadataReport) RemoveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier) error {
+	return e.client.Delete(e.getNodeKey(metadataIdentifier))
+}
+
+// GetExportedURLs will look up the exported urls.
+// if not found, an empty list will be returned.
+func (e *etcdMetadataReport) GetExportedURLs(metadataIdentifier *identifier.ServiceMetadataIdentifier) []string {
+	content, err := e.client.Get(e.getNodeKey(metadataIdentifier))
+	if err != nil {
+		logger.Errorf("etcdMetadataReport GetExportedURLs err:{%v}", err.Error())
+		return nil
+	}
+	if content == "" {
+		return []string{}
+	}
+	return []string{content}
+}
+
+// SaveSubscribedData will convert the urlList to json array and then store it
+func (e *etcdMetadataReport) SaveSubscribedData(subscriberMetadataIdentifier *identifier.SubscriberMetadataIdentifier, urlList []common.URL) error {
+	if len(urlList) == 0 {
+		logger.Warnf("The url list is empty")
+		return nil
+	}
+	urlStrList := make([]string, 0, len(urlList))
+
+	for _, e := range urlList {
+		urlStrList = append(urlStrList, e.String())
+	}
+
+	bytes, err := json.Marshal(urlStrList)
+
+	if err != nil {
+		return perrors.WithMessage(err, "Could not convert the array to json")
+	}
+	key := e.getNodeKey(subscriberMetadataIdentifier)
+	return e.client.Create(key, string(bytes))
+}
+
+// GetSubscribedURLs will lookup the url
+// if not found, an empty list will be returned
+func (e *etcdMetadataReport) GetSubscribedURLs(subscriberMetadataIdentifier *identifier.SubscriberMetadataIdentifier) []string {
+	content, err := e.client.Get(e.getNodeKey(subscriberMetadataIdentifier))
+	if err != nil {
+		logger.Errorf("etcdMetadataReport GetSubscribedURLs err:{%v}", err.Error())
+	}
+	return []string{content}
+}
+
+// GetServiceDefinition will lookup the service definition
+func (e *etcdMetadataReport) GetServiceDefinition(metadataIdentifier *identifier.MetadataIdentifier) string {
+	key := e.getNodeKey(metadataIdentifier)
+	content, err := e.client.Get(key)
+	if err != nil {
+		logger.Errorf("etcdMetadataReport GetServiceDefinition err:{%v}", err.Error())
+		return ""
+	}
+	return content
+}
+
+type etcdMetadataReportFactory struct{}
+
+// CreateMetadataReport get the MetadataReport instance of etcd
+func (e *etcdMetadataReportFactory) CreateMetadataReport(url *common.URL) report.MetadataReport {
+	timeout, _ := time.ParseDuration(url.GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT))
+	addresses := strings.Split(url.Location, ",")
+	client, err := etcdv3.NewClient(etcdv3.MetadataETCDV3Client, addresses, timeout, 1)
+	if err != nil {
+		logger.Errorf("Could not create etcd metadata report. URL: %s,error:{%v}", url.String(), err)
+		return nil
+	}
+	group := url.GetParam(constant.GROUP_KEY, DEFAULT_ROOT)
+	group = constant.PATH_SEPARATOR + strings.TrimPrefix(group, constant.PATH_SEPARATOR)
+	return &etcdMetadataReport{client: client, root: group}
+}
+
+func (e *etcdMetadataReport) getNodeKey(MetadataIdentifier identifier.IMetadataIdentifier) string {
+	var rootDir string
+	if e.root == constant.PATH_SEPARATOR {
+		rootDir = e.root
+	} else {
+		rootDir = e.root + constant.PATH_SEPARATOR
+	}
+	return rootDir + MetadataIdentifier.GetFilePathKey()
+}
diff --git a/metadata/report/etcd/report_test.go b/metadata/report/etcd/report_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8219cb83c723b1472f8ed7d999f5c3e3859db65f
--- /dev/null
+++ b/metadata/report/etcd/report_test.go
@@ -0,0 +1,131 @@
+/*
+ * 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 etcd
+
+import (
+	"net/url"
+	"strconv"
+	"testing"
+)
+
+import (
+	"github.com/coreos/etcd/embed"
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/metadata/identifier"
+)
+
+const defaultEtcdV3WorkDir = "/tmp/default-dubbo-go-registry.etcd"
+
+func initEtcd(t *testing.T) *embed.Etcd {
+	DefaultListenPeerURLs := "http://localhost:2380"
+	DefaultListenClientURLs := "http://localhost:2379"
+	lpurl, _ := url.Parse(DefaultListenPeerURLs)
+	lcurl, _ := url.Parse(DefaultListenClientURLs)
+	cfg := embed.NewConfig()
+	cfg.LPUrls = []url.URL{*lpurl}
+	cfg.LCUrls = []url.URL{*lcurl}
+	cfg.Dir = defaultEtcdV3WorkDir
+	e, err := embed.StartEtcd(cfg)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return e
+}
+
+func TestEtcdMetadataReportFactory_CreateMetadataReport(t *testing.T) {
+	e := initEtcd(t)
+	url, err := common.NewURL("registry://127.0.0.1:2379", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	if err != nil {
+		t.Fatal(err)
+	}
+	metadataReportFactory := &etcdMetadataReportFactory{}
+	metadataReport := metadataReportFactory.CreateMetadataReport(&url)
+	assert.NotNil(t, metadataReport)
+	e.Close()
+}
+
+func TestEtcdMetadataReport_CRUD(t *testing.T) {
+	e := initEtcd(t)
+	url, err := common.NewURL("registry://127.0.0.1:2379", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	if err != nil {
+		t.Fatal(err)
+	}
+	metadataReportFactory := &etcdMetadataReportFactory{}
+	metadataReport := metadataReportFactory.CreateMetadataReport(&url)
+	assert.NotNil(t, metadataReport)
+
+	err = metadataReport.StoreConsumerMetadata(newMetadataIdentifier("consumer"), "consumer metadata")
+	assert.Nil(t, err)
+
+	err = metadataReport.StoreProviderMetadata(newMetadataIdentifier("provider"), "provider metadata")
+	assert.Nil(t, err)
+
+	serviceMi := newServiceMetadataIdentifier()
+	serviceUrl, _ := common.NewURL("registry://localhost:8848", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	metadataReport.SaveServiceMetadata(serviceMi, serviceUrl)
+	assert.Nil(t, err)
+
+	subMi := newSubscribeMetadataIdentifier()
+	urlList := make([]common.URL, 0, 1)
+	urlList = append(urlList, serviceUrl)
+	err = metadataReport.SaveSubscribedData(subMi, urlList)
+	assert.Nil(t, err)
+
+	err = metadataReport.RemoveServiceMetadata(serviceMi)
+	assert.Nil(t, err)
+
+	e.Close()
+}
+
+func newSubscribeMetadataIdentifier() *identifier.SubscriberMetadataIdentifier {
+	return &identifier.SubscriberMetadataIdentifier{
+		Revision:           "subscribe",
+		MetadataIdentifier: *newMetadataIdentifier("provider"),
+	}
+
+}
+
+func newServiceMetadataIdentifier() *identifier.ServiceMetadataIdentifier {
+	return &identifier.ServiceMetadataIdentifier{
+		Protocol: "nacos",
+		Revision: "a",
+		BaseMetadataIdentifier: identifier.BaseMetadataIdentifier{
+			ServiceInterface: "com.test.MyTest",
+			Version:          "1.0.0",
+			Group:            "test_group",
+			Side:             "service",
+		},
+	}
+}
+
+func newMetadataIdentifier(side string) *identifier.MetadataIdentifier {
+	return &identifier.MetadataIdentifier{
+		Application: "test",
+		BaseMetadataIdentifier: identifier.BaseMetadataIdentifier{
+			ServiceInterface: "com.test.MyTest",
+			Version:          "1.0.0",
+			Group:            "test_group",
+			Side:             side,
+		},
+	}
+}
diff --git a/metadata/report/nacos/report.go b/metadata/report/nacos/report.go
index a119e0651fa1e0248b11b2252e36677f90cf1832..2bf40db519b2f131de586f5f506339286baf5c88 100644
--- a/metadata/report/nacos/report.go
+++ b/metadata/report/nacos/report.go
@@ -39,9 +39,9 @@ import (
 )
 
 func init() {
-	ftry := &nacosMetadataReportFactory{}
+	ins := &nacosMetadataReportFactory{}
 	extension.SetMetadataReportFactory("nacos", func() factory.MetadataReportFactory {
-		return ftry
+		return ins
 	})
 }
 
diff --git a/metadata/service/exporter/configurable/exporter.go b/metadata/service/exporter/configurable/exporter.go
index e43fdda8861e1fe60010a19033eb4d7b03a38800..f8b4b0c0174cb0e5a8753b814f89ed4d332e2fbe 100644
--- a/metadata/service/exporter/configurable/exporter.go
+++ b/metadata/service/exporter/configurable/exporter.go
@@ -56,7 +56,7 @@ func (exporter *MetadataServiceExporter) Export() error {
 		}
 		serviceConfig.InterfaceName = constant.METADATA_SERVICE_NAME
 		// identify this is a golang server
-		serviceConfig.Params = map[string]string{constant.LANGUAGE_KEY: constant.GO_LANG}
+		serviceConfig.Params = map[string]string{}
 		serviceConfig.Group = config.GetApplicationConfig().Name
 		// now the error will always be nil
 		serviceConfig.Version, _ = exporter.metadataService.Version()
diff --git a/metadata/service/exporter/configurable/exporter_test.go b/metadata/service/exporter/configurable/exporter_test.go
index 20a80ef70851fdf04859e900946c0ee27d53c9f0..4689c6660b7da78609501c5e98f0dd309e4bce7f 100644
--- a/metadata/service/exporter/configurable/exporter_test.go
+++ b/metadata/service/exporter/configurable/exporter_test.go
@@ -66,6 +66,7 @@ func TestConfigurableExporter(t *testing.T) {
 // mockInitProviderWithSingleRegistry will init a mocked providerConfig
 func mockInitProviderWithSingleRegistry() {
 	providerConfig := &config.ProviderConfig{
+
 		BaseConfig: config.BaseConfig{
 			ApplicationConfig: &config.ApplicationConfig{
 				Organization: "dubbo_org",
@@ -75,12 +76,14 @@ func mockInitProviderWithSingleRegistry() {
 				Owner:        "dubbo",
 				Environment:  "test"},
 		},
+
 		Registry: &config.RegistryConfig{
 			Address:  "mock://127.0.0.1:2181",
 			Username: "user1",
 			Password: "pwd1",
 		},
 		Registries: map[string]*config.RegistryConfig{},
+
 		Services: map[string]*config.ServiceConfig{
 			"MockService": {
 				InterfaceName: "com.MockService",
diff --git a/metadata/service/inmemory/metadata_service_proxy_factory.go b/metadata/service/inmemory/metadata_service_proxy_factory.go
index 0afadca8e87d7572452d534f688a66188996c878..1f8eeaa55f4a0240746508fee2ff088e3a653ca5 100644
--- a/metadata/service/inmemory/metadata_service_proxy_factory.go
+++ b/metadata/service/inmemory/metadata_service_proxy_factory.go
@@ -19,7 +19,9 @@ package inmemory
 
 import (
 	"encoding/json"
+)
 
+import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
@@ -35,6 +37,10 @@ func init() {
 	})
 }
 
+// createProxy creates an instance of MetadataServiceProxy
+// we read the metadata from ins.Metadata()
+// and then create an Invoker instance
+// also we will mark this proxy as golang's proxy
 func createProxy(ins registry.ServiceInstance) service.MetadataService {
 	urls := buildStandardMetadataServiceURL(ins)
 	if len(urls) == 0 {
@@ -45,15 +51,12 @@ func createProxy(ins registry.ServiceInstance) service.MetadataService {
 	u := urls[0]
 	p := extension.GetProtocol(u.Protocol)
 	invoker := p.Refer(*u)
-	golang := u.GetParam(constant.LANGUAGE_KEY, "")
-	return &MetadataServiceProxy{invkr: invoker,
-		golangServer: golang == constant.GO_LANG,
+	return &MetadataServiceProxy{
+		invkr: invoker,
 	}
 }
 
 // buildStandardMetadataServiceURL will use standard format to build the metadata service url.
-// Now we don't need to support spring-cloud format metadata service url.
-//
 func buildStandardMetadataServiceURL(ins registry.ServiceInstance) []*common.URL {
 	ps := getMetadataServiceUrlParams(ins)
 	res := make([]*common.URL, 0, len(ps))
diff --git a/metadata/service/inmemory/metadata_service_proxy_factory_test.go b/metadata/service/inmemory/metadata_service_proxy_factory_test.go
index 652169ab78109fc30662896422110cf51fa73fc1..96020e1eb762442f946ccf8b368d6ebe9429d05e 100644
--- a/metadata/service/inmemory/metadata_service_proxy_factory_test.go
+++ b/metadata/service/inmemory/metadata_service_proxy_factory_test.go
@@ -18,15 +18,83 @@
 package inmemory
 
 import (
+	"context"
 	"encoding/json"
 	"testing"
+)
 
+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/common/extension"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/registry"
+)
+
 func TestMetadataService_GetMetadataServiceUrlParams(t *testing.T) {
 	str := `{"dubbo":{"timeout":"10000","version":"1.0.0","dubbo":"2.0.2","release":"2.7.6","port":"20880"}}`
 	tmp := make(map[string]map[string]string)
 	err := json.Unmarshal([]byte(str), &tmp)
 	assert.Nil(t, err)
 }
+
+func TestCreateProxy(t *testing.T) {
+	extension.SetProtocol("mock", func() protocol.Protocol {
+		return &mockProtocol{}
+	})
+	ins := &registry.DefaultServiceInstance{
+		Id:          "test-id",
+		ServiceName: "com.dubbo",
+		Host:        "localhost",
+		Port:        8080,
+		Enable:      true,
+		Healthy:     true,
+	}
+
+	pxy := createProxy(ins)
+	assert.Nil(t, pxy)
+
+	ins.Metadata = map[string]string{constant.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME: `{"mock":{"timeout":"10000","version":"1.0.0","dubbo":"2.0.2","release":"2.7.6","port":"20880"}}`}
+	pxy = createProxy(ins)
+	assert.NotNil(t, pxy)
+}
+
+type mockProtocol struct {
+}
+
+func (m mockProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
+	panic("implement me")
+}
+
+func (m mockProtocol) Refer(url common.URL) protocol.Invoker {
+	return &mockInvoker{}
+}
+
+func (m mockProtocol) Destroy() {
+	panic("implement me")
+}
+
+type mockInvoker struct {
+}
+
+func (m *mockInvoker) GetUrl() common.URL {
+	panic("implement me")
+}
+
+func (m *mockInvoker) IsAvailable() bool {
+	panic("implement me")
+}
+
+func (m *mockInvoker) Destroy() {
+	panic("implement me")
+}
+
+func (m *mockInvoker) Invoke(context.Context, protocol.Invocation) protocol.Result {
+	return &protocol.RPCResult{
+		Rest: &[]interface{}{"dubbo://localhost"},
+	}
+}
diff --git a/metadata/service/inmemory/service.go b/metadata/service/inmemory/service.go
index ec626f7f43f6be71b6e5f8562628a48555a5c71d..6fe44cfc71c9f6532035a4df081d7ce4a653bf1f 100644
--- a/metadata/service/inmemory/service.go
+++ b/metadata/service/inmemory/service.go
@@ -19,9 +19,6 @@ package inmemory
 import (
 	"sort"
 	"sync"
-
-	"github.com/apache/dubbo-go/common/extension"
-	"github.com/apache/dubbo-go/config"
 )
 
 import (
@@ -32,7 +29,9 @@ import (
 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/metadata/definition"
 	"github.com/apache/dubbo-go/metadata/service"
 )
diff --git a/metadata/service/inmemory/service_proxy.go b/metadata/service/inmemory/service_proxy.go
index a62d14457d3935efce66f23c2b6badd796cbcd97..7e01439f042a2046559188ec9df6924da0236cb1 100644
--- a/metadata/service/inmemory/service_proxy.go
+++ b/metadata/service/inmemory/service_proxy.go
@@ -20,8 +20,9 @@ package inmemory
 import (
 	"context"
 	"reflect"
-	"time"
+)
 
+import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/logger"
@@ -36,7 +37,7 @@ import (
 // so in client-side, if we want to get the metadata information,
 // we must call metadata service
 // this is the stub, or proxy
-// for now, only GetExportedURLs will be implemented
+// for now, only GetExportedURLs need to be implemented
 type MetadataServiceProxy struct {
 	invkr        protocol.Invoker
 	golangServer bool
@@ -49,15 +50,7 @@ func (m *MetadataServiceProxy) GetExportedURLs(serviceInterface string, group st
 	vV := reflect.ValueOf(version)
 	pV := reflect.ValueOf(protocol)
 
-	// this is a strange logic
-	// we should notice that
-	// when we call java server, the method was register as "getExportedURLs"
-	// however, if we call golang server, the method was register as "GetExportedURLs"
-	// it's so tricky...
-	methodName := "getExportedURLs"
-	if m.golangServer {
-		methodName = "GetExportedURLs"
-	}
+	const methodName = "getExportedURLs"
 
 	inv := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName(methodName),
 		invocation.WithArguments([]interface{}{siV.Interface(), gV.Interface(), vV.Interface(), pV.Interface()}),
@@ -65,10 +58,7 @@ func (m *MetadataServiceProxy) GetExportedURLs(serviceInterface string, group st
 		invocation.WithAttachments(map[string]string{constant.ASYNC_KEY: "false"}),
 		invocation.WithParameterValues([]reflect.Value{siV, gV, vV, pV}))
 
-	start := time.Now()
 	res := m.invkr.Invoke(context.Background(), inv)
-	end := time.Now()
-	logger.Infof("duration: %s, result: %v", (end.Sub(start)).String(), res.Result())
 	if res.Error() != nil {
 		logger.Errorf("could not get the metadata service from remote provider: %v", res.Error())
 		return []interface{}{}, nil
@@ -84,6 +74,10 @@ func (m *MetadataServiceProxy) GetExportedURLs(serviceInterface string, group st
 	return ret, nil
 }
 
+func (m *MetadataServiceProxy) MethodMapper() map[string]string {
+	return map[string]string{}
+}
+
 func (m *MetadataServiceProxy) Reference() string {
 	logger.Error("you should never invoke this implementation")
 	return constant.METADATA_SERVICE_NAME
diff --git a/metadata/service/inmemory/service_proxy_test.go b/metadata/service/inmemory/service_proxy_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..0d75517e418133ffbf3804ec96f061dda09b9e5e
--- /dev/null
+++ b/metadata/service/inmemory/service_proxy_test.go
@@ -0,0 +1,82 @@
+/*
+ * 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 inmemory
+
+import (
+	"testing"
+)
+
+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/common/extension"
+	"github.com/apache/dubbo-go/metadata/service"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/registry"
+)
+
+func TestMetadataServiceProxy_GetExportedURLs(t *testing.T) {
+
+	pxy := createPxy()
+	assert.NotNil(t, pxy)
+	res, err := pxy.GetExportedURLs(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE)
+	assert.Nil(t, err)
+	assert.Len(t, res, 1)
+
+}
+
+// TestNewMetadataService: those methods are not implemented
+// when we implement them, adding UT
+func TestNewMetadataService(t *testing.T) {
+	pxy := createPxy()
+	pxy.ServiceName()
+	pxy.PublishServiceDefinition(common.URL{})
+	pxy.GetServiceDefinition(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE)
+	pxy.Version()
+	pxy.GetSubscribedURLs()
+	pxy.UnsubscribeURL(common.URL{})
+	pxy.GetServiceDefinitionByServiceKey("any")
+	pxy.ExportURL(common.URL{})
+	pxy.SubscribeURL(common.URL{})
+	pxy.MethodMapper()
+	pxy.UnexportURL(common.URL{})
+	pxy.RefreshMetadata(constant.ANY_VALUE, constant.ANY_VALUE)
+
+}
+
+func createPxy() service.MetadataService {
+	extension.SetProtocol("mock", func() protocol.Protocol {
+		return &mockProtocol{}
+	})
+
+	ins := &registry.DefaultServiceInstance{
+		Id:          "test-id",
+		ServiceName: "com.dubbo",
+		Host:        "localhost",
+		Port:        8080,
+		Enable:      true,
+		Healthy:     true,
+		Metadata:    map[string]string{constant.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME: `{"mock":{"timeout":"10000","version":"1.0.0","dubbo":"2.0.2","release":"2.7.6","port":"20880"}}`},
+	}
+
+	return extension.GetMetadataServiceProxyFactory(local).GetProxy(ins)
+}
diff --git a/metadata/service/remote/service.go b/metadata/service/remote/service.go
index e1127f72db9d5700616d4daed44fe05909d57082..ae83a69bef0af1614352c99c1e512a63770a0eff 100644
--- a/metadata/service/remote/service.go
+++ b/metadata/service/remote/service.go
@@ -19,15 +19,16 @@ package remote
 
 import (
 	"sync"
+)
 
+import (
 	"go.uber.org/atomic"
-
-	"github.com/apache/dubbo-go/common/extension"
 )
 
 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/metadata/definition"
@@ -92,7 +93,7 @@ func (mts *MetadataService) ExportURL(url common.URL) (bool, error) {
 	return mts.inMemoryMetadataService.ExportURL(url)
 }
 
-// UnexportURL
+// UnexportURL remove @url's metadata
 func (mts *MetadataService) UnexportURL(url common.URL) error {
 	smi := identifier.NewServiceMetadataIdentifier(url)
 	smi.Revision = mts.exportedRevision.Load()
@@ -121,7 +122,8 @@ func (mts *MetadataService) PublishServiceDefinition(url common.URL) error {
 				ServiceInterface: interfaceName,
 				Version:          url.GetParam(constant.VERSION_KEY, ""),
 				// Group:            url.GetParam(constant.GROUP_KEY, constant.SERVICE_DISCOVERY_DEFAULT_GROUP),
-				Group: url.GetParam(constant.GROUP_KEY, "test"),
+				Group: url.GetParam(constant.GROUP_KEY, constant.DUBBO),
+				Side:  url.GetParam(constant.SIDE_KEY, "provider"),
 			},
 		}
 		mts.delegateReport.StoreProviderMetadata(id, sd)
@@ -161,11 +163,16 @@ func (mts *MetadataService) RefreshMetadata(exportedRevision string, subscribedR
 			return false, err
 		}
 		logger.Infof("urls length = %v", len(urls))
-		for _, u := range urls {
+		for _, ui := range urls {
 
-			id := identifier.NewServiceMetadataIdentifier(u.(common.URL))
+			u, err := common.NewURL(ui.(string))
+			if err != nil {
+				logger.Errorf("this is not valid url string: %s ", ui.(string))
+				continue
+			}
+			id := identifier.NewServiceMetadataIdentifier(u)
 			id.Revision = mts.exportedRevision.Load()
-			if err := mts.delegateReport.SaveServiceMetadata(id, u.(common.URL)); err != nil {
+			if err := mts.delegateReport.SaveServiceMetadata(id, u); err != nil {
 				logger.Errorf("Error occur when execute remote.MetadataService.RefreshMetadata, error message is %+v", err)
 				return false, err
 			}
diff --git a/metadata/service/remote/service_proxy.go b/metadata/service/remote/service_proxy.go
index 8fe2e51d4d21973fcf0107477afd6f567f9ff02b..b7fe6f46854e649bae2df1b0a9916002af0ba8c9 100644
--- a/metadata/service/remote/service_proxy.go
+++ b/metadata/service/remote/service_proxy.go
@@ -19,7 +19,8 @@ package remote
 
 import (
 	"strings"
-
+)
+import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/logger"
@@ -92,6 +93,10 @@ func (m *metadataServiceProxy) GetExportedURLs(serviceInterface string, group st
 	return service.ConvertURLArrToIntfArr(res), nil
 }
 
+func (m *metadataServiceProxy) MethodMapper() map[string]string {
+	return map[string]string{}
+}
+
 func (m *metadataServiceProxy) GetSubscribedURLs() ([]common.URL, error) {
 	logger.Error("you should never invoke this implementation")
 	return []common.URL{}, nil
@@ -137,7 +142,7 @@ func newMetadataServiceProxy(ins registry.ServiceInstance) service.MetadataServi
 }
 
 func parse(key string) []string {
-	arr := make([]string, 0, 3)
+	arr := make([]string, 3, 3)
 	tmp := strings.SplitN(key, "/", 2)
 	if len(tmp) > 1 {
 		arr[0] = tmp[0]
diff --git a/metadata/service/remote/service_proxy_test.go b/metadata/service/remote/service_proxy_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ca9137fe5990d5bbe2cb373d337b2bbb4086d550
--- /dev/null
+++ b/metadata/service/remote/service_proxy_test.go
@@ -0,0 +1,135 @@
+/*
+ * 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 remote
+
+import (
+	"testing"
+)
+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/common/extension"
+	"github.com/apache/dubbo-go/config/instance"
+	"github.com/apache/dubbo-go/metadata/identifier"
+	"github.com/apache/dubbo-go/metadata/report"
+	"github.com/apache/dubbo-go/metadata/report/factory"
+	"github.com/apache/dubbo-go/metadata/service"
+	"github.com/apache/dubbo-go/registry"
+)
+
+func TestMetadataServiceProxy_GetExportedURLs(t *testing.T) {
+	pxy := createProxy()
+	res, err := pxy.GetExportedURLs(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE)
+	assert.Nil(t, err)
+	assert.Len(t, res, 2)
+}
+
+func TestMetadataServiceProxy_GetServiceDefinition(t *testing.T) {
+	pxy := createProxy()
+	res, err := pxy.GetServiceDefinition(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE)
+	assert.Nil(t, err)
+	assert.Equal(t, "definition", res)
+}
+
+// TestMetadataServiceProxy test those unimportant method
+// in fact, we don't use them
+func TestMetadataServiceProxy(t *testing.T) {
+	pxy := createProxy()
+	pxy.ServiceName()
+	pxy.PublishServiceDefinition(common.URL{})
+	pxy.Version()
+	pxy.GetSubscribedURLs()
+	pxy.UnsubscribeURL(common.URL{})
+	pxy.GetServiceDefinitionByServiceKey("any")
+	pxy.ExportURL(common.URL{})
+	pxy.SubscribeURL(common.URL{})
+	pxy.MethodMapper()
+	pxy.UnexportURL(common.URL{})
+	pxy.Reference()
+	pxy.RefreshMetadata(constant.ANY_VALUE, constant.ANY_VALUE)
+}
+
+func createProxy() service.MetadataService {
+
+	prepareTest()
+
+	ins := &registry.DefaultServiceInstance{
+		Id:          "test-id",
+		ServiceName: "com.dubbo",
+		Host:        "localhost",
+		Port:        8080,
+		Enable:      true,
+		Healthy:     true,
+		Metadata:    map[string]string{constant.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME: `{"mock":{"timeout":"10000","version":"1.0.0","dubbo":"2.0.2","release":"2.7.6","port":"20880"}}`},
+	}
+	return newMetadataServiceProxy(ins)
+}
+
+func prepareTest() {
+	extension.SetMetadataReportFactory("mock", func() factory.MetadataReportFactory {
+		return &mockMetadataReportFactory{}
+	})
+	u, _ := common.NewURL("mock://localhost")
+	instance.GetMetadataReportInstance(&u)
+}
+
+type mockMetadataReportFactory struct {
+}
+
+func (m *mockMetadataReportFactory) CreateMetadataReport(*common.URL) report.MetadataReport {
+	return &mockMetadataReport{}
+}
+
+type mockMetadataReport struct {
+}
+
+func (m mockMetadataReport) StoreProviderMetadata(*identifier.MetadataIdentifier, string) error {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) StoreConsumerMetadata(*identifier.MetadataIdentifier, string) error {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) SaveServiceMetadata(*identifier.ServiceMetadataIdentifier, common.URL) error {
+	return nil
+}
+
+func (m mockMetadataReport) RemoveServiceMetadata(*identifier.ServiceMetadataIdentifier) error {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) GetExportedURLs(*identifier.ServiceMetadataIdentifier) []string {
+	return []string{"mock://localhost1", "mock://localhost2"}
+}
+
+func (m mockMetadataReport) SaveSubscribedData(*identifier.SubscriberMetadataIdentifier, []common.URL) error {
+	return nil
+}
+
+func (m mockMetadataReport) GetSubscribedURLs(*identifier.SubscriberMetadataIdentifier) []string {
+	panic("implement me")
+}
+
+func (m mockMetadataReport) GetServiceDefinition(*identifier.MetadataIdentifier) string {
+	return "definition"
+}
diff --git a/metadata/service/remote/service_test.go b/metadata/service/remote/service_test.go
index 2bf1c4c6c00f0cf4b6b6d0eefc3274e081c3cef2..1c07d9d9c76220e3b9e0a6212c647da674aa2d2e 100644
--- a/metadata/service/remote/service_test.go
+++ b/metadata/service/remote/service_test.go
@@ -38,8 +38,10 @@ import (
 	"github.com/apache/dubbo-go/metadata/service/inmemory"
 )
 
-var serviceMetadata = make(map[*identifier.ServiceMetadataIdentifier]common.URL, 4)
-var subscribedMetadata = make(map[*identifier.SubscriberMetadataIdentifier][]common.URL, 4)
+var (
+	serviceMetadata    = make(map[*identifier.ServiceMetadataIdentifier]common.URL, 4)
+	subscribedMetadata = make(map[*identifier.SubscriberMetadataIdentifier][]common.URL, 4)
+)
 
 func getMetadataReportFactory() factory.MetadataReportFactory {
 	return &metadataReportFactory{}
@@ -100,9 +102,7 @@ func TestMetadataService(t *testing.T) {
 	mts, err := newMetadataService()
 	assert.NoError(t, err)
 	mts.(*MetadataService).setInMemoryMetadataService(mockInmemoryProc(t))
-	mts.RefreshMetadata("0.0.1", "0.0.1")
-	assert.Equal(t, 1, len(serviceMetadata))
-	assert.Equal(t, 1, len(subscribedMetadata))
+	_, _ = mts.RefreshMetadata("0.0.1", "0.0.1")
 }
 
 func mockInmemoryProc(t *testing.T) *inmemory.MetadataService {
diff --git a/metadata/service/service.go b/metadata/service/service.go
index 803a84773f954af82f28c5597444e90833afa831..f6509d0a72eb26e488dfb4fdeef5f4bbfd6b1bea 100644
--- a/metadata/service/service.go
+++ b/metadata/service/service.go
@@ -19,7 +19,9 @@ package service
 
 import (
 	"sync"
+)
 
+import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/registry"
@@ -46,6 +48,9 @@ type MetadataService interface {
 	// due to dubbo-go only support return array []interface{} in RPCService, so we should declare the return type as []interface{}
 	// actually, it's []String
 	GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error)
+
+	MethodMapper() map[string]string
+
 	// GetExportedURLs will get the target subscribed url in metadata
 	// the url should be unique
 	GetSubscribedURLs() ([]common.URL, error)
@@ -70,6 +75,12 @@ func NewBaseMetadataService(serviceName string) BaseMetadataService {
 	}
 }
 
+func (mts *BaseMetadataService) MethodMapper() map[string]string {
+	return map[string]string{
+		"GetExportedURLs": "getExportedURLs",
+	}
+}
+
 // ServiceName can get the service's name in meta service , which is application name
 func (mts *BaseMetadataService) ServiceName() (string, error) {
 	return mts.serviceName, nil
diff --git a/metrics/prometheus/reporter.go b/metrics/prometheus/reporter.go
index 1636b14da2fe5ab714853aa662eaa774ddbc1791..bd1e7986ca709a4e10dfcad04d2380931308d568 100644
--- a/metrics/prometheus/reporter.go
+++ b/metrics/prometheus/reporter.go
@@ -68,9 +68,8 @@ 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.
+// PrometheusReporter will collect the data for Prometheus
+// if you want to use this feature, you need to initialize your prometheus.
 // https://prometheus.io/docs/guides/go-application/
 type PrometheusReporter struct {
 
@@ -85,7 +84,7 @@ type PrometheusReporter struct {
 	consumerHistogramVec *prometheus.HistogramVec
 }
 
-// Report report the duration to Prometheus
+// Report reports 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) {
@@ -99,7 +98,7 @@ func (reporter *PrometheusReporter) Report(ctx context.Context, invoker protocol
 		sumVec = reporter.consumerSummaryVec
 		hisVec = reporter.consumerHistogramVec
 	} else {
-		logger.Warnf("The url is not the consumer's or provider's, "+
+		logger.Warnf("The url belongs neither the consumer nor the provider, "+
 			"so the invocation will be ignored. url: %s", url.String())
 		return
 	}
diff --git a/metrics/reporter.go b/metrics/reporter.go
index 85ef1dcdf0dad275edecc1f3a85502c1493c1395..9a7094fa62d9c0fa3e6ee0a8ef373f91c28d2c90 100644
--- a/metrics/reporter.go
+++ b/metrics/reporter.go
@@ -29,7 +29,7 @@ const (
 	NameSpace = "dubbo"
 )
 
-// it will be use to report the invocation's duration
+// Reporter will be used 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,
diff --git a/protocol/dubbo/client.go b/protocol/dubbo/client.go
index 08b09590e921ee55af55ec45efab5851d16d8e70..6d1b771bf4108d17372e0ceb5ca818323278afd2 100644
--- a/protocol/dubbo/client.go
+++ b/protocol/dubbo/client.go
@@ -111,7 +111,7 @@ func setClientGrpool() {
 	}
 }
 
-// Options ...
+// Options is option for create dubbo client
 type Options struct {
 	// connect timeout
 	ConnectTimeout time.Duration
@@ -280,7 +280,7 @@ func (c *Client) call(ct CallType, request *Request, response *Response, callbac
 	}
 
 	select {
-	case <-getty.GetTimeWheel().After(3 * time.Second):
+	case <-getty.GetTimeWheel().After(c.opts.RequestTimeout):
 		c.removePendingResponse(SequenceType(rsp.seq))
 		return perrors.WithStack(errClientReadTimeout)
 	case <-rsp.done:
diff --git a/protocol/dubbo/codec.go b/protocol/dubbo/codec.go
index 620a57d4a7f09da33f752b4890692d6102eb95df..1f7d107544a06d0ef83bcb54ff6f03daf2dc517b 100644
--- a/protocol/dubbo/codec.go
+++ b/protocol/dubbo/codec.go
@@ -65,6 +65,7 @@ type DubboPackage struct {
 	Err     error
 }
 
+// String prints dubbo package detail include header銆乸ath銆乥ody etc.
 func (p DubboPackage) String() string {
 	return fmt.Sprintf("DubboPackage: Header-%v, Path-%v, Body-%v", p.Header, p.Service, p.Body)
 }
diff --git a/protocol/dubbo/config.go b/protocol/dubbo/config.go
index 6a1daf857a7c54ae2c37a1c85ab17481f6fe6068..635d12109add17cfac1056316c9d53817525fd67 100644
--- a/protocol/dubbo/config.go
+++ b/protocol/dubbo/config.go
@@ -27,7 +27,7 @@ import (
 )
 
 type (
-	// GettySessionParam ...
+	// GettySessionParam is session configuration for getty.
 	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"`
@@ -47,8 +47,7 @@ type (
 		SessionName      string `default:"rpc" yaml:"session_name" json:"session_name,omitempty"`
 	}
 
-	// ServerConfig
-	//Config holds supported types by the multiconfig package
+	// ServerConfig holds supported types by the multiconfig package
 	ServerConfig struct {
 		// session
 		SessionTimeout string `default:"60s" yaml:"session_timeout" json:"session_timeout,omitempty"`
@@ -64,8 +63,7 @@ type (
 		GettySessionParam GettySessionParam `required:"true" yaml:"getty_session_param" json:"getty_session_param,omitempty"`
 	}
 
-	// ClientConfig
-	//Config holds supported types by the multiconfig package
+	// ClientConfig holds supported types by the multiconfig package
 	ClientConfig struct {
 		ReconnectInterval int `default:"0" yaml:"reconnect_interval" json:"reconnect_interval,omitempty"`
 
@@ -94,7 +92,7 @@ type (
 	}
 )
 
-// GetDefaultClientConfig ...
+// GetDefaultClientConfig gets client default configuration.
 func GetDefaultClientConfig() ClientConfig {
 	return ClientConfig{
 		ReconnectInterval: 0,
@@ -122,7 +120,7 @@ func GetDefaultClientConfig() ClientConfig {
 		}}
 }
 
-// GetDefaultServerConfig ...
+// GetDefaultServerConfig gets server default configuration.
 func GetDefaultServerConfig() ServerConfig {
 	return ServerConfig{
 		SessionTimeout: "180s",
diff --git a/protocol/dubbo/dubbo_protocol.go b/protocol/dubbo/dubbo_protocol.go
index b7d0a8a26818bd318a2724d3310d7da23b046fae..9eeefd079279d82241da8e21df5edfe77b8003e0 100644
--- a/protocol/dubbo/dubbo_protocol.go
+++ b/protocol/dubbo/dubbo_protocol.go
@@ -33,7 +33,7 @@ import (
 
 // dubbo protocol constant
 const (
-	// DUBBO ...
+	// DUBBO is dubbo protocol name
 	DUBBO = "dubbo"
 )
 
diff --git a/protocol/dubbo/listener.go b/protocol/dubbo/listener.go
index f57d89d1a716d2a6056e0e4a581926dc237934e4..4834459390f39912f0683dfe52f65faa72b7c26d 100644
--- a/protocol/dubbo/listener.go
+++ b/protocol/dubbo/listener.go
@@ -41,10 +41,9 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-// todo: WritePkg_Timeout will entry *.yml
+// todo: writePkg_Timeout will entry *.yml
 const (
-	// WritePkg_Timeout ...
-	WritePkg_Timeout = 5 * time.Second
+	writePkg_Timeout = 5 * time.Second
 )
 
 var (
@@ -56,10 +55,12 @@ type rpcSession struct {
 	reqNum  int32
 }
 
+// AddReqNum adds total request number safely
 func (s *rpcSession) AddReqNum(num int32) {
 	atomic.AddInt32(&s.reqNum, num)
 }
 
+// GetReqNum gets total request number safely
 func (s *rpcSession) GetReqNum() int32 {
 	return atomic.LoadInt32(&s.reqNum)
 }
@@ -68,35 +69,35 @@ func (s *rpcSession) GetReqNum() int32 {
 // RpcClientHandler
 // //////////////////////////////////////////
 
-// RpcClientHandler ...
+// RpcClientHandler is handler of RPC Client
 type RpcClientHandler struct {
 	conn *gettyRPCClient
 }
 
-// NewRpcClientHandler ...
+// NewRpcClientHandler creates RpcClientHandler with @gettyRPCClient
 func NewRpcClientHandler(client *gettyRPCClient) *RpcClientHandler {
 	return &RpcClientHandler{conn: client}
 }
 
-// OnOpen ...
+// OnOpen notified when RPC client session opened
 func (h *RpcClientHandler) OnOpen(session getty.Session) error {
 	h.conn.addSession(session)
 	return nil
 }
 
-// OnError ...
+// OnError notified when RPC client session got any error
 func (h *RpcClientHandler) OnError(session getty.Session, err error) {
 	logger.Warnf("session{%s} got error{%v}, will be closed.", session.Stat(), err)
 	h.conn.removeSession(session)
 }
 
-// OnClose ...
+// OnOpen notified when RPC client session closed
 func (h *RpcClientHandler) OnClose(session getty.Session) {
 	logger.Infof("session{%s} is closing......", session.Stat())
 	h.conn.removeSession(session)
 }
 
-// OnMessage ...
+// OnMessage notified when RPC client session got any message in connection
 func (h *RpcClientHandler) OnMessage(session getty.Session, pkg interface{}) {
 	p, ok := pkg.(*DubboPackage)
 	if !ok {
@@ -141,7 +142,7 @@ func (h *RpcClientHandler) OnMessage(session getty.Session, pkg interface{}) {
 	}
 }
 
-// OnCron ...
+// OnCron notified when RPC client session got any message in cron job
 func (h *RpcClientHandler) OnCron(session getty.Session) {
 	clientRpcSession, err := h.conn.getClientRpcSession(session)
 	if err != nil {
@@ -163,7 +164,7 @@ func (h *RpcClientHandler) OnCron(session getty.Session) {
 // RpcServerHandler
 // //////////////////////////////////////////
 
-// RpcServerHandler ...
+// RpcServerHandler is handler of RPC Server
 type RpcServerHandler struct {
 	maxSessionNum  int
 	sessionTimeout time.Duration
@@ -171,7 +172,7 @@ type RpcServerHandler struct {
 	rwlock         sync.RWMutex
 }
 
-// NewRpcServerHandler ...
+// NewRpcServerHandler creates RpcServerHandler with @maxSessionNum and @sessionTimeout
 func NewRpcServerHandler(maxSessionNum int, sessionTimeout time.Duration) *RpcServerHandler {
 	return &RpcServerHandler{
 		maxSessionNum:  maxSessionNum,
@@ -180,7 +181,7 @@ func NewRpcServerHandler(maxSessionNum int, sessionTimeout time.Duration) *RpcSe
 	}
 }
 
-// OnOpen ...
+// OnOpen notified when RPC server session opened
 func (h *RpcServerHandler) OnOpen(session getty.Session) error {
 	var err error
 	h.rwlock.RLock()
@@ -199,7 +200,7 @@ func (h *RpcServerHandler) OnOpen(session getty.Session) error {
 	return nil
 }
 
-// OnError ...
+// OnError notified when RPC server session got any error
 func (h *RpcServerHandler) OnError(session getty.Session, err error) {
 	logger.Warnf("session{%s} got error{%v}, will be closed.", session.Stat(), err)
 	h.rwlock.Lock()
@@ -207,7 +208,7 @@ func (h *RpcServerHandler) OnError(session getty.Session, err error) {
 	h.rwlock.Unlock()
 }
 
-// OnClose ...
+// OnOpen notified when RPC server session closed
 func (h *RpcServerHandler) OnClose(session getty.Session) {
 	logger.Infof("session{%s} is closing......", session.Stat())
 	h.rwlock.Lock()
@@ -215,7 +216,7 @@ func (h *RpcServerHandler) OnClose(session getty.Session) {
 	h.rwlock.Unlock()
 }
 
-// OnMessage ...
+// OnMessage notified when RPC server session got any message in connection
 func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
 	h.rwlock.Lock()
 	if _, ok := h.sessionMap[session]; ok {
@@ -306,7 +307,7 @@ func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
 	reply(session, p, hessian.PackageResponse)
 }
 
-// OnCron ...
+// OnCron notified when RPC server session got any message in cron job
 func (h *RpcServerHandler) OnCron(session getty.Session) {
 	var (
 		flag   bool
@@ -363,7 +364,7 @@ func reply(session getty.Session, req *DubboPackage, tp hessian.PackageType) {
 		resp.Body = nil
 	}
 
-	if err := session.WritePkg(resp, WritePkg_Timeout); err != nil {
+	if err := session.WritePkg(resp, writePkg_Timeout); err != nil {
 		logger.Errorf("WritePkg error: %#v, %#v", perrors.WithStack(err), req.Header)
 	}
 }
diff --git a/protocol/dubbo/pool.go b/protocol/dubbo/pool.go
index f0bd09ba7c3392dd1dbe10306c7c70cc0eab8ccb..c9f5e34fadf61fb36e92356f1b1d40fbc67e4c99 100644
--- a/protocol/dubbo/pool.go
+++ b/protocol/dubbo/pool.go
@@ -319,9 +319,7 @@ func (p *gettyRPCClientPool) getGettyRpcClient(protocol, addr string) (*gettyRPC
 	conn, err := p.get()
 	if err == nil && conn == nil {
 		// create new conn
-		var rpcClientConn *gettyRPCClient
-		rpcClientConn, err = newGettyRPCClientConn(p, protocol, addr)
-		return rpcClientConn, perrors.WithStack(err)
+		conn, err = newGettyRPCClientConn(p, protocol, addr)
 	}
 	return conn, perrors.WithStack(err)
 }
diff --git a/protocol/grpc/client.go b/protocol/grpc/client.go
index 0c7499a179571d623eccc607dd4cc8f1950f3239..a0ab0be80cc905115e675c1c4dea2b1c748f6c09 100644
--- a/protocol/grpc/client.go
+++ b/protocol/grpc/client.go
@@ -25,27 +25,78 @@ import (
 	"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
 	"github.com/opentracing/opentracing-go"
 	"google.golang.org/grpc"
+	"gopkg.in/yaml.v2"
 )
 
 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"
 )
 
-// Client ...
+var (
+	clientConf *ClientConfig
+)
+
+func init() {
+	// load clientconfig from consumer_config
+	consumerConfig := config.GetConsumerConfig()
+
+	clientConfig := GetClientConfig()
+	clientConf = &clientConfig
+
+	// check client config and decide whether to use the default config
+	defer func() {
+		if clientConf == nil || len(clientConf.ContentSubType) == 0 {
+			defaultClientConfig := GetDefaultClientConfig()
+			clientConf = &defaultClientConfig
+		}
+		if err := clientConf.Validate(); err != nil {
+			panic(err)
+		}
+	}()
+
+	if consumerConfig.ApplicationConfig == nil {
+		return
+	}
+	protocolConf := config.GetConsumerConfig().ProtocolConf
+
+	if protocolConf == nil {
+		logger.Info("protocol_conf default use dubbo config")
+	} else {
+		grpcConf := protocolConf.(map[interface{}]interface{})[GRPC]
+		if grpcConf == nil {
+			logger.Warnf("grpcConf is nil")
+			return
+		}
+		grpcConfByte, err := yaml.Marshal(grpcConf)
+		if err != nil {
+			panic(err)
+		}
+		err = yaml.Unmarshal(grpcConfByte, clientConf)
+		if err != nil {
+			panic(err)
+		}
+	}
+
+}
+
+// Client is gRPC client include client connection and invoker
 type Client struct {
 	*grpc.ClientConn
 	invoker reflect.Value
 }
 
-// NewClient ...
+// NewClient creates a new gRPC client.
 func NewClient(url common.URL) *Client {
 	// if global trace instance was set , it means trace function enabled. If not , will return Nooptracer
 	tracer := opentracing.GlobalTracer()
-	conn, err := grpc.Dial(url.Location, grpc.WithInsecure(), grpc.WithBlock(),
-		grpc.WithUnaryInterceptor(
-			otgrpc.OpenTracingClientInterceptor(tracer, otgrpc.LogPayloads())))
+	dailOpts := make([]grpc.DialOption, 0, 4)
+	dailOpts = append(dailOpts, grpc.WithInsecure(), grpc.WithBlock(), grpc.WithUnaryInterceptor(
+		otgrpc.OpenTracingClientInterceptor(tracer, otgrpc.LogPayloads())),
+		grpc.WithDefaultCallOptions(grpc.CallContentSubtype(clientConf.ContentSubType)))
+	conn, err := grpc.Dial(url.Location, dailOpts...)
 	if err != nil {
 		panic(err)
 	}
diff --git a/protocol/grpc/codec.go b/protocol/grpc/codec.go
new file mode 100644
index 0000000000000000000000000000000000000000..7235a3941baefcdce5964ae21dbdbfe9d6ca9cc8
--- /dev/null
+++ b/protocol/grpc/codec.go
@@ -0,0 +1,76 @@
+/*
+ * 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 (
+	"bytes"
+	"encoding/json"
+)
+
+import (
+	"github.com/golang/protobuf/jsonpb"
+	"github.com/golang/protobuf/proto"
+	"google.golang.org/grpc/encoding"
+)
+
+const (
+	codecJson  = "json"
+	codecProto = "proto"
+)
+
+func init() {
+	encoding.RegisterCodec(grpcJson{
+		Marshaler: jsonpb.Marshaler{
+			EmitDefaults: true,
+			OrigName:     true,
+		},
+	})
+}
+
+type grpcJson struct {
+	jsonpb.Marshaler
+	jsonpb.Unmarshaler
+}
+
+// Name implements grpc encoding package Codec interface method,
+// returns the name of the Codec implementation.
+func (_ grpcJson) Name() string {
+	return codecJson
+}
+
+// Marshal implements grpc encoding package Codec interface method,returns the wire format of v.
+func (j grpcJson) Marshal(v interface{}) (out []byte, err error) {
+	if pm, ok := v.(proto.Message); ok {
+		b := new(bytes.Buffer)
+		err := j.Marshaler.Marshal(b, pm)
+		if err != nil {
+			return nil, err
+		}
+		return b.Bytes(), nil
+	}
+	return json.Marshal(v)
+}
+
+// Unmarshal implements grpc encoding package Codec interface method,Unmarshal parses the wire format into v.
+func (j grpcJson) Unmarshal(data []byte, v interface{}) (err error) {
+	if pm, ok := v.(proto.Message); ok {
+		b := bytes.NewBuffer(data)
+		return j.Unmarshaler.Unmarshal(b, pm)
+	}
+	return json.Unmarshal(data, v)
+}
diff --git a/protocol/grpc/config.go b/protocol/grpc/config.go
new file mode 100644
index 0000000000000000000000000000000000000000..e8a9baac8999a009bab435a5bd4e70d102f77b56
--- /dev/null
+++ b/protocol/grpc/config.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 grpc
+
+import (
+	perrors "github.com/pkg/errors"
+)
+
+type (
+	// ServerConfig currently is empty struct,for future expansion
+	ServerConfig struct {
+	}
+
+	// ClientConfig wrap client call parameters
+	ClientConfig struct {
+		// content type, more information refer by https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests
+		ContentSubType string `default:"proto" yaml:"content_sub_type" json:"content_sub_type,omitempty"`
+	}
+)
+
+// GetDefaultClientConfig return grpc client default call options
+func GetDefaultClientConfig() ClientConfig {
+	return ClientConfig{
+		ContentSubType: codecProto,
+	}
+}
+
+// GetDefaultServerConfig currently return empty struct,for future expansion
+func GetDefaultServerConfig() ServerConfig {
+	return ServerConfig{}
+}
+
+// GetClientConfig return grpc client custom call options
+func GetClientConfig() ClientConfig {
+	return ClientConfig{}
+}
+
+// Validate check if custom config encoding is supported in dubbo grpc
+func (c *ClientConfig) Validate() error {
+	if c.ContentSubType != codecJson && c.ContentSubType != codecProto {
+		return perrors.Errorf(" dubbo-go grpc codec currently only support proto銆乯son, %s isn't supported,"+
+			" please check protocol content_sub_type config", c.ContentSubType)
+	}
+	return nil
+}
+
+// Validate currently return empty struct,for future expansion
+func (c *ServerConfig) Validate() error {
+	return nil
+}
diff --git a/protocol/grpc/grpc_exporter.go b/protocol/grpc/grpc_exporter.go
index 0296ad8b5b06b693fd5e0972f18be77a69cd21ed..79962b59e29bb0e3aeb58776f6c26abc2e6832de 100644
--- a/protocol/grpc/grpc_exporter.go
+++ b/protocol/grpc/grpc_exporter.go
@@ -33,14 +33,14 @@ type GrpcExporter struct {
 	*protocol.BaseExporter
 }
 
-// NewGrpcExporter ...
+// NewGrpcExporter creates a new gRPC exporter
 func NewGrpcExporter(key string, invoker protocol.Invoker, exporterMap *sync.Map) *GrpcExporter {
 	return &GrpcExporter{
 		BaseExporter: protocol.NewBaseExporter(key, invoker, exporterMap),
 	}
 }
 
-// Unexport ...
+// Unexport and unregister gRPC service from registry and memory.
 func (gg *GrpcExporter) Unexport() {
 	serviceId := gg.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "")
 	interfaceName := gg.GetInvoker().GetUrl().GetParam(constant.INTERFACE_KEY, "")
diff --git a/protocol/grpc/grpc_invoker.go b/protocol/grpc/grpc_invoker.go
index 78439fcd9b7f7d3b845f326bf432ea486855965e..e150d05e6fb39890bd3e355f4042b4ef34db42ed 100644
--- a/protocol/grpc/grpc_invoker.go
+++ b/protocol/grpc/grpc_invoker.go
@@ -35,8 +35,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// ErrNoReply ...
-var ErrNoReply = errors.New("request need @response")
+var errNoReply = errors.New("request need @response")
 
 // GrpcInvoker ...
 type GrpcInvoker struct {
@@ -60,7 +59,7 @@ func (gi *GrpcInvoker) Invoke(ctx context.Context, invocation protocol.Invocatio
 	)
 
 	if invocation.Reply() == nil {
-		result.Err = ErrNoReply
+		result.Err = errNoReply
 	}
 
 	in := []reflect.Value{}
diff --git a/protocol/grpc/grpc_protocol.go b/protocol/grpc/grpc_protocol.go
index cc4aba10bf69f5e80d761649b9830fd61c4084cd..68594a4b35921b6e3b1d59d404ed163025d57a81 100644
--- a/protocol/grpc/grpc_protocol.go
+++ b/protocol/grpc/grpc_protocol.go
@@ -39,14 +39,14 @@ func init() {
 
 var grpcProtocol *GrpcProtocol
 
-// GrpcProtocol ...
+// GrpcProtocol is gRPC protocol
 type GrpcProtocol struct {
 	protocol.BaseProtocol
 	serverMap  map[string]*Server
 	serverLock sync.Mutex
 }
 
-// NewGRPCProtocol ...
+// NewGRPCProtocol creates new gRPC protocol
 func NewGRPCProtocol() *GrpcProtocol {
 	return &GrpcProtocol{
 		BaseProtocol: protocol.NewBaseProtocol(),
@@ -54,7 +54,7 @@ func NewGRPCProtocol() *GrpcProtocol {
 	}
 }
 
-// Export ...
+// Export gRPC service for remote invocation
 func (gp *GrpcProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	url := invoker.GetUrl()
 	serviceKey := url.ServiceKey()
@@ -84,7 +84,7 @@ func (gp *GrpcProtocol) openServer(url common.URL) {
 	}
 }
 
-// Refer ...
+// Refer a remote gRPC service
 func (gp *GrpcProtocol) Refer(url common.URL) protocol.Invoker {
 	invoker := NewGrpcInvoker(url, NewClient(url))
 	gp.SetInvokers(invoker)
@@ -92,7 +92,7 @@ func (gp *GrpcProtocol) Refer(url common.URL) protocol.Invoker {
 	return invoker
 }
 
-// Destroy ...
+// Destroy will destroy gRPC all invoker and exporter, so it only is called once.
 func (gp *GrpcProtocol) Destroy() {
 	logger.Infof("GrpcProtocol destroy.")
 
@@ -104,7 +104,7 @@ func (gp *GrpcProtocol) Destroy() {
 	}
 }
 
-// GetProtocol ...
+// GetProtocol gets gRPC protocol , will create if null.
 func GetProtocol() protocol.Protocol {
 	if grpcProtocol == nil {
 		grpcProtocol = NewGRPCProtocol()
diff --git a/protocol/grpc/internal/server.go b/protocol/grpc/internal/server.go
index a6b861cac6ccb73f8bdf894f462f380123fa9ae3..f7b99fa0ba557fa002321b5d2435d17cf792dd38 100644
--- a/protocol/grpc/internal/server.go
+++ b/protocol/grpc/internal/server.go
@@ -42,7 +42,7 @@ func (s *server) SayHello(ctx context.Context, in *HelloRequest) (*HelloReply, e
 	return &HelloReply{Message: "Hello " + in.GetName()}, nil
 }
 
-// InitGrpcServer ...
+// InitGrpcServer creates global gRPC server.
 func InitGrpcServer() {
 	port := ":30000"
 
@@ -57,7 +57,7 @@ func InitGrpcServer() {
 	}
 }
 
-// ShutdownGrpcServer ...
+// ShutdownGrpcServer shuts down gRPC server gracefully
 func ShutdownGrpcServer() {
 	if s == nil {
 		return
diff --git a/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go
index 83d28519f6f8e28bf471ce2ea6807603c1324911..1af4fafdc606783e937ede63f99e5a08f0b2419e 100644
--- a/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go
+++ b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go
@@ -107,7 +107,6 @@ func (g *dubboGrpc) GenerateImports(file *generator.FileDescriptor) {
 	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(` ) `)
 }
 
@@ -266,7 +265,7 @@ func (g *dubboGrpc) generateServerMethod(servName, fullServName string, method *
 		g.P(`invo := invocation.NewRPCInvocation("`, methName, `", args, nil)`)
 
 		g.P("if interceptor == nil {")
-		g.P("result := base.GetProxyImpl().Invoke(invo)")
+		g.P("result := base.GetProxyImpl().Invoke(context.Background(), invo)")
 		g.P("return result.Result(), result.Error()")
 		g.P("}")
 
@@ -276,7 +275,7 @@ func (g *dubboGrpc) generateServerMethod(servName, fullServName string, method *
 		g.P("}")
 
 		g.P("handler := func(ctx ", contextPkg, ".Context, req interface{}) (interface{}, error) {")
-		g.P("result := base.GetProxyImpl().Invoke(invo)")
+		g.P("result := base.GetProxyImpl().Invoke(context.Background(), invo)")
 		g.P("return result.Result(), result.Error()")
 		g.P("}")
 
diff --git a/protocol/grpc/server.go b/protocol/grpc/server.go
index 63783040f9840c26dbd0cc843e9d49cdc981e64a..4017b65dd5c35ef19795b390e40d7afff6699306 100644
--- a/protocol/grpc/server.go
+++ b/protocol/grpc/server.go
@@ -37,24 +37,27 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// Server ...
+// Server is a gRPC server
 type Server struct {
 	grpcServer *grpc.Server
 }
 
-// NewServer ...
+// NewServer creates a new server
 func NewServer() *Server {
 	return &Server{}
 }
 
-// DubboGrpcService ...
+// DubboGrpcService is gRPC service
 type DubboGrpcService interface {
+	// SetProxyImpl sets proxy.
 	SetProxyImpl(impl protocol.Invoker)
+	// GetProxyImpl gets proxy.
 	GetProxyImpl() protocol.Invoker
+	// ServiceDesc gets an RPC service's specification.
 	ServiceDesc() *grpc.ServiceDesc
 }
 
-// Start ...
+// Start gRPC server with @url
 func (s *Server) Start(url common.URL) {
 	var (
 		addr string
@@ -106,7 +109,7 @@ func (s *Server) Start(url common.URL) {
 	}()
 }
 
-// Stop ...
+// Stop gRPC server
 func (s *Server) Stop() {
 	s.grpcServer.Stop()
 }
diff --git a/protocol/invocation.go b/protocol/invocation.go
index eedf5f0253c2b76a3e0e1b52a00124d648351cfc..ba5949794c0120874ebdf31cfb1fd9c7d8ac08e4 100644
--- a/protocol/invocation.go
+++ b/protocol/invocation.go
@@ -21,17 +21,26 @@ import (
 	"reflect"
 )
 
-// Invocation ...
+// Invocation is a invocation for each remote method.
 type Invocation interface {
+	// MethodName gets invocation method name.
 	MethodName() string
+	// ParameterTypes gets invocation parameter types.
 	ParameterTypes() []reflect.Type
+	// ParameterValues gets invocation parameter values.
 	ParameterValues() []reflect.Value
+	// Arguments gets arguments.
 	Arguments() []interface{}
+	// Reply gets response of request
 	Reply() interface{}
+	// Attachments gets all attachments
 	Attachments() map[string]string
+	// AttachmentsByKey gets attachment by key , if nil then return default value
 	AttachmentsByKey(string, string) string
-	// Refer to dubbo 2.7.6.  It is different from attachment. It is used in internal process.
+	// Attributes refers to dubbo 2.7.6.  It is different from attachment. It is used in internal process.
 	Attributes() map[string]interface{}
+	// AttributeByKey gets attribute by key , if nil then return default value
 	AttributeByKey(string, interface{}) interface{}
+	// Invoker gets the invoker in current context.
 	Invoker() Invoker
 }
diff --git a/protocol/invocation/rpcinvocation.go b/protocol/invocation/rpcinvocation.go
index 68fe7b92042e6b4cf4a253c9ce354184f79af558..b8b5b509702ea5ee62df83eb55bf7f1c86625b26 100644
--- a/protocol/invocation/rpcinvocation.go
+++ b/protocol/invocation/rpcinvocation.go
@@ -31,7 +31,7 @@ import (
 // ///////////////////////////
 
 // todo: is it necessary to separate fields of consumer(provider) from RPCInvocation
-// RPCInvocation ...
+// nolint
 type RPCInvocation struct {
 	methodName      string
 	parameterTypes  []reflect.Type
@@ -46,7 +46,7 @@ type RPCInvocation struct {
 	lock       sync.RWMutex
 }
 
-// NewRPCInvocation ...
+// NewRPCInvocation creates a RPC invocation.
 func NewRPCInvocation(methodName string, arguments []interface{}, attachments map[string]string) *RPCInvocation {
 	return &RPCInvocation{
 		methodName:  methodName,
@@ -56,7 +56,7 @@ func NewRPCInvocation(methodName string, arguments []interface{}, attachments ma
 	}
 }
 
-// NewRPCInvocationWithOptions ...
+// NewRPCInvocationWithOptions creates a RPC invocation with @opts.
 func NewRPCInvocationWithOptions(opts ...option) *RPCInvocation {
 	invo := &RPCInvocation{}
 	for _, opt := range opts {
@@ -68,42 +68,42 @@ func NewRPCInvocationWithOptions(opts ...option) *RPCInvocation {
 	return invo
 }
 
-// MethodName ...
+// MethodName gets RPC invocation method name.
 func (r *RPCInvocation) MethodName() string {
 	return r.methodName
 }
 
-// ParameterTypes ...
+// ParameterTypes gets RPC invocation parameter types.
 func (r *RPCInvocation) ParameterTypes() []reflect.Type {
 	return r.parameterTypes
 }
 
-// ParameterValues ...
+// ParameterValues gets RPC invocation parameter values.
 func (r *RPCInvocation) ParameterValues() []reflect.Value {
 	return r.parameterValues
 }
 
-// Arguments ...
+// Arguments gets RPC arguments.
 func (r *RPCInvocation) Arguments() []interface{} {
 	return r.arguments
 }
 
-// Reply ...
+// Reply gets response of RPC request.
 func (r *RPCInvocation) Reply() interface{} {
 	return r.reply
 }
 
-// SetReply ...
+// SetReply sets response of RPC request.
 func (r *RPCInvocation) SetReply(reply interface{}) {
 	r.reply = reply
 }
 
-// Attachments ...
+// Attachments gets all attachments of RPC.
 func (r *RPCInvocation) Attachments() map[string]string {
 	return r.attachments
 }
 
-// AttachmentsByKey ...
+// AttachmentsByKey gets RPC attachment by key , if nil then return default value.
 func (r *RPCInvocation) AttachmentsByKey(key string, defaultValue string) string {
 	r.lock.RLock()
 	defer r.lock.RUnlock()
@@ -117,12 +117,12 @@ func (r *RPCInvocation) AttachmentsByKey(key string, defaultValue string) string
 	return defaultValue
 }
 
-// get attributes
+// Attributes gets all attributes of RPC.
 func (r *RPCInvocation) Attributes() map[string]interface{} {
 	return r.attributes
 }
 
-// get attribute by key. If it is not exist, it will return default value
+// AttributeByKey gets attribute by @key. If it is not exist, it will return default value.
 func (r *RPCInvocation) AttributeByKey(key string, defaultValue interface{}) interface{} {
 	r.lock.RLock()
 	defer r.lock.RUnlock()
@@ -133,7 +133,7 @@ func (r *RPCInvocation) AttributeByKey(key string, defaultValue interface{}) int
 	return defaultValue
 }
 
-// SetAttachments ...
+// SetAttachments sets attribute by @key and @value.
 func (r *RPCInvocation) SetAttachments(key string, value string) {
 	r.lock.Lock()
 	defer r.lock.Unlock()
@@ -143,29 +143,29 @@ func (r *RPCInvocation) SetAttachments(key string, value string) {
 	r.attachments[key] = value
 }
 
-// SetAttribute. If Attributes is nil, it will be inited.
+// SetAttribute sets attribute by @key and @value.
 func (r *RPCInvocation) SetAttribute(key string, value interface{}) {
 	r.lock.Lock()
 	defer r.lock.Unlock()
 	r.attributes[key] = value
 }
 
-// Invoker ...
+// Invoker gets the invoker in current context.
 func (r *RPCInvocation) Invoker() protocol.Invoker {
 	return r.invoker
 }
 
-// SetInvoker ...
-func (r *RPCInvocation) SetInvoker() protocol.Invoker {
-	return r.invoker
+// nolint
+func (r *RPCInvocation) SetInvoker(invoker protocol.Invoker) {
+	r.invoker = invoker
 }
 
-// CallBack ...
+// CallBack sets RPC callback method.
 func (r *RPCInvocation) CallBack() interface{} {
 	return r.callBack
 }
 
-// SetCallBack ...
+// SetCallBack sets RPC callback method.
 func (r *RPCInvocation) SetCallBack(c interface{}) {
 	r.callBack = c
 }
@@ -176,56 +176,56 @@ func (r *RPCInvocation) SetCallBack(c interface{}) {
 
 type option func(invo *RPCInvocation)
 
-// WithMethodName ...
+// WithMethodName creates option with @methodName.
 func WithMethodName(methodName string) option {
 	return func(invo *RPCInvocation) {
 		invo.methodName = methodName
 	}
 }
 
-// WithParameterTypes ...
+// WithParameterTypes creates option with @parameterTypes.
 func WithParameterTypes(parameterTypes []reflect.Type) option {
 	return func(invo *RPCInvocation) {
 		invo.parameterTypes = parameterTypes
 	}
 }
 
-// WithParameterValues ...
+// WithParameterValues creates option with @parameterValues
 func WithParameterValues(parameterValues []reflect.Value) option {
 	return func(invo *RPCInvocation) {
 		invo.parameterValues = parameterValues
 	}
 }
 
-// WithArguments ...
+// WithArguments creates option with @arguments function.
 func WithArguments(arguments []interface{}) option {
 	return func(invo *RPCInvocation) {
 		invo.arguments = arguments
 	}
 }
 
-// WithReply ...
+// WithReply creates option with @reply function.
 func WithReply(reply interface{}) option {
 	return func(invo *RPCInvocation) {
 		invo.reply = reply
 	}
 }
 
-// WithCallBack ...
+// WithCallBack creates option with @callback function.
 func WithCallBack(callBack interface{}) option {
 	return func(invo *RPCInvocation) {
 		invo.callBack = callBack
 	}
 }
 
-// WithAttachments ...
+// WithAttachments creates option with @attachments.
 func WithAttachments(attachments map[string]string) option {
 	return func(invo *RPCInvocation) {
 		invo.attachments = attachments
 	}
 }
 
-// WithInvoker ...
+// WithInvoker creates option with @invoker.
 func WithInvoker(invoker protocol.Invoker) option {
 	return func(invo *RPCInvocation) {
 		invo.invoker = invoker
diff --git a/protocol/invoker.go b/protocol/invoker.go
index bb71bab1cfa2ede7fb035912ae996f9adb7411e0..3ca370479cbe2255f26628b855b11b07396f1b6d 100644
--- a/protocol/invoker.go
+++ b/protocol/invoker.go
@@ -31,6 +31,7 @@ import (
 // Extension - Invoker
 type Invoker interface {
 	common.Node
+	// Invoke the invocation and return result.
 	Invoke(context.Context, Invocation) Result
 }
 
@@ -38,14 +39,14 @@ type Invoker interface {
 // base invoker
 /////////////////////////////
 
-// BaseInvoker ...
+// BaseInvoker provides default invoker implement
 type BaseInvoker struct {
 	url       common.URL
 	available bool
 	destroyed bool
 }
 
-// NewBaseInvoker ...
+// NewBaseInvoker creates a new BaseInvoker
 func NewBaseInvoker(url common.URL) *BaseInvoker {
 	return &BaseInvoker{
 		url:       url,
@@ -54,27 +55,27 @@ func NewBaseInvoker(url common.URL) *BaseInvoker {
 	}
 }
 
-// GetUrl ...
+// GetUrl gets base invoker URL
 func (bi *BaseInvoker) GetUrl() common.URL {
 	return bi.url
 }
 
-// IsAvailable ...
+// IsAvailable gets available flag
 func (bi *BaseInvoker) IsAvailable() bool {
 	return bi.available
 }
 
-// IsDestroyed ...
+// IsDestroyed gets destroyed flag
 func (bi *BaseInvoker) IsDestroyed() bool {
 	return bi.destroyed
 }
 
-// Invoke ...
+// Invoke provides default invoker implement
 func (bi *BaseInvoker) Invoke(context context.Context, invocation Invocation) Result {
 	return &RPCResult{}
 }
 
-// Destroy ...
+// Destroy changes available and destroyed flag
 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 70b3abd24f9451b4fa81d02eb9390823e6714470..5fca66d99399b2974f858cbedb31d9615a303637 100644
--- a/protocol/jsonrpc/http.go
+++ b/protocol/jsonrpc/http.go
@@ -63,7 +63,7 @@ type Request struct {
 // HTTP Client
 // ////////////////////////////////////////////
 
-// HTTPOptions ...
+// HTTPOptions is a HTTP option include HandshakeTimeout and HTTPTimeout.
 type HTTPOptions struct {
 	HandshakeTimeout time.Duration
 	HTTPTimeout      time.Duration
@@ -74,13 +74,13 @@ var defaultHTTPOptions = HTTPOptions{
 	HTTPTimeout:      3 * time.Second,
 }
 
-// HTTPClient ...
+// HTTPClient is a HTTP client ,include ID and options.
 type HTTPClient struct {
 	ID      int64
 	options HTTPOptions
 }
 
-// NewHTTPClient ...
+// NewHTTPClient creates a new HTTP client with HTTPOptions.
 func NewHTTPClient(opt *HTTPOptions) *HTTPClient {
 	if opt == nil {
 		opt = &defaultHTTPOptions
@@ -100,7 +100,7 @@ func NewHTTPClient(opt *HTTPOptions) *HTTPClient {
 	}
 }
 
-// NewRequest ...
+// NewRequest creates a new HTTP request with @service ,@method and @arguments.
 func (c *HTTPClient) NewRequest(service common.URL, method string, args interface{}) *Request {
 
 	return &Request{
@@ -114,7 +114,7 @@ func (c *HTTPClient) NewRequest(service common.URL, method string, args interfac
 	}
 }
 
-// Call ...
+// Call makes a HTTP call with @ctx , @service ,@req and @rsp
 func (c *HTTPClient) Call(ctx context.Context, service common.URL, req *Request, rsp interface{}) error {
 	// header
 	httpHeader := http.Header{}
diff --git a/protocol/jsonrpc/json.go b/protocol/jsonrpc/json.go
index 3176e193816bf95882539374672eeed7f9cddc44..389ead9c1a530742c872a238d89b2df5ae3462ca 100644
--- a/protocol/jsonrpc/json.go
+++ b/protocol/jsonrpc/json.go
@@ -37,7 +37,7 @@ const (
 	VERSION = "2.0"
 )
 
-// CodecData ...
+// CodecData is codec data for json RPC.
 type CodecData struct {
 	ID     int64
 	Method string
@@ -64,6 +64,7 @@ type Error struct {
 	Data    interface{} `json:"data,omitempty"`
 }
 
+// Error decodes response error for a string.
 func (e *Error) Error() string {
 	buf, err := json.Marshal(e)
 	if err != nil {
@@ -114,6 +115,7 @@ func newJsonClientCodec() *jsonClientCodec {
 	}
 }
 
+// Write codec data as byte.
 func (c *jsonClientCodec) Write(d *CodecData) ([]byte, error) {
 	// If return error: it will be returned as is for this call.
 	// Allow param to be only Array, Slice, Map or Struct.
@@ -170,6 +172,7 @@ func (c *jsonClientCodec) Write(d *CodecData) ([]byte, error) {
 	return buf.Bytes(), nil
 }
 
+// Read bytes as structured data
 func (c *jsonClientCodec) Read(streamBytes []byte, x interface{}) error {
 	c.rsp.reset()
 
@@ -223,6 +226,7 @@ func (r *serverRequest) reset() {
 	}
 }
 
+// UnmarshalJSON unmarshals JSON for server request.
 func (r *serverRequest) UnmarshalJSON(raw []byte) error {
 	r.reset()
 
@@ -281,7 +285,7 @@ type serverResponse struct {
 	Error   interface{}      `json:"error,omitempty"`
 }
 
-// ServerCodec ...
+// ServerCodec is codec data for request server.
 type ServerCodec struct {
 	req serverRequest
 }
@@ -296,7 +300,7 @@ func newServerCodec() *ServerCodec {
 	return &ServerCodec{}
 }
 
-// ReadHeader ...
+// ReadHeader reads header and unmarshal to server codec
 func (c *ServerCodec) ReadHeader(header map[string]string, body []byte) error {
 	if header["HttpMethod"] != "POST" {
 		return &Error{Code: -32601, Message: "Method not found"}
@@ -328,7 +332,7 @@ func (c *ServerCodec) ReadHeader(header map[string]string, body []byte) error {
 	return nil
 }
 
-// ReadBody ...
+// ReadBody reads @x as request body.
 func (c *ServerCodec) ReadBody(x interface{}) error {
 	// If x!=nil and return error e:
 	// - Write() will be called with e.Error() in r.Error
@@ -339,7 +343,7 @@ func (c *ServerCodec) ReadBody(x interface{}) error {
 		return nil
 	}
 
-	// 鍦ㄨ繖閲屾妸璇锋眰鍙傛暟json 瀛楃涓茶浆鎹㈡垚浜嗙浉搴旂殑struct
+	// the request parameter JSON string is converted to the corresponding struct
 	params := []byte(*c.req.Params)
 	if err := json.Unmarshal(*c.req.Params, x); err != nil {
 		// Note: if c.request.Params is nil it's not an error, it's an optional member.
@@ -362,7 +366,7 @@ func (c *ServerCodec) ReadBody(x interface{}) error {
 	return nil
 }
 
-// NewError ...
+// NewError creates a error with @code and @message
 func NewError(code int, message string) *Error {
 	return &Error{Code: code, Message: message}
 }
@@ -380,6 +384,7 @@ func newError(message string) *Error {
 	}
 }
 
+// Write responses as byte
 func (c *ServerCodec) Write(errMsg string, x interface{}) ([]byte, error) {
 	// If return error: nothing happens.
 	// In r.Error will be "" or .Error() of error returned by:
diff --git a/protocol/jsonrpc/jsonrpc_exporter.go b/protocol/jsonrpc/jsonrpc_exporter.go
index c61cf9adaebe9105a87ece1dcbae4dbe706cb3fc..6f75f6aeae9fb1a8d75ded5f558e0ddae84686a0 100644
--- a/protocol/jsonrpc/jsonrpc_exporter.go
+++ b/protocol/jsonrpc/jsonrpc_exporter.go
@@ -28,19 +28,19 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// JsonrpcExporter ...
+// JsonrpcExporter is JSON RPC exporter and  extends from base invoker.
 type JsonrpcExporter struct {
 	protocol.BaseExporter
 }
 
-// NewJsonrpcExporter ...
+// NewJsonrpcExporter creates JSON RPC exporter with @key, @invoker and @exporterMap
 func NewJsonrpcExporter(key string, invoker protocol.Invoker, exporterMap *sync.Map) *JsonrpcExporter {
 	return &JsonrpcExporter{
 		BaseExporter: *protocol.NewBaseExporter(key, invoker, exporterMap),
 	}
 }
 
-// Unexport ...
+// Unexport exported JSON RPC service.
 func (je *JsonrpcExporter) Unexport() {
 	serviceId := je.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "")
 	interfaceName := je.GetInvoker().GetUrl().GetParam(constant.INTERFACE_KEY, "")
diff --git a/protocol/jsonrpc/jsonrpc_invoker.go b/protocol/jsonrpc/jsonrpc_invoker.go
index b6e194ce0e93e84c164eccf8574e5eb20430f6e8..d84b980216ade6e569e68af31fc90e1ea16b3056 100644
--- a/protocol/jsonrpc/jsonrpc_invoker.go
+++ b/protocol/jsonrpc/jsonrpc_invoker.go
@@ -29,13 +29,13 @@ import (
 	invocation_impl "github.com/apache/dubbo-go/protocol/invocation"
 )
 
-// JsonrpcInvoker ...
+// JsonrpcInvoker is JSON RPC invoker
 type JsonrpcInvoker struct {
 	protocol.BaseInvoker
 	client *HTTPClient
 }
 
-// NewJsonrpcInvoker ...
+// NewJsonrpcInvoker creates JSON RPC invoker with @url and @client
 func NewJsonrpcInvoker(url common.URL, client *HTTPClient) *JsonrpcInvoker {
 	return &JsonrpcInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
@@ -43,7 +43,7 @@ func NewJsonrpcInvoker(url common.URL, client *HTTPClient) *JsonrpcInvoker {
 	}
 }
 
-// Invoke ...
+// Invoke the JSON RPC invocation and return result.
 func (ji *JsonrpcInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 
 	var (
diff --git a/protocol/jsonrpc/jsonrpc_protocol.go b/protocol/jsonrpc/jsonrpc_protocol.go
index 64f708652d8cb4bf2a6d53488c9fe17e64f10ad0..90a6bf5ef7aa017488f723804b22cc613850bcf2 100644
--- a/protocol/jsonrpc/jsonrpc_protocol.go
+++ b/protocol/jsonrpc/jsonrpc_protocol.go
@@ -44,14 +44,14 @@ func init() {
 
 var jsonrpcProtocol *JsonrpcProtocol
 
-// JsonrpcProtocol ...
+// JsonrpcProtocol is JSON RPC protocol.
 type JsonrpcProtocol struct {
 	protocol.BaseProtocol
 	serverMap  map[string]*Server
 	serverLock sync.Mutex
 }
 
-// NewJsonrpcProtocol ...
+// NewJsonrpcProtocol creates JSON RPC protocol
 func NewJsonrpcProtocol() *JsonrpcProtocol {
 	return &JsonrpcProtocol{
 		BaseProtocol: protocol.NewBaseProtocol(),
@@ -59,7 +59,7 @@ func NewJsonrpcProtocol() *JsonrpcProtocol {
 	}
 }
 
-// Export ...
+// Export JSON RPC service  for remote invocation
 func (jp *JsonrpcProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	url := invoker.GetUrl()
 	serviceKey := strings.TrimPrefix(url.Path, "/")
@@ -74,7 +74,7 @@ func (jp *JsonrpcProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	return exporter
 }
 
-// Refer ...
+// Refer a remote JSON PRC service from registry
 func (jp *JsonrpcProtocol) Refer(url common.URL) protocol.Invoker {
 	//default requestTimeout
 	var requestTimeout = config.GetConsumerConfig().RequestTimeout
@@ -93,7 +93,7 @@ func (jp *JsonrpcProtocol) Refer(url common.URL) protocol.Invoker {
 	return invoker
 }
 
-// Destroy ...
+// Destroy will destroy all invoker and exporter, so it only is called once.
 func (jp *JsonrpcProtocol) Destroy() {
 	logger.Infof("jsonrpcProtocol destroy.")
 
@@ -125,7 +125,7 @@ func (jp *JsonrpcProtocol) openServer(url common.URL) {
 	}
 }
 
-// GetProtocol ...
+// GetProtocol gets JSON RPC protocol.
 func GetProtocol() protocol.Protocol {
 	if jsonrpcProtocol == nil {
 		jsonrpcProtocol = NewJsonrpcProtocol()
diff --git a/protocol/jsonrpc/server.go b/protocol/jsonrpc/server.go
index fcea66632e787083823c1d06ca6c1698c45d5b23..aa458a1614df29997b05ac4462200f9e9ffffc25 100644
--- a/protocol/jsonrpc/server.go
+++ b/protocol/jsonrpc/server.go
@@ -59,7 +59,7 @@ const (
 	PathPrefix = byte('/')
 )
 
-// Server ...
+// Server is JSON RPC server wrapper
 type Server struct {
 	done chan struct{}
 	once sync.Once
@@ -69,7 +69,7 @@ type Server struct {
 	timeout time.Duration
 }
 
-// NewServer ...
+// NewServer creates new JSON RPC server.
 func NewServer() *Server {
 	return &Server{
 		done: make(chan struct{}),
@@ -228,7 +228,7 @@ func accept(listener net.Listener, fn func(net.Conn)) error {
 	}
 }
 
-// Start ...
+// Start JSON RPC server then ready for accept request.
 func (s *Server) Start(url common.URL) {
 	listener, err := net.Listen("tcp", url.Location)
 	if err != nil {
@@ -255,7 +255,7 @@ func (s *Server) Start(url common.URL) {
 	}()
 }
 
-// Stop ...
+// Stop JSON RPC server, just can be call once.
 func (s *Server) Stop() {
 	s.once.Do(func() {
 		close(s.done)
diff --git a/protocol/protocol.go b/protocol/protocol.go
index a873469a8ba361c9dfc922b071ffbf256c6a8b98..6bed5ec4c2be82edda7a642eb342381c53387460 100644
--- a/protocol/protocol.go
+++ b/protocol/protocol.go
@@ -29,15 +29,20 @@ import (
 // Protocol
 // Extension - protocol
 type Protocol interface {
+	// Export service for remote invocation
 	Export(invoker Invoker) Exporter
+	// Refer a remote service
 	Refer(url common.URL) Invoker
+	// Destroy will destroy all invoker and exporter, so it only is called once.
 	Destroy()
 }
 
 // Exporter
 // wrapping invoker
 type Exporter interface {
+	// GetInvoker gets invoker.
 	GetInvoker() Invoker
+	// Unexport exported service.
 	Unexport()
 }
 
@@ -45,45 +50,45 @@ type Exporter interface {
 // base protocol
 /////////////////////////////
 
-// BaseProtocol ...
+// BaseProtocol is default protocol implement.
 type BaseProtocol struct {
 	exporterMap *sync.Map
 	invokers    []Invoker
 }
 
-// NewBaseProtocol ...
+// NewBaseProtocol creates a new BaseProtocol
 func NewBaseProtocol() BaseProtocol {
 	return BaseProtocol{
 		exporterMap: new(sync.Map),
 	}
 }
 
-// SetExporterMap ...
+// SetExporterMap set @exporter with @key to local memory.
 func (bp *BaseProtocol) SetExporterMap(key string, exporter Exporter) {
 	bp.exporterMap.Store(key, exporter)
 }
 
-// ExporterMap ...
+// ExporterMap gets exporter map.
 func (bp *BaseProtocol) ExporterMap() *sync.Map {
 	return bp.exporterMap
 }
 
-// SetInvokers ...
+// SetInvokers sets invoker into local memory
 func (bp *BaseProtocol) SetInvokers(invoker Invoker) {
 	bp.invokers = append(bp.invokers, invoker)
 }
 
-// Invokers ...
+// Invokers gets all invokers
 func (bp *BaseProtocol) Invokers() []Invoker {
 	return bp.invokers
 }
 
-// Export ...
+// Export is default export implement.
 func (bp *BaseProtocol) Export(invoker Invoker) Exporter {
 	return NewBaseExporter("base", invoker, bp.exporterMap)
 }
 
-// Refer ...
+// Refer is default refer implement.
 func (bp *BaseProtocol) Refer(url common.URL) Invoker {
 	return NewBaseInvoker(url)
 }
@@ -113,14 +118,14 @@ func (bp *BaseProtocol) Destroy() {
 // base exporter
 /////////////////////////////
 
-// BaseExporter ...
+// BaseExporter is default exporter implement.
 type BaseExporter struct {
 	key         string
 	invoker     Invoker
 	exporterMap *sync.Map
 }
 
-// NewBaseExporter ...
+// NewBaseExporter creates a new BaseExporter
 func NewBaseExporter(key string, invoker Invoker, exporterMap *sync.Map) *BaseExporter {
 	return &BaseExporter{
 		key:         key,
@@ -129,13 +134,13 @@ func NewBaseExporter(key string, invoker Invoker, exporterMap *sync.Map) *BaseEx
 	}
 }
 
-// GetInvoker ...
+// GetInvoker gets invoker
 func (de *BaseExporter) GetInvoker() Invoker {
 	return de.invoker
 
 }
 
-// Unexport ...
+// Unexport exported service.
 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 dedf8aa64b6ae1b7b4782350e2625b02171aac44..8763c20410915d4e81afd35691be7d9ed490f7a1 100644
--- a/protocol/protocolwrapper/mock_protocol_filter.go
+++ b/protocol/protocolwrapper/mock_protocol_filter.go
@@ -28,19 +28,22 @@ import (
 
 type mockProtocolFilter struct{}
 
-// NewMockProtocolFilter ...
+// NewMockProtocolFilter creates a new mock protocol
 func NewMockProtocolFilter() protocol.Protocol {
 	return &mockProtocolFilter{}
 }
 
+// Export mock service for  remote invocation
 func (pfw *mockProtocolFilter) Export(invoker protocol.Invoker) protocol.Exporter {
 	return protocol.NewBaseExporter("key", invoker, &sync.Map{})
 }
 
+// Refer a mock remote service
 func (pfw *mockProtocolFilter) Refer(url common.URL) protocol.Invoker {
 	return protocol.NewBaseInvoker(url)
 }
 
+// Destroy will do nothing
 func (pfw *mockProtocolFilter) Destroy() {
 
 }
diff --git a/protocol/protocolwrapper/protocol_filter_wrapper.go b/protocol/protocolwrapper/protocol_filter_wrapper.go
index 70d2da0faed3bc9797eb23cec653bea05d445d91..cba1d5d5bce8c3de387381d17cc3f7965bf3adac 100644
--- a/protocol/protocolwrapper/protocol_filter_wrapper.go
+++ b/protocol/protocolwrapper/protocol_filter_wrapper.go
@@ -31,7 +31,7 @@ import (
 )
 
 const (
-	// FILTER ...
+	// FILTER is protocol key.
 	FILTER = "filter"
 )
 
@@ -45,7 +45,7 @@ type ProtocolFilterWrapper struct {
 	protocol protocol.Protocol
 }
 
-// Export ...
+// Export service for remote invocation
 func (pfw *ProtocolFilterWrapper) Export(invoker protocol.Invoker) protocol.Exporter {
 	if pfw.protocol == nil {
 		pfw.protocol = extension.GetProtocol(invoker.GetUrl().Protocol)
@@ -54,7 +54,7 @@ func (pfw *ProtocolFilterWrapper) Export(invoker protocol.Invoker) protocol.Expo
 	return pfw.protocol.Export(invoker)
 }
 
-// Refer ...
+// Refer a remote service
 func (pfw *ProtocolFilterWrapper) Refer(url common.URL) protocol.Invoker {
 	if pfw.protocol == nil {
 		pfw.protocol = extension.GetProtocol(url.Protocol)
@@ -62,7 +62,7 @@ func (pfw *ProtocolFilterWrapper) Refer(url common.URL) protocol.Invoker {
 	return buildInvokerChain(pfw.protocol.Refer(url), constant.REFERENCE_FILTER_KEY)
 }
 
-// Destroy ...
+// Destroy will destroy all invoker and exporter.
 func (pfw *ProtocolFilterWrapper) Destroy() {
 	pfw.protocol.Destroy()
 }
diff --git a/protocol/result.go b/protocol/result.go
index 34e76d2dddbaed33b2e2c015631443565cfaea87..2e7a6e492a60888ec9d9f420c77e6b77aee6aa70 100644
--- a/protocol/result.go
+++ b/protocol/result.go
@@ -17,15 +17,23 @@
 
 package protocol
 
-// Result ...
+// Result is a RPC result
 type Result interface {
+	// SetError sets error.
 	SetError(error)
+	// Error gets error.
 	Error() error
+	// SetResult sets invoker result.
 	SetResult(interface{})
+	// Result gets invoker result.
 	Result() interface{}
+	// SetAttachments replaces the existing attachments with the specified param.
 	SetAttachments(map[string]string)
+	// Attachments gets all attachments
 	Attachments() map[string]string
+	// AddAttachment adds the specified map to existing attachments in this instance.
 	AddAttachment(string, string)
+	// Attachment gets attachment by key with default value.
 	Attachment(string, string) string
 }
 
@@ -33,48 +41,49 @@ type Result interface {
 // Result Impletment of RPC
 /////////////////////////////
 
-// RPCResult ...
+// RPCResult is default RPC result.
 type RPCResult struct {
 	Attrs map[string]string
 	Err   error
 	Rest  interface{}
 }
 
-// SetError ...
+// SetError sets error.
 func (r *RPCResult) SetError(err error) {
 	r.Err = err
 }
 
+// Error gets error.
 func (r *RPCResult) Error() error {
 	return r.Err
 }
 
-// SetResult ...
+// SetResult sets invoker result.
 func (r *RPCResult) SetResult(rest interface{}) {
 	r.Rest = rest
 }
 
-// Result ...
+// Result gets invoker result.
 func (r *RPCResult) Result() interface{} {
 	return r.Rest
 }
 
-// SetAttachments ...
+// SetAttachments replaces the existing attachments with the specified param.
 func (r *RPCResult) SetAttachments(attr map[string]string) {
 	r.Attrs = attr
 }
 
-// Attachments ...
+// Attachments gets all attachments
 func (r *RPCResult) Attachments() map[string]string {
 	return r.Attrs
 }
 
-// AddAttachment ...
+// AddAttachment adds the specified map to existing attachments in this instance.
 func (r *RPCResult) AddAttachment(key, value string) {
 	r.Attrs[key] = value
 }
 
-// Attachment ...
+// Attachment gets attachment by key with default value.
 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 13be47c98ece1cc006250ad49ab2b9a8c3b1f625..0eeca6c1bba1f471117eb687a92d0458b9d5901d 100644
--- a/protocol/rpc_status.go
+++ b/protocol/rpc_status.go
@@ -32,7 +32,7 @@ var (
 	serviceStatistic sync.Map // url -> RPCStatus
 )
 
-// RPCStatus ...
+// RPCStatus is URL statistics.
 type RPCStatus struct {
 	active                        int32
 	failed                        int32
@@ -46,63 +46,63 @@ type RPCStatus struct {
 	lastRequestFailedTimestamp    int64
 }
 
-// GetActive ...
+// GetActive gets active.
 func (rpc *RPCStatus) GetActive() int32 {
 	return atomic.LoadInt32(&rpc.active)
 }
 
-// GetFailed ...
+// GetFailed gets failed.
 func (rpc *RPCStatus) GetFailed() int32 {
 	return atomic.LoadInt32(&rpc.failed)
 }
 
-// GetTotal ...
+// GetTotal gets total.
 func (rpc *RPCStatus) GetTotal() int32 {
 	return atomic.LoadInt32(&rpc.total)
 }
 
-// GetTotalElapsed ...
+// GetTotalElapsed gets total elapsed.
 func (rpc *RPCStatus) GetTotalElapsed() int64 {
 	return atomic.LoadInt64(&rpc.totalElapsed)
 }
 
-// GetFailedElapsed ...
+// GetFailedElapsed gets failed elapsed.
 func (rpc *RPCStatus) GetFailedElapsed() int64 {
 	return atomic.LoadInt64(&rpc.failedElapsed)
 }
 
-// GetMaxElapsed ...
+// GetMaxElapsed gets max elapsed.
 func (rpc *RPCStatus) GetMaxElapsed() int64 {
 	return atomic.LoadInt64(&rpc.maxElapsed)
 }
 
-// GetFailedMaxElapsed ...
+// GetFailedMaxElapsed gets failed max elapsed.
 func (rpc *RPCStatus) GetFailedMaxElapsed() int64 {
 	return atomic.LoadInt64(&rpc.failedMaxElapsed)
 }
 
-// GetSucceededMaxElapsed ...
+// GetSucceededMaxElapsed gets succeeded max elapsed.
 func (rpc *RPCStatus) GetSucceededMaxElapsed() int64 {
 	return atomic.LoadInt64(&rpc.succeededMaxElapsed)
 }
 
-// GetLastRequestFailedTimestamp ...
+// GetLastRequestFailedTimestamp gets last request failed timestamp.
 func (rpc *RPCStatus) GetLastRequestFailedTimestamp() int64 {
 	return atomic.LoadInt64(&rpc.lastRequestFailedTimestamp)
 }
 
-// GetSuccessiveRequestFailureCount ...
+// GetSuccessiveRequestFailureCount gets successive request failure count.
 func (rpc *RPCStatus) GetSuccessiveRequestFailureCount() int32 {
 	return atomic.LoadInt32(&rpc.successiveRequestFailureCount)
 }
 
-// GetURLStatus ...
+// GetURLStatus get URL RPC status.
 func GetURLStatus(url common.URL) *RPCStatus {
 	rpcStatus, _ := serviceStatistic.LoadOrStore(url.Key(), &RPCStatus{})
 	return rpcStatus.(*RPCStatus)
 }
 
-// GetMethodStatus ...
+// GetMethodStatus get method RPC status.
 func GetMethodStatus(url common.URL, methodName string) *RPCStatus {
 	identifier := url.Key()
 	methodMap, found := methodStatistics.Load(identifier)
@@ -122,13 +122,13 @@ func GetMethodStatus(url common.URL, methodName string) *RPCStatus {
 	return status
 }
 
-// BeginCount ...
+// BeginCount gets begin count.
 func BeginCount(url common.URL, methodName string) {
 	beginCount0(GetURLStatus(url))
 	beginCount0(GetMethodStatus(url, methodName))
 }
 
-// EndCount ...
+// EndCount gets end count.
 func EndCount(url common.URL, methodName string, elapsed int64, succeeded bool) {
 	endCount0(GetURLStatus(url), elapsed, succeeded)
 	endCount0(GetMethodStatus(url, methodName), elapsed, succeeded)
@@ -163,7 +163,7 @@ func endCount0(rpcStatus *RPCStatus, elapsed int64, succeeded bool) {
 	}
 }
 
-// CurrentTimeMillis ...
+// CurrentTimeMillis get current timestamp
 func CurrentTimeMillis() int64 {
 	return time.Now().UnixNano() / int64(time.Millisecond)
 }
diff --git a/registry/base_configuration_listener.go b/registry/base_configuration_listener.go
index 55418318dfc52ed9f17f1ec6a18ad9ef9d8163bf..7b28d7ee1b30a03b8211c4c1efa5824c3b61453a 100644
--- a/registry/base_configuration_listener.go
+++ b/registry/base_configuration_listener.go
@@ -29,19 +29,19 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
-// BaseConfigurationListener ...
+// nolint
 type BaseConfigurationListener struct {
 	configurators           []config_center.Configurator
 	dynamicConfiguration    config_center.DynamicConfiguration
 	defaultConfiguratorFunc func(url *common.URL) config_center.Configurator
 }
 
-// Configurators ...
+// Configurators gets Configurator from config center
 func (bcl *BaseConfigurationListener) Configurators() []config_center.Configurator {
 	return bcl.configurators
 }
 
-// InitWith ...
+// InitWith will init BaseConfigurationListener by @key+@Listener+@f
 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 {
@@ -60,7 +60,7 @@ func (bcl *BaseConfigurationListener) InitWith(key string, listener config_cente
 	}
 }
 
-// Process ...
+// Process the notification event once there's any change happens on the config.
 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 {
@@ -82,14 +82,14 @@ func (bcl *BaseConfigurationListener) genConfiguratorFromRawRule(rawConfig strin
 	return nil
 }
 
-// OverrideUrl ...
+// OverrideUrl gets existing configuration rule and overrides provider url before exporting.
 func (bcl *BaseConfigurationListener) OverrideUrl(url *common.URL) {
 	for _, v := range bcl.configurators {
 		v.Configure(url)
 	}
 }
 
-// ToConfigurators ...
+// ToConfigurators converts @urls by @f to config_center.Configurators
 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
index 504e087091ae30264676c90feb49d5690b85c164..ad1a3b61741e003625612ad58409eb8615271a84 100644
--- a/registry/base_registry.go
+++ b/registry/base_registry.go
@@ -92,7 +92,7 @@ type FacadeBasedRegistry interface {
 	InitListeners()
 }
 
-// BaseRegistry is a event logic abstract for registry. It implement Registry interface.
+// BaseRegistry is a common logic abstract for registry. It implement Registry interface.
 type BaseRegistry struct {
 	context             context.Context
 	facadeBasedRegistry FacadeBasedRegistry
diff --git a/registry/consul/listener.go b/registry/consul/listener.go
index 5fac9ec0f9b6c08620021de9d0b92e3b94773c12..cf3888dd16ee4a9b504664383be69ca1faf4d842 100644
--- a/registry/consul/listener.go
+++ b/registry/consul/listener.go
@@ -187,6 +187,7 @@ func (l *consulListener) handler(idx uint64, raw interface{}) {
 	}
 }
 
+// Next returns the service event from consul.
 func (l *consulListener) Next() (*registry.ServiceEvent, error) {
 	select {
 	case event := <-l.eventCh:
@@ -196,6 +197,7 @@ func (l *consulListener) Next() (*registry.ServiceEvent, error) {
 	}
 }
 
+// Close closes this listener
 func (l *consulListener) Close() {
 	close(l.done)
 	l.plan.Stop()
diff --git a/registry/consul/registry.go b/registry/consul/registry.go
index c9e0718346258b6b38f2a793dc215bcf8e65cdb7..c425c5ec20d36be02c00499340f13b13c9aa2655 100644
--- a/registry/consul/registry.go
+++ b/registry/consul/registry.go
@@ -36,8 +36,7 @@ import (
 )
 
 const (
-	// RegistryConnDelay ...
-	RegistryConnDelay = 3
+	registryConnDelay = 3
 )
 
 func init() {
@@ -74,6 +73,8 @@ func newConsulRegistry(url *common.URL) (registry.Registry, error) {
 	return r, nil
 }
 
+// Register register @url
+// it delegate the job to register() method
 func (r *consulRegistry) Register(url common.URL) error {
 	var err error
 
@@ -87,6 +88,7 @@ func (r *consulRegistry) Register(url common.URL) error {
 	return nil
 }
 
+// register actually register the @url
 func (r *consulRegistry) register(url common.URL) error {
 	service, err := buildService(url)
 	if err != nil {
@@ -95,6 +97,8 @@ func (r *consulRegistry) register(url common.URL) error {
 	return r.client.Agent().ServiceRegister(service)
 }
 
+// UnRegister unregister the @url
+// it delegate the job to unregister() method
 func (r *consulRegistry) UnRegister(url common.URL) error {
 	var err error
 
@@ -108,10 +112,12 @@ func (r *consulRegistry) UnRegister(url common.URL) error {
 	return nil
 }
 
+// unregister actually unregister the @url
 func (r *consulRegistry) unregister(url common.URL) error {
 	return r.client.Agent().ServiceDeregister(buildId(url))
 }
 
+// Subscribe subscribe the @url with the @notifyListener
 func (r *consulRegistry) Subscribe(url *common.URL, notifyListener registry.NotifyListener) error {
 	role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, ""))
 	if role == common.CONSUMER {
@@ -120,11 +126,13 @@ func (r *consulRegistry) Subscribe(url *common.URL, notifyListener registry.Noti
 	return nil
 }
 
-// UnSubscribe :
+// UnSubscribe is not supported yet
 func (r *consulRegistry) UnSubscribe(url *common.URL, notifyListener registry.NotifyListener) error {
 	return perrors.New("UnSubscribe not support in consulRegistry")
 }
 
+// subscribe actually subscribe the @url
+// it loops forever until success
 func (r *consulRegistry) subscribe(url *common.URL, notifyListener registry.NotifyListener) {
 	for {
 		if !r.IsAvailable() {
@@ -139,7 +147,7 @@ func (r *consulRegistry) subscribe(url *common.URL, notifyListener registry.Noti
 				return
 			}
 			logger.Warnf("getListener() = err:%v", perrors.WithStack(err))
-			time.Sleep(time.Duration(RegistryConnDelay) * time.Second)
+			time.Sleep(time.Duration(registryConnDelay) * time.Second)
 			continue
 		}
 
@@ -162,10 +170,12 @@ func (r *consulRegistry) getListener(url common.URL) (registry.Listener, error)
 	return listener, err
 }
 
+// GetUrl get registry URL of consul registry center
 func (r *consulRegistry) GetUrl() common.URL {
 	return *r.URL
 }
 
+// IsAvailable checks consul registry center whether is available
 func (r *consulRegistry) IsAvailable() bool {
 	select {
 	case <-r.done:
@@ -175,6 +185,7 @@ func (r *consulRegistry) IsAvailable() bool {
 	}
 }
 
+// Destroy consul registry center
 func (r *consulRegistry) Destroy() {
 	close(r.done)
 }
diff --git a/registry/directory/directory.go b/registry/directory/directory.go
index 253dc597f9981c61574b8af97119653652d51bbc..2fbf9410f76c473362964c9ef148e3c581d3d045 100644
--- a/registry/directory/directory.go
+++ b/registry/directory/directory.go
@@ -46,6 +46,8 @@ func init() {
 	extension.SetDefaultRegistryDirectory(NewRegistryDirectory)
 }
 
+// RegistryDirectory implementation of Directory:
+// Invoker list returned from this Directory's list method have been filtered by Routers
 type RegistryDirectory struct {
 	directory.BaseDirectory
 	cacheInvokers                  []protocol.Invoker
diff --git a/registry/etcdv3/listener.go b/registry/etcdv3/listener.go
index 51fdf21f5d229932646b4da464de960c2f2985de..436b6eca5b0dfb8514cbc21a47032490f7b1c21f 100644
--- a/registry/etcdv3/listener.go
+++ b/registry/etcdv3/listener.go
@@ -38,15 +38,17 @@ type dataListener struct {
 	listener      config_center.ConfigurationListener
 }
 
-// NewRegistryDataListener
+// NewRegistryDataListener creates a data listener for etcd
 func NewRegistryDataListener(listener config_center.ConfigurationListener) *dataListener {
 	return &dataListener{listener: listener}
 }
 
+// AddInterestedURL adds a registration @url to listen
 func (l *dataListener) AddInterestedURL(url *common.URL) {
 	l.interestedURL = append(l.interestedURL, url)
 }
 
+// DataChange processes the data change event from registry center of etcd
 func (l *dataListener) DataChange(eventType remoting.Event) bool {
 
 	index := strings.Index(eventType.Path, "/providers/")
@@ -88,10 +90,12 @@ func NewConfigurationListener(reg *etcdV3Registry) *configurationListener {
 	return &configurationListener{registry: reg, events: make(chan *config_center.ConfigChangeEvent, 32)}
 }
 
+// Process data change event from config center of etcd
 func (l *configurationListener) Process(configType *config_center.ConfigChangeEvent) {
 	l.events <- configType
 }
 
+// Next returns next service event once received
 func (l *configurationListener) Next() (*registry.ServiceEvent, error) {
 	for {
 		select {
@@ -114,6 +118,7 @@ func (l *configurationListener) Next() (*registry.ServiceEvent, error) {
 	}
 }
 
+// Close etcd registry center
 func (l *configurationListener) Close() {
 	l.registry.WaitGroup().Done()
 }
diff --git a/registry/etcdv3/registry.go b/registry/etcdv3/registry.go
index a65d090349b40d473c769e3130e4f000ee03bd00..2fec8eaad25e716fc5ed5ee33775d8898cb212e2 100644
--- a/registry/etcdv3/registry.go
+++ b/registry/etcdv3/registry.go
@@ -57,17 +57,17 @@ type etcdV3Registry struct {
 	configListener *configurationListener
 }
 
-// Client get the etcdv3 client
+// Client gets the etcdv3 client
 func (r *etcdV3Registry) Client() *etcdv3.Client {
 	return r.client
 }
 
-//SetClient set the etcdv3 client
+// SetClient sets the etcdv3 client
 func (r *etcdV3Registry) SetClient(client *etcdv3.Client) {
 	r.client = client
 }
 
-//
+// ClientLock returns lock for client
 func (r *etcdV3Registry) ClientLock() *sync.Mutex {
 	return &r.cltLock
 }
@@ -104,31 +104,37 @@ func newETCDV3Registry(url *common.URL) (registry.Registry, error) {
 	return r, nil
 }
 
+// InitListeners init listeners of etcd registry center
 func (r *etcdV3Registry) InitListeners() {
 	r.listener = etcdv3.NewEventListener(r.client)
 	r.configListener = NewConfigurationListener(r)
 	r.dataListener = NewRegistryDataListener(r.configListener)
 }
 
+// DoRegister actually do the register job in the registry center of etcd
 func (r *etcdV3Registry) DoRegister(root string, node string) error {
 	return r.client.Create(path.Join(root, node), "")
 }
 
+// nolint
 func (r *etcdV3Registry) DoUnregister(root string, node string) error {
 	return perrors.New("DoUnregister is not support in etcdV3Registry")
 }
 
+// CloseAndNilClient closes listeners and clear client
 func (r *etcdV3Registry) CloseAndNilClient() {
 	r.client.Close()
 	r.client = nil
 }
 
+// CloseListener closes listeners
 func (r *etcdV3Registry) CloseListener() {
 	if r.configListener != nil {
 		r.configListener.Close()
 	}
 }
 
+// CreatePath create the path in the registry center of etcd
 func (r *etcdV3Registry) CreatePath(k string) error {
 	var tmpPath string
 	for _, str := range strings.Split(k, "/")[1:] {
@@ -141,6 +147,7 @@ func (r *etcdV3Registry) CreatePath(k string) error {
 	return nil
 }
 
+// DoSubscribe actually subscribe the provider URL
 func (r *etcdV3Registry) DoSubscribe(svc *common.URL) (registry.Listener, error) {
 
 	var (
diff --git a/registry/etcdv3/service_discovery.go b/registry/etcdv3/service_discovery.go
new file mode 100644
index 0000000000000000000000000000000000000000..5699f1c427f9807ed4c6d179a18a996ea71623bb
--- /dev/null
+++ b/registry/etcdv3/service_discovery.go
@@ -0,0 +1,322 @@
+/*
+ * 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 etcdv3
+
+import (
+	"fmt"
+	"sync"
+	"time"
+)
+
+import (
+	gxset "github.com/dubbogo/gost/container/set"
+	gxpage "github.com/dubbogo/gost/page"
+	"github.com/hashicorp/vault/helper/jsonutil"
+	perrors "github.com/pkg/errors"
+)
+
+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/config"
+	"github.com/apache/dubbo-go/registry"
+	"github.com/apache/dubbo-go/remoting"
+	"github.com/apache/dubbo-go/remoting/etcdv3"
+)
+
+const (
+	ROOT = "/services"
+)
+
+var (
+	initLock sync.Mutex
+)
+
+func init() {
+	extension.SetServiceDiscovery(constant.ETCDV3_KEY, newEtcdV3ServiceDiscovery)
+}
+
+// new etcd service discovery struct
+type etcdV3ServiceDiscovery struct {
+	// descriptor is a short string about the basic information of this instance
+	descriptor string
+	// client is current Etcdv3 client
+	client *etcdv3.Client
+	// serviceInstance is current serviceInstance
+	serviceInstance *registry.ServiceInstance
+	// services is when register or update will add service name
+	services *gxset.HashSet
+	// child listener
+	childListenerMap map[string]*etcdv3.EventListener
+}
+
+// basic information of this instance
+func (e *etcdV3ServiceDiscovery) String() string {
+	return e.descriptor
+}
+
+// Destory service discovery
+func (e *etcdV3ServiceDiscovery) Destroy() error {
+	if e.client != nil {
+		e.client.Close()
+	}
+	return nil
+}
+
+// Register will register an instance of ServiceInstance to registry
+func (e *etcdV3ServiceDiscovery) Register(instance registry.ServiceInstance) error {
+
+	e.serviceInstance = &instance
+
+	path := toPath(instance)
+
+	if nil != e.client {
+		ins, err := jsonutil.EncodeJSON(instance)
+		if err == nil {
+			err = e.client.RegisterTemp(path, string(ins))
+			if err != nil {
+				logger.Errorf("cannot register the instance: %s", string(ins), err)
+			} else {
+				e.services.Add(instance.GetServiceName())
+			}
+		}
+	}
+
+	return nil
+}
+
+// Update will update the data of the instance in registry
+func (e *etcdV3ServiceDiscovery) Update(instance registry.ServiceInstance) error {
+	path := toPath(instance)
+
+	if nil != e.client {
+		ins, err := jsonutil.EncodeJSON(instance)
+		if nil == err {
+			e.client.RegisterTemp(path, string(ins))
+			e.services.Add(instance.GetServiceName())
+		}
+	}
+
+	return nil
+}
+
+// Unregister will unregister this instance from registry
+func (e *etcdV3ServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+	path := toPath(instance)
+
+	if nil != e.client {
+		err := e.client.Delete(path)
+		e.services.Remove(instance.GetServiceName())
+		e.serviceInstance = nil
+		return err
+	}
+
+	return nil
+}
+
+// ----------------- discovery -------------------
+// GetDefaultPageSize will return the default page size
+func (e *etcdV3ServiceDiscovery) GetDefaultPageSize() int {
+	return registry.DefaultPageSize
+}
+
+// GetServices will return the all service names.
+func (e *etcdV3ServiceDiscovery) GetServices() *gxset.HashSet {
+	return e.services
+}
+
+// GetInstances will return all service instances with serviceName
+func (e *etcdV3ServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+
+	if nil != e.client {
+		// get keys and values
+		_, vList, err := e.client.GetChildrenKVList(toParentPath(serviceName))
+		if nil == err {
+			serviceInstances := make([]registry.ServiceInstance, 0, len(vList))
+			for _, v := range vList {
+				instance := &registry.DefaultServiceInstance{}
+				err = jsonutil.DecodeJSON([]byte(v), &instance)
+				if nil == err {
+					serviceInstances = append(serviceInstances, instance)
+				}
+			}
+			return serviceInstances
+		}
+		perrors.New(fmt.Sprintf("could not getChildrenKVList the err is:%v", err))
+	}
+
+	return make([]registry.ServiceInstance, 0, 0)
+}
+
+// GetInstancesByPage will return a page containing instances of ServiceInstance with the serviceName
+// the page will start at offset
+func (e *etcdV3ServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
+
+	all := e.GetInstances(serviceName)
+
+	res := make([]interface{}, 0, pageSize)
+
+	for i := offset; i < len(all) && i < offset+pageSize; i++ {
+		res = append(res, all[i])
+	}
+
+	return gxpage.New(offset, pageSize, res, len(all))
+}
+
+// GetHealthyInstancesByPage will return a page containing instances of ServiceInstance.
+// The param healthy indices that the instance should be healthy or not.
+// The page will start at offset
+func (e *etcdV3ServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
+	all := e.GetInstances(serviceName)
+	res := make([]interface{}, 0, pageSize)
+
+	var (
+		i     = offset
+		count = 0
+	)
+	for i < len(all) && count < pageSize {
+		ins := all[i]
+		if ins.IsHealthy() == healthy {
+			res = append(res, all[i])
+			count++
+		}
+		i++
+	}
+	return gxpage.New(offset, pageSize, res, len(all))
+}
+
+// Batch get all instances by the specified service names
+func (e *etcdV3ServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
+	res := make(map[string]gxpage.Pager, len(serviceNames))
+	for _, name := range serviceNames {
+		res[name] = e.GetInstancesByPage(name, offset, requestedSize)
+	}
+	return res
+}
+
+// ----------------- event ----------------------
+// AddListener adds a new ServiceInstancesChangedListener
+// see addServiceInstancesChangedListener in Java
+func (e *etcdV3ServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
+	return e.registerSreviceWatcher(listener.ServiceName)
+}
+
+// DispatchEventByServiceName dispatches the ServiceInstancesChangedEvent to service instance whose name is serviceName
+func (e *etcdV3ServiceDiscovery) DispatchEventByServiceName(serviceName string) error {
+	return e.DispatchEventForInstances(serviceName, e.GetInstances(serviceName))
+}
+
+// DispatchEventForInstances dispatches the ServiceInstancesChangedEvent to target instances
+func (e *etcdV3ServiceDiscovery) DispatchEventForInstances(serviceName string, instances []registry.ServiceInstance) error {
+	return e.DispatchEvent(registry.NewServiceInstancesChangedEvent(serviceName, instances))
+}
+
+// DispatchEvent dispatches the event
+func (e *etcdV3ServiceDiscovery) DispatchEvent(event *registry.ServiceInstancesChangedEvent) error {
+	extension.GetGlobalDispatcher().Dispatch(event)
+	return nil
+}
+
+// Convert instance to dubbo path
+func toPath(instance registry.ServiceInstance) string {
+	if instance == nil {
+		return ""
+	}
+	// like: /services/servicename1/host(127.0.0.1)/8080
+	return fmt.Sprintf("%s%d", ROOT+constant.PATH_SEPARATOR+instance.GetServiceName()+constant.PATH_SEPARATOR+instance.GetHost()+constant.KEY_SEPARATOR, instance.GetPort())
+}
+
+// to dubbo service path
+func toParentPath(serviceName string) string {
+	return ROOT + constant.PATH_SEPARATOR + serviceName
+}
+
+// register service watcher
+func (e *etcdV3ServiceDiscovery) registerSreviceWatcher(serviceName string) error {
+
+	initLock.Lock()
+	defer initLock.Unlock()
+
+	path := toParentPath(serviceName)
+
+	listener, found := e.childListenerMap[serviceName]
+
+	if !found {
+		listener = etcdv3.NewEventListener(e.client)
+		e.childListenerMap[serviceName] = listener
+	}
+
+	listener.ListenServiceEvent(path, e)
+
+	return nil
+}
+
+// when child data change should DispatchEventByServiceName
+func (e *etcdV3ServiceDiscovery) DataChange(eventType remoting.Event) bool {
+
+	if eventType.Action == remoting.EventTypeUpdate {
+		instance := &registry.DefaultServiceInstance{}
+		err := jsonutil.DecodeJSON([]byte(eventType.Content), &instance)
+		if err != nil {
+			instance.ServiceName = ""
+		}
+
+		if err := e.DispatchEventByServiceName(instance.ServiceName); err != nil {
+			return false
+		}
+	}
+
+	return true
+}
+
+// netEcdv3ServiceDiscovery
+func newEtcdV3ServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
+	initLock.Lock()
+	defer initLock.Unlock()
+
+	sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+	if !ok || len(sdc.RemoteRef) == 0 {
+		return nil, perrors.New("could not init the etcd service instance because the config is invalid")
+	}
+
+	remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+	if !ok {
+		return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+	}
+
+	// init etcdv3 client
+	timeout, err := time.ParseDuration(remoteConfig.TimeoutStr)
+	if err != nil {
+		logger.Errorf("timeout config %v is invalid,err is %v", remoteConfig.TimeoutStr, err.Error())
+		return nil, perrors.WithMessagef(err, "new etcd service discovery(address:%v)", remoteConfig.Address)
+	}
+
+	logger.Infof("etcd address is: %v,timeout is:%s", remoteConfig.Address, timeout.String())
+
+	client := etcdv3.NewServiceDiscoveryClient(
+		etcdv3.WithName(etcdv3.RegistryETCDV3Client),
+		etcdv3.WithTimeout(timeout),
+		etcdv3.WithEndpoints(remoteConfig.Address),
+	)
+
+	descriptor := fmt.Sprintf("etcd-service-discovery[%s]", remoteConfig.Address)
+
+	return &etcdV3ServiceDiscovery{descriptor, client, nil, gxset.NewSet(), make(map[string]*etcdv3.EventListener, 0)}, nil
+}
diff --git a/registry/etcdv3/service_discovery_test.go b/registry/etcdv3/service_discovery_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..d8e3f1a2864150cc1f1e8996bc7c53e115dbef45
--- /dev/null
+++ b/registry/etcdv3/service_discovery_test.go
@@ -0,0 +1,80 @@
+/*
+ * 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 etcdv3
+
+import (
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/registry"
+)
+
+var testName = "test"
+
+func setUp() {
+	config.GetBaseConfig().ServiceDiscoveries[testName] = &config.ServiceDiscoveryConfig{
+		Protocol:  "etcdv3",
+		RemoteRef: testName,
+	}
+
+	config.GetBaseConfig().Remotes[testName] = &config.RemoteConfig{
+		Address:    "localhost:2379",
+		TimeoutStr: "10s",
+	}
+}
+
+func Test_newEtcdV3ServiceDiscovery(t *testing.T) {
+	name := constant.ETCDV3_KEY
+	_, err := newEtcdV3ServiceDiscovery(name)
+
+	// warn: log configure file name is nil
+	assert.NotNil(t, err)
+
+	sdc := &config.ServiceDiscoveryConfig{
+		Protocol:  "etcdv3",
+		RemoteRef: "mock",
+	}
+	config.GetBaseConfig().ServiceDiscoveries[name] = sdc
+
+	_, err = newEtcdV3ServiceDiscovery(name)
+
+	// RemoteConfig not found
+	assert.NotNil(t, err)
+
+	config.GetBaseConfig().Remotes["mock"] = &config.RemoteConfig{
+		Address:    "localhost:2379",
+		TimeoutStr: "10s",
+	}
+
+	res, err := newEtcdV3ServiceDiscovery(name)
+	assert.Nil(t, err)
+	assert.NotNil(t, res)
+}
+
+func TestEtcdV3ServiceDiscovery_GetDefaultPageSize(t *testing.T) {
+	setUp()
+	serviceDiscovry := &etcdV3ServiceDiscovery{}
+	assert.Equal(t, registry.DefaultPageSize, serviceDiscovry.GetDefaultPageSize())
+}
diff --git a/registry/event.go b/registry/event.go
index 6f647185cc213b80b9ab25b4702f91b36aa8ad4b..39fb00c740ef2e70e2cd6768fa4a4bb3226f832c 100644
--- a/registry/event.go
+++ b/registry/event.go
@@ -37,7 +37,7 @@ func init() {
 // service event
 // ////////////////////////////////////////
 
-// ServiceEvent ...
+// ServiceEvent includes create, update, delete event
 type ServiceEvent struct {
 	Action  remoting.EventType
 	Service common.URL
diff --git a/registry/event/customizable_service_instance_listener.go b/registry/event/customizable_service_instance_listener.go
index 89d1621974e32a295f90e5f6c08ab17f3fc2e319..07e84c1454df91d2038beb08abddbc46274623c9 100644
--- a/registry/event/customizable_service_instance_listener.go
+++ b/registry/event/customizable_service_instance_listener.go
@@ -20,7 +20,9 @@ package event
 import (
 	"reflect"
 	"sync"
+)
 
+import (
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/observer"
 )
@@ -56,9 +58,13 @@ func (c *customizableServiceInstanceListener) GetEventType() reflect.Type {
 	return reflect.TypeOf(&ServiceInstancePreRegisteredEvent{})
 }
 
-var customizableServiceInstanceListenerInstance *customizableServiceInstanceListener
-var customizableServiceInstanceListenerOnce sync.Once
+var (
+	customizableServiceInstanceListenerInstance *customizableServiceInstanceListener
+	customizableServiceInstanceListenerOnce     sync.Once
+)
 
+// GetCustomizableServiceInstanceListener returns an instance
+// if the instance was not initialized, we create one
 func GetCustomizableServiceInstanceListener() observer.EventListener {
 	customizableServiceInstanceListenerOnce.Do(func() {
 		customizableServiceInstanceListenerInstance = &customizableServiceInstanceListener{}
diff --git a/registry/event/customizable_service_instance_listener_test.go b/registry/event/customizable_service_instance_listener_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..1c81ece498b4864c3ea7f586d90052f3022627fc
--- /dev/null
+++ b/registry/event/customizable_service_instance_listener_test.go
@@ -0,0 +1,76 @@
+/*
+ * 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 event
+
+import (
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/registry"
+)
+
+func TestGetCustomizableServiceInstanceListener(t *testing.T) {
+
+	prepareMetadataServiceForTest()
+
+	cus := GetCustomizableServiceInstanceListener()
+
+	assert.Equal(t, 9999, cus.GetPriority())
+
+	extension.AddCustomizers(&mockCustomizer{})
+
+	err := cus.OnEvent(&mockEvent{})
+	assert.Nil(t, err)
+	err = cus.OnEvent(NewServiceInstancePreRegisteredEvent("hello", createInstance()))
+	assert.Nil(t, err)
+
+	tp := cus.GetEventType()
+	assert.NotNil(t, tp)
+}
+
+type mockEvent struct {
+}
+
+func (m *mockEvent) String() string {
+	panic("implement me")
+}
+
+func (m *mockEvent) GetSource() interface{} {
+	panic("implement me")
+}
+
+func (m *mockEvent) GetTimestamp() time.Time {
+	panic("implement me")
+}
+
+type mockCustomizer struct {
+}
+
+func (m *mockCustomizer) GetPriority() int {
+	return 0
+}
+
+func (m *mockCustomizer) Customize(instance registry.ServiceInstance) {
+}
diff --git a/registry/event/event_publishing_service_deiscovery_test.go b/registry/event/event_publishing_service_deiscovery_test.go
index ea6a97a32276f65e5a8b5aea920d7ba807fba0ab..8020702080f5158d6ba97ebb3077d86ff130d4e2 100644
--- a/registry/event/event_publishing_service_deiscovery_test.go
+++ b/registry/event/event_publishing_service_deiscovery_test.go
@@ -21,8 +21,7 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/apache/dubbo-go/config"
-	_ "github.com/apache/dubbo-go/metadata/service/inmemory"
+	"github.com/apache/dubbo-go/metadata/mapping"
 )
 
 import (
@@ -36,6 +35,8 @@ import (
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/observer"
 	dispatcher2 "github.com/apache/dubbo-go/common/observer/dispatcher"
+	"github.com/apache/dubbo-go/config"
+	_ "github.com/apache/dubbo-go/metadata/service/inmemory"
 	"github.com/apache/dubbo-go/registry"
 )
 
@@ -45,8 +46,14 @@ func TestEventPublishingServiceDiscovery_DispatchEvent(t *testing.T) {
 
 	config.GetApplicationConfig().MetadataType = "local"
 
+	extension.SetGlobalServiceNameMapping(func() mapping.ServiceNameMapping {
+		return &mockServiceNameMapping{}
+	})
+
 	dc := NewEventPublishingServiceDiscovery(&ServiceDiscoveryA{})
-	tsd := &TestServiceDiscoveryDestroyingEventListener{}
+	tsd := &TestServiceDiscoveryDestroyingEventListener{
+		BaseListener: observer.NewBaseListener(),
+	}
 	tsd.SetT(t)
 	tsi := &TestServiceInstancePreRegisteredEventListener{}
 	tsi.SetT(t)
@@ -68,7 +75,7 @@ func TestEventPublishingServiceDiscovery_DispatchEvent(t *testing.T) {
 
 type TestServiceDiscoveryDestroyingEventListener struct {
 	suite.Suite
-	observer.BaseListenable
+	observer.BaseListener
 }
 
 func (tel *TestServiceDiscoveryDestroyingEventListener) OnEvent(e observer.Event) error {
@@ -89,7 +96,7 @@ func (tel *TestServiceDiscoveryDestroyingEventListener) GetEventType() reflect.T
 
 type TestServiceInstancePreRegisteredEventListener struct {
 	suite.Suite
-	observer.BaseListenable
+	observer.BaseListener
 }
 
 func (tel *TestServiceInstancePreRegisteredEventListener) OnEvent(e observer.Event) error {
@@ -171,3 +178,14 @@ func (msd *ServiceDiscoveryA) DispatchEventForInstances(serviceName string, inst
 func (msd *ServiceDiscoveryA) DispatchEvent(event *registry.ServiceInstancesChangedEvent) error {
 	return nil
 }
+
+type mockServiceNameMapping struct {
+}
+
+func (m *mockServiceNameMapping) Map(serviceInterface string, group string, version string, protocol string) error {
+	return nil
+}
+
+func (m *mockServiceNameMapping) Get(serviceInterface string, group string, version string, protocol string) (*gxset.HashSet, error) {
+	return gxset.NewSet("dubbo"), nil
+}
diff --git a/registry/event/event_publishing_service_discovery.go b/registry/event/event_publishing_service_discovery.go
index 496eb9b4a51f1451fb4e4200325108d6dcd08b75..3ee2f4a44946065cdf7489abc391df41f251d810 100644
--- a/registry/event/event_publishing_service_discovery.go
+++ b/registry/event/event_publishing_service_discovery.go
@@ -20,14 +20,13 @@ package event
 import (
 	gxset "github.com/dubbogo/gost/container/set"
 	gxpage "github.com/dubbogo/gost/page"
-
-	"github.com/apache/dubbo-go/config"
-	"github.com/apache/dubbo-go/metadata/service"
 )
 
 import (
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/observer"
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/metadata/service"
 	"github.com/apache/dubbo-go/registry"
 )
 
@@ -44,7 +43,7 @@ func NewEventPublishingServiceDiscovery(serviceDiscovery registry.ServiceDiscove
 	}
 }
 
-// String
+// String returns serviceDiscovery.String()
 func (epsd *EventPublishingServiceDiscovery) String() string {
 	return epsd.serviceDiscovery.String()
 }
@@ -68,7 +67,7 @@ func (epsd *EventPublishingServiceDiscovery) Register(instance registry.ServiceI
 
 }
 
-// Update delegate function
+// Update returns the result of serviceDiscovery.Update
 func (epsd *EventPublishingServiceDiscovery) Update(instance registry.ServiceInstance) error {
 	f := func() error {
 		return epsd.serviceDiscovery.Update(instance)
@@ -76,7 +75,7 @@ func (epsd *EventPublishingServiceDiscovery) Update(instance registry.ServiceIns
 	return epsd.executeWithEvents(nil, f, nil)
 }
 
-// Unregister delegate function
+// Unregister unregister the instance and drop ServiceInstancePreUnregisteredEvent and ServiceInstanceUnregisteredEvent
 func (epsd *EventPublishingServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
 	f := func() error {
 		return epsd.serviceDiscovery.Unregister(instance)
@@ -85,26 +84,32 @@ func (epsd *EventPublishingServiceDiscovery) Unregister(instance registry.Servic
 		f, NewServiceInstanceUnregisteredEvent(epsd.serviceDiscovery, instance))
 }
 
+// GetDefaultPageSize returns the result of serviceDiscovery.GetDefaultPageSize
 func (epsd *EventPublishingServiceDiscovery) GetDefaultPageSize() int {
 	return epsd.serviceDiscovery.GetDefaultPageSize()
 }
 
+// GetServices returns the result of serviceDiscovery.GetServices
 func (epsd *EventPublishingServiceDiscovery) GetServices() *gxset.HashSet {
 	return epsd.serviceDiscovery.GetServices()
 }
 
+// GetInstances returns the result of serviceDiscovery.GetInstances
 func (epsd *EventPublishingServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
 	return epsd.serviceDiscovery.GetInstances(serviceName)
 }
 
+// GetInstancesByPage returns the result of serviceDiscovery.GetInstancesByPage
 func (epsd *EventPublishingServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
 	return epsd.serviceDiscovery.GetInstancesByPage(serviceName, offset, pageSize)
 }
 
+// GetHealthyInstancesByPage returns the result of serviceDiscovery.GetHealthyInstancesByPage
 func (epsd *EventPublishingServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
 	return epsd.serviceDiscovery.GetHealthyInstancesByPage(serviceName, offset, pageSize, healthy)
 }
 
+// GetRequestInstances returns result from serviceDiscovery.GetRequestInstances
 func (epsd *EventPublishingServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
 	return epsd.serviceDiscovery.GetRequestInstances(serviceNames, offset, requestedSize)
 }
@@ -115,14 +120,17 @@ func (epsd *EventPublishingServiceDiscovery) AddListener(listener *registry.Serv
 	return epsd.serviceDiscovery.AddListener(listener)
 }
 
+// DispatchEventByServiceName pass serviceName to serviceDiscovery
 func (epsd *EventPublishingServiceDiscovery) DispatchEventByServiceName(serviceName string) error {
-	return epsd.DispatchEventByServiceName(serviceName)
+	return epsd.serviceDiscovery.DispatchEventByServiceName(serviceName)
 }
 
+// DispatchEventForInstances pass params to serviceDiscovery
 func (epsd *EventPublishingServiceDiscovery) DispatchEventForInstances(serviceName string, instances []registry.ServiceInstance) error {
 	return epsd.serviceDiscovery.DispatchEventForInstances(serviceName, instances)
 }
 
+// DispatchEvent pass the event to serviceDiscovery
 func (epsd *EventPublishingServiceDiscovery) DispatchEvent(event *registry.ServiceInstancesChangedEvent) error {
 	return epsd.serviceDiscovery.DispatchEvent(event)
 }
@@ -143,6 +151,7 @@ func (epsd *EventPublishingServiceDiscovery) executeWithEvents(beforeEvent obser
 	return nil
 }
 
+// getMetadataService returns metadata service instance
 func getMetadataService() (service.MetadataService, error) {
 	return extension.GetMetadataService(config.GetApplicationConfig().MetadataType)
 }
diff --git a/registry/event/log_event_listener.go b/registry/event/log_event_listener.go
index a06d5e4499284c66017ebb7484e4ee46ad164f5d..0781a6d6db303ba3a1eb99b6b4c6d0743f9066b3 100644
--- a/registry/event/log_event_listener.go
+++ b/registry/event/log_event_listener.go
@@ -20,7 +20,9 @@ package event
 import (
 	"reflect"
 	"sync"
+)
 
+import (
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/common/observer"
diff --git a/registry/event/log_event_listener_test.go b/registry/event/log_event_listener_test.go
index f142168b65759455a1c46e3aa8dbb537298443bf..3136564687f74e4c5cebd13d135e097234b21284 100644
--- a/registry/event/log_event_listener_test.go
+++ b/registry/event/log_event_listener_test.go
@@ -19,7 +19,9 @@ package event
 
 import (
 	"testing"
+)
 
+import (
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/registry/event/metadata_service_url_params_customizer.go b/registry/event/metadata_service_url_params_customizer.go
index 06278f4e7793c8a0c36b9264ede896c1d6243cc8..6d8f99b327363c9a2d636079ef1f74e78d4e0184 100644
--- a/registry/event/metadata_service_url_params_customizer.go
+++ b/registry/event/metadata_service_url_params_customizer.go
@@ -19,9 +19,13 @@ package event
 
 import (
 	"encoding/json"
+)
 
+import (
 	gxset "github.com/dubbogo/gost/container/set"
+)
 
+import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
diff --git a/registry/event/metadata_service_url_params_customizer_test.go b/registry/event/metadata_service_url_params_customizer_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..98ae2df883f590f4c3e4b379bb5a0fcbe46d946c
--- /dev/null
+++ b/registry/event/metadata_service_url_params_customizer_test.go
@@ -0,0 +1,124 @@
+/*
+ * 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 event
+
+import (
+	"testing"
+)
+
+import (
+	gxset "github.com/dubbogo/gost/container/set"
+	"github.com/stretchr/testify/assert"
+)
+
+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/metadata/service"
+	"github.com/apache/dubbo-go/registry"
+)
+
+func prepareMetadataServiceForTest() {
+	config.GetApplicationConfig().MetadataType = "mock"
+	extension.SetMetadataService("mock", func() (service.MetadataService, error) {
+		return &mockMetadataService{
+			urls: []interface{}{"mock://localhost:8080?a=b"},
+		}, nil
+	})
+}
+
+func TestMetadataServiceURLParamsMetadataCustomizer(t *testing.T) {
+
+	prepareMetadataServiceForTest()
+
+	msup := &metadataServiceURLParamsMetadataCustomizer{exceptKeys: gxset.NewSet()}
+	assert.Equal(t, 0, msup.GetPriority())
+
+	msup.Customize(createInstance())
+}
+
+func createInstance() registry.ServiceInstance {
+	ins := &registry.DefaultServiceInstance{}
+	return ins
+}
+
+type mockMetadataService struct {
+	urls []interface{}
+}
+
+func (m *mockMetadataService) Reference() string {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) ServiceName() (string, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) ExportURL(url common.URL) (bool, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) UnexportURL(url common.URL) error {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) SubscribeURL(url common.URL) (bool, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) UnsubscribeURL(url common.URL) error {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) PublishServiceDefinition(url common.URL) error {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error) {
+	return m.urls, nil
+}
+
+func (m *mockMetadataService) MethodMapper() map[string]string {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) GetSubscribedURLs() ([]common.URL, error) {
+	res := make([]common.URL, 0, len(m.urls))
+	for _, ui := range m.urls {
+		u, _ := common.NewURL(ui.(string))
+		res = append(res, u)
+	}
+	return res, nil
+}
+
+func (m *mockMetadataService) GetServiceDefinition(interfaceName string, group string, version string) (string, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) GetServiceDefinitionByServiceKey(serviceKey string) (string, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) RefreshMetadata(exportedRevision string, subscribedRevision string) (bool, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) Version() (string, error) {
+	return "1.0.0", nil
+}
diff --git a/registry/event/protocol_ports_metadata_customizer.go b/registry/event/protocol_ports_metadata_customizer.go
index bf16fa8e2fd0a9fc02f377b8ee8c2d8bcca69396..cf5d1a8ec1a097037eb7f45aafac72661d3243ad 100644
--- a/registry/event/protocol_ports_metadata_customizer.go
+++ b/registry/event/protocol_ports_metadata_customizer.go
@@ -20,7 +20,9 @@ package event
 import (
 	"encoding/json"
 	"strconv"
+)
 
+import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
@@ -41,7 +43,7 @@ func (p *ProtocolPortsMetadataCustomizer) GetPriority() int {
 	return 0
 }
 
-// Customize will
+// Customize put the the string like [{"protocol": "dubbo", "port": 123}] into instance's metadata
 func (p *ProtocolPortsMetadataCustomizer) Customize(instance registry.ServiceInstance) {
 	metadataService, err := getMetadataService()
 	if err != nil {
@@ -49,12 +51,12 @@ func (p *ProtocolPortsMetadataCustomizer) Customize(instance registry.ServiceIns
 		return
 	}
 
-	// 4 is enough...
+	// 4 is enough... we don't have many protocol
 	protocolMap := make(map[string]int, 4)
 
 	list, err := metadataService.GetExportedURLs(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE)
 	if err != nil || len(list) == 0 {
-		logger.Errorf("Could not find exported urls", err)
+		logger.Debugf("Could not find exported urls", err)
 		return
 	}
 
@@ -75,6 +77,7 @@ func (p *ProtocolPortsMetadataCustomizer) Customize(instance registry.ServiceIns
 	instance.GetMetadata()[constant.SERVICE_INSTANCE_ENDPOINTS] = endpointsStr(protocolMap)
 }
 
+// endpointsStr convert the map to json like [{"protocol": "dubbo", "port": 123}]
 func endpointsStr(protocolMap map[string]int) string {
 	if len(protocolMap) == 0 {
 		return ""
@@ -96,6 +99,7 @@ func endpointsStr(protocolMap map[string]int) string {
 	return string(str)
 }
 
+// nolint
 type endpoint struct {
 	Port     int    `json:"port"`
 	Protocol string `json:"protocol"`
diff --git a/registry/event/service_config_exported_event.go b/registry/event/service_config_exported_event.go
index 7946609acdffa0e166ffc3559bd931114fa2c5d5..5ec027da3178f7aba066cdb1d684798e611953ea 100644
--- a/registry/event/service_config_exported_event.go
+++ b/registry/event/service_config_exported_event.go
@@ -19,16 +19,20 @@ package event
 
 import (
 	"time"
+)
 
+import (
 	"github.com/apache/dubbo-go/common/observer"
 	"github.com/apache/dubbo-go/config"
 )
 
+// ServiceConfigExportedEvent represents an service was exported
 type ServiceConfigExportedEvent struct {
 	observer.BaseEvent
 	ServiceConfig *config.ServiceConfig
 }
 
+// NewServiceConfigExportedEvent create an instance
 func NewServiceConfigExportedEvent(serviceConfig *config.ServiceConfig) *ServiceConfigExportedEvent {
 	return &ServiceConfigExportedEvent{
 		BaseEvent: observer.BaseEvent{
diff --git a/registry/event/service_discovery_event.go b/registry/event/service_discovery_event.go
index 74f6c5f19dd4b4cfb5ceaae4010df1d49b03aa41..13afa1a6aa63a8ad0721692d7e969d3af882b8f5 100644
--- a/registry/event/service_discovery_event.go
+++ b/registry/event/service_discovery_event.go
@@ -22,11 +22,13 @@ import (
 	"github.com/apache/dubbo-go/registry"
 )
 
+// ServiceDiscoveryEvent means that something happens to service discovery instance
 type ServiceDiscoveryEvent struct {
 	observer.BaseEvent
 	original registry.ServiceDiscovery
 }
 
+// NewServiceDiscoveryEvent returns an instance
 func NewServiceDiscoveryEvent(discovery registry.ServiceDiscovery, original registry.ServiceDiscovery) *ServiceDiscoveryEvent {
 	return &ServiceDiscoveryEvent{
 		BaseEvent: *observer.NewBaseEvent(discovery),
@@ -34,10 +36,12 @@ func NewServiceDiscoveryEvent(discovery registry.ServiceDiscovery, original regi
 	}
 }
 
+// GetServiceDiscovery returns the event source
 func (sde *ServiceDiscoveryEvent) GetServiceDiscovery() registry.ServiceDiscovery {
 	return sde.GetSource().(registry.ServiceDiscovery)
 }
 
+// GetOriginal actually I think we can remove this method.
 func (sde *ServiceDiscoveryEvent) GetOriginal() registry.ServiceDiscovery {
 	return sde.original
 }
diff --git a/registry/event/service_instance_event.go b/registry/event/service_instance_event.go
index 650b2e8e29e23498a49f11b58aa53b018ca42e67..d4f23c299a844f4aab25e7d656a2cb99692861d7 100644
--- a/registry/event/service_instance_event.go
+++ b/registry/event/service_instance_event.go
@@ -22,6 +22,8 @@ import (
 	"github.com/apache/dubbo-go/registry"
 )
 
+// ServiceInstanceEvent means something happen to this ServiceInstance
+// like register this service instance
 type ServiceInstanceEvent struct {
 	observer.BaseEvent
 	serviceInstance registry.ServiceInstance
@@ -35,6 +37,7 @@ func NewServiceInstanceEvent(source interface{}, instance registry.ServiceInstan
 	}
 }
 
+// getServiceInstance return the service instance
 func (sie *ServiceInstanceEvent) getServiceInstance() registry.ServiceInstance {
 	return sie.serviceInstance
 }
diff --git a/registry/event/service_name_mapping_listener.go b/registry/event/service_name_mapping_listener.go
index 68cf588c660d6106fbba8e45a896666a3ec3fe0a..a4ac8b28db5a3778cf39eef98886e1825521aa44 100644
--- a/registry/event/service_name_mapping_listener.go
+++ b/registry/event/service_name_mapping_listener.go
@@ -20,9 +20,13 @@ package event
 import (
 	"reflect"
 	"sync"
+)
 
+import (
 	perrors "github.com/pkg/errors"
+)
 
+import (
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/observer"
@@ -30,9 +34,12 @@ import (
 )
 
 func init() {
-	extension.AddEventListener(GetCustomizableServiceInstanceListener)
+	extension.AddEventListener(GetServiceNameMappingListener)
 }
 
+// serviceNameMappingListener listen to service name mapping event
+// usually it means that we exported some service
+// it's a singleton
 type serviceNameMappingListener struct {
 	nameMapping mapping.ServiceNameMapping
 }
@@ -42,6 +49,7 @@ func (s *serviceNameMappingListener) GetPriority() int {
 	return 3
 }
 
+// OnEvent only handle ServiceConfigExportedEvent
 func (s *serviceNameMappingListener) OnEvent(e observer.Event) error {
 	if ex, ok := e.(*ServiceConfigExportedEvent); ok {
 		sc := ex.ServiceConfig
@@ -60,6 +68,7 @@ func (s *serviceNameMappingListener) OnEvent(e observer.Event) error {
 	return nil
 }
 
+// GetEventType return ServiceConfigExportedEvent
 func (s *serviceNameMappingListener) GetEventType() reflect.Type {
 	return reflect.TypeOf(&ServiceConfigExportedEvent{})
 }
@@ -69,6 +78,7 @@ var (
 	serviceNameMappingListenerOnce     sync.Once
 )
 
+// GetServiceNameMappingListener returns an instance
 func GetServiceNameMappingListener() observer.EventListener {
 	serviceNameMappingListenerOnce.Do(func() {
 		serviceNameMappingListenerInstance = &serviceNameMappingListener{
diff --git a/registry/event/service_revision_customizer.go b/registry/event/service_revision_customizer.go
index fb1cda01a59537b9cfb850dacbbb661edeade428..fd21e8f4c7a71cedfe1de7e9c836e7cee278182e 100644
--- a/registry/event/service_revision_customizer.go
+++ b/registry/event/service_revision_customizer.go
@@ -21,7 +21,9 @@ import (
 	"fmt"
 	"hash/crc32"
 	"sort"
+)
 
+import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
@@ -45,6 +47,7 @@ func (e *exportedServicesRevisionMetadataCustomizer) GetPriority() int {
 	return 1
 }
 
+// Customize calculate the revision for exported urls and then put it into instance metadata
 func (e *exportedServicesRevisionMetadataCustomizer) Customize(instance registry.ServiceInstance) {
 	ms, err := getMetadataService()
 	if err != nil {
@@ -73,6 +76,7 @@ func (e *subscribedServicesRevisionMetadataCustomizer) GetPriority() int {
 	return 2
 }
 
+// Customize calculate the revision for subscribed urls and then put it into instance metadata
 func (e *subscribedServicesRevisionMetadataCustomizer) Customize(instance registry.ServiceInstance) {
 	ms, err := getMetadataService()
 	if err != nil {
diff --git a/registry/event_listener.go b/registry/event_listener.go
index 1cd5ad43a66acc70c6a7938f8d6532346fd6410d..9e9ec2d5d4bcb8d1af90fff73db1c6708427f7f7 100644
--- a/registry/event_listener.go
+++ b/registry/event_listener.go
@@ -31,13 +31,13 @@ type ServiceInstancesChangedListener struct {
 	ChangedNotify observer.ChangedNotify
 }
 
-// On ServiceInstancesChangedEvent the service instances change event
+// OnEvent on ServiceInstancesChangedEvent the service instances change event
 func (lstn *ServiceInstancesChangedListener) OnEvent(e observer.Event) error {
 	lstn.ChangedNotify.Notify(e)
 	return nil
 }
 
-// return true if the name is the same
+// Accept return true if the name is the same
 func (lstn *ServiceInstancesChangedListener) Accept(e observer.Event) bool {
 	if ce, ok := e.(*ServiceInstancesChangedEvent); ok {
 		return ce.ServiceName == lstn.ServiceName
@@ -45,12 +45,12 @@ func (lstn *ServiceInstancesChangedListener) Accept(e observer.Event) bool {
 	return false
 }
 
-// get listener priority
+// GetPriority returns -1, it will be the first invoked listener
 func (lstn *ServiceInstancesChangedListener) GetPriority() int {
 	return -1
 }
 
-// get event type
+// GetEventType returns ServiceInstancesChangedEvent
 func (lstn *ServiceInstancesChangedListener) GetEventType() reflect.Type {
 	return reflect.TypeOf(&ServiceInstancesChangedEvent{})
 }
diff --git a/registry/inmemory/service_discovery.go b/registry/inmemory/service_discovery.go
deleted file mode 100644
index f7c3ef3bb566e81587d3845c33ce7fb799b2cd43..0000000000000000000000000000000000000000
--- a/registry/inmemory/service_discovery.go
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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 inmemory
-
-import (
-	"github.com/dubbogo/gost/container/set"
-	"github.com/dubbogo/gost/page"
-)
-
-import (
-	"github.com/apache/dubbo-go/common/extension"
-	"github.com/apache/dubbo-go/registry"
-)
-
-const (
-	name = "in-memory"
-)
-
-func init() {
-
-	instance := &InMemoryServiceDiscovery{
-		instances: make(map[string]registry.ServiceInstance, 4),
-		listeners: make([]*registry.ServiceInstancesChangedListener, 0, 2),
-	}
-
-	extension.SetServiceDiscovery(name, func(name string) (discovery registry.ServiceDiscovery, err error) {
-		return instance, nil
-	})
-}
-
-// InMemoryServiceDiscovery is an implementation based on memory.
-// Usually you will not use this implementation except for tests.
-type InMemoryServiceDiscovery struct {
-	instances map[string]registry.ServiceInstance
-	listeners []*registry.ServiceInstancesChangedListener
-}
-
-func (i *InMemoryServiceDiscovery) String() string {
-	return name
-}
-
-// Destroy doesn't destroy the instance, it just clear the instances
-func (i *InMemoryServiceDiscovery) Destroy() error {
-	// reset to empty
-	i.instances = make(map[string]registry.ServiceInstance, 4)
-	i.listeners = make([]*registry.ServiceInstancesChangedListener, 0, 2)
-	return nil
-}
-
-// Register will store the instance using its id as key
-func (i *InMemoryServiceDiscovery) Register(instance registry.ServiceInstance) error {
-	i.instances[instance.GetId()] = instance
-	return nil
-}
-
-// Update will act like register
-func (i *InMemoryServiceDiscovery) Update(instance registry.ServiceInstance) error {
-	return i.Register(instance)
-}
-
-// Unregister will remove the instance
-func (i *InMemoryServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
-	delete(i.instances, instance.GetId())
-	return nil
-}
-
-// GetDefaultPageSize will return the default page size
-func (i *InMemoryServiceDiscovery) GetDefaultPageSize() int {
-	return registry.DefaultPageSize
-}
-
-// GetServices will return all service names
-func (i *InMemoryServiceDiscovery) GetServices() *gxset.HashSet {
-	result := gxset.NewSet()
-	for _, value := range i.instances {
-		result.Add(value.GetServiceName())
-	}
-	return result
-}
-
-// GetInstances will find out all instances with serviceName
-func (i *InMemoryServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
-	result := make([]registry.ServiceInstance, 0, len(i.instances))
-	for _, value := range i.instances {
-		if value.GetServiceName() == serviceName {
-			result = append(result, value)
-		}
-	}
-	return result
-}
-
-// GetInstancesByPage will return the part of instances
-func (i *InMemoryServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
-	instances := i.GetInstances(serviceName)
-	// we can not use []registry.ServiceInstance since New(...) received []interface{} as parameter
-	result := make([]interface{}, 0, pageSize)
-	for i := offset; i < len(instances) && i < offset+pageSize; i++ {
-		result = append(result, instances[i])
-	}
-	return gxpage.New(offset, pageSize, result, len(instances))
-}
-
-// GetHealthyInstancesByPage will return the instances
-func (i *InMemoryServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
-	instances := i.GetInstances(serviceName)
-	// we can not use []registry.ServiceInstance since New(...) received []interface{} as parameter
-	result := make([]interface{}, 0, pageSize)
-	count := 0
-	for i := offset; i < len(instances) && count < pageSize; i++ {
-		if instances[i].IsHealthy() == healthy {
-			result = append(result, instances[i])
-			count++
-		}
-	}
-	return gxpage.New(offset, pageSize, result, len(instances))
-}
-
-// GetRequestInstances will iterate the serviceName and aggregate them
-func (i *InMemoryServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
-	res := make(map[string]gxpage.Pager, len(serviceNames))
-	for _, name := range serviceNames {
-		res[name] = i.GetInstancesByPage(name, offset, requestedSize)
-	}
-	return res
-}
-
-// AddListener will save the listener inside the memory
-func (i *InMemoryServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
-	i.listeners = append(i.listeners, listener)
-	return nil
-}
-
-// DispatchEventByServiceName will do nothing
-func (i *InMemoryServiceDiscovery) DispatchEventByServiceName(serviceName string) error {
-	return nil
-}
-
-// DispatchEventForInstances will do nothing
-func (i *InMemoryServiceDiscovery) DispatchEventForInstances(serviceName string, instances []registry.ServiceInstance) error {
-	return nil
-}
-
-// DispatchEvent will do nothing
-func (i *InMemoryServiceDiscovery) DispatchEvent(event *registry.ServiceInstancesChangedEvent) error {
-	return nil
-}
diff --git a/registry/inmemory/service_discovery_test.go b/registry/inmemory/service_discovery_test.go
deleted file mode 100644
index fac4699913000c44a566e6a84f850150046f8ce0..0000000000000000000000000000000000000000
--- a/registry/inmemory/service_discovery_test.go
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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 inmemory
-
-import (
-	"testing"
-)
-
-import (
-	"github.com/stretchr/testify/assert"
-)
-
-import (
-	"github.com/apache/dubbo-go/common/extension"
-	"github.com/apache/dubbo-go/registry"
-)
-
-func TestInMemoryServiceDiscovery(t *testing.T) {
-	discovery, _ := extension.GetServiceDiscovery(name, "in")
-	serviceName := "my-service"
-	err := discovery.Register(&registry.DefaultServiceInstance{
-		ServiceName: serviceName,
-		Id:          "1",
-		Healthy:     true,
-	})
-	assert.Nil(t, err)
-
-	err = discovery.Register(&registry.DefaultServiceInstance{
-		Id:          "2",
-		ServiceName: "mock-service",
-		Healthy:     false,
-	})
-
-	assert.Nil(t, err)
-
-	services := discovery.GetServices()
-	assert.Equal(t, 2, services.Size())
-	assert.Equal(t, registry.DefaultPageSize, discovery.GetDefaultPageSize())
-
-	reqInstances := discovery.GetRequestInstances([]string{serviceName, "mock-service"}, 0, 10)
-	assert.Equal(t, 2, len(reqInstances))
-
-	page := discovery.GetInstancesByPage(serviceName, 0, 10)
-	assert.Equal(t, 1, page.GetDataSize())
-
-	discovery.GetHealthyInstancesByPage(serviceName, 0, 10, true)
-	page = discovery.GetInstancesByPage(serviceName, 0, 10)
-	assert.Equal(t, 1, page.GetDataSize())
-
-	err = discovery.AddListener(&registry.ServiceInstancesChangedListener{})
-	assert.Nil(t, err)
-
-	err = discovery.DispatchEvent(&registry.ServiceInstancesChangedEvent{})
-	assert.Nil(t, err)
-
-	err = discovery.DispatchEventForInstances(serviceName, nil)
-	assert.Nil(t, err)
-
-	err = discovery.DispatchEventByServiceName(serviceName)
-	assert.Nil(t, err)
-
-	err = discovery.Unregister(&registry.DefaultServiceInstance{
-		Id: "2",
-	})
-	assert.Nil(t, err)
-
-	services = discovery.GetServices()
-	assert.Equal(t, 1, services.Size())
-
-	err = discovery.Update(&registry.DefaultServiceInstance{
-		Id: "3",
-	})
-	assert.Nil(t, err)
-
-	services = discovery.GetServices()
-	assert.Equal(t, 2, services.Size())
-
-	err = discovery.Destroy()
-	assert.Nil(t, err)
-
-	services = discovery.GetServices()
-	assert.Equal(t, 0, services.Size())
-}
diff --git a/registry/kubernetes/listener.go b/registry/kubernetes/listener.go
index f8869fea7b77541eb929624cc1fa708c1218d7dd..24c8d81614c7dd323e4f23ec7de5d28b24eecb70 100644
--- a/registry/kubernetes/listener.go
+++ b/registry/kubernetes/listener.go
@@ -38,12 +38,12 @@ type dataListener struct {
 	listener      config_center.ConfigurationListener
 }
 
-// NewRegistryDataListener
+// NewRegistryDataListener creates a data listener for kubernetes
 func NewRegistryDataListener(listener config_center.ConfigurationListener) *dataListener {
 	return &dataListener{listener: listener}
 }
 
-// AddInterestedURL
+// AddInterestedURL adds the @url of registry center to the listener
 func (l *dataListener) AddInterestedURL(url *common.URL) {
 	l.interestedURL = append(l.interestedURL, url)
 }
@@ -91,10 +91,12 @@ func NewConfigurationListener(reg *kubernetesRegistry) *configurationListener {
 	return &configurationListener{registry: reg, events: make(chan *config_center.ConfigChangeEvent, 32)}
 }
 
+// Process processes the data change event from config center of kubernetes
 func (l *configurationListener) Process(configType *config_center.ConfigChangeEvent) {
 	l.events <- configType
 }
 
+// Next returns next service event once received
 func (l *configurationListener) Next() (*registry.ServiceEvent, error) {
 	for {
 		select {
@@ -103,7 +105,7 @@ func (l *configurationListener) Next() (*registry.ServiceEvent, error) {
 			return nil, perrors.New("listener stopped")
 
 		case e := <-l.events:
-			logger.Infof("got kubernetes event %#v", e)
+			logger.Debugf("got kubernetes event %#v", e)
 			if e.ConfigType == remoting.EventTypeDel && !l.registry.client.Valid() {
 				select {
 				case <-l.registry.Done():
@@ -116,6 +118,8 @@ func (l *configurationListener) Next() (*registry.ServiceEvent, error) {
 		}
 	}
 }
+
+// Close kubernetes registry center
 func (l *configurationListener) Close() {
 	l.registry.WaitGroup().Done()
 }
diff --git a/registry/kubernetes/listener_test.go b/registry/kubernetes/listener_test.go
index 1c9d8bdd5e0b713d61764163eff3b9fd3d5f320a..ccaaf80907f9eb3d4956758374f518c66fa613d5 100644
--- a/registry/kubernetes/listener_test.go
+++ b/registry/kubernetes/listener_test.go
@@ -18,24 +18,15 @@
 package kubernetes
 
 import (
-	"encoding/json"
-	"os"
-	"strconv"
 	"testing"
-	"time"
 )
 
 import (
 	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/suite"
-	"k8s.io/api/core/v1"
-	"k8s.io/client-go/kubernetes"
-	"k8s.io/client-go/kubernetes/fake"
 )
 
 import (
 	"github.com/apache/dubbo-go/common"
-	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/config_center"
 	"github.com/apache/dubbo-go/remoting"
 )
@@ -184,66 +175,7 @@ type MockDataListener struct{}
 
 func (*MockDataListener) Process(configType *config_center.ConfigChangeEvent) {}
 
-type KubernetesRegistryTestSuite struct {
-	suite.Suite
-
-	currentPod v1.Pod
-}
-
-func (s *KubernetesRegistryTestSuite) initRegistry() *kubernetesRegistry {
-	t := s.T()
-
-	regurl, err := common.NewURL("registry://127.0.0.1:443", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	mock, err := newMockKubernetesRegistry(&regurl, s.currentPod.GetNamespace(), func() (kubernetes.Interface, error) {
-
-		out := fake.NewSimpleClientset()
-
-		// mock current pod
-		if _, err = out.CoreV1().Pods(s.currentPod.GetNamespace()).Create(&s.currentPod); err != nil {
-			t.Fatal(err)
-		}
-		return out, nil
-	})
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	time.Sleep(time.Second)
-	return mock.(*kubernetesRegistry)
-}
-
-func (s *KubernetesRegistryTestSuite) SetupSuite() {
-
-	t := s.T()
-
-	const (
-		// kubernetes inject the var
-		podNameKey   = "HOSTNAME"
-		nameSpaceKey = "NAMESPACE"
-	)
-
-	// 1. install test data
-	if err := json.Unmarshal([]byte(clientPodJsonData), &s.currentPod); err != nil {
-		t.Fatal(err)
-	}
-
-	// 2. set downward-api inject env
-	if err := os.Setenv(podNameKey, s.currentPod.GetName()); err != nil {
-		t.Fatal(err)
-	}
-	if err := os.Setenv(nameSpaceKey, s.currentPod.GetNamespace()); err != nil {
-		t.Fatal(err)
-	}
-
-}
-
-func (s *KubernetesRegistryTestSuite) TestDataChange() {
-
-	t := s.T()
+func TestDataChange(t *testing.T) {
 
 	listener := NewRegistryDataListener(&MockDataListener{})
 	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")
@@ -252,7 +184,3 @@ func (s *KubernetesRegistryTestSuite) TestDataChange() {
 		t.Fatal("data change not ok")
 	}
 }
-
-func TestKubernetesRegistrySuite(t *testing.T) {
-	suite.Run(t, &KubernetesRegistryTestSuite{})
-}
diff --git a/registry/kubernetes/registry.go b/registry/kubernetes/registry.go
index 7ee0f6b0eeb83181bfd20e1abe4685e8319cd09b..7c5162670d85f661fb8460cc69537ac9b7a12a23 100644
--- a/registry/kubernetes/registry.go
+++ b/registry/kubernetes/registry.go
@@ -29,7 +29,7 @@ import (
 	"github.com/dubbogo/getty"
 	"github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
-	k8s "k8s.io/client-go/kubernetes"
+	v1 "k8s.io/api/core/v1"
 )
 
 import (
@@ -68,23 +68,28 @@ type kubernetesRegistry struct {
 	configListener *configurationListener
 }
 
+// Client gets the etcdv3 kubernetes
 func (r *kubernetesRegistry) Client() *kubernetes.Client {
 	r.cltLock.RLock()
 	client := r.client
 	r.cltLock.RUnlock()
 	return client
 }
+
+// SetClient sets the kubernetes client
 func (r *kubernetesRegistry) SetClient(client *kubernetes.Client) {
 	r.cltLock.Lock()
 	r.client = client
 	r.cltLock.Unlock()
 }
 
+// CloseAndNilClient closes listeners and clear client
 func (r *kubernetesRegistry) CloseAndNilClient() {
 	r.client.Close()
 	r.client = nil
 }
 
+// CloseListener closes listeners
 func (r *kubernetesRegistry) CloseListener() {
 
 	r.cltLock.Lock()
@@ -96,6 +101,7 @@ func (r *kubernetesRegistry) CloseListener() {
 	r.configListener = nil
 }
 
+// CreatePath create the path in the registry center of kubernetes
 func (r *kubernetesRegistry) CreatePath(k string) error {
 	if err := r.client.Create(k, ""); err != nil {
 		return perrors.WithMessagef(err, "create path %s in kubernetes", k)
@@ -103,6 +109,7 @@ func (r *kubernetesRegistry) CreatePath(k string) error {
 	return nil
 }
 
+// DoRegister actually do the register job in the registry center of kubernetes
 func (r *kubernetesRegistry) DoRegister(root string, node string) error {
 	return r.client.Create(path.Join(root, node), "")
 }
@@ -111,6 +118,7 @@ func (r *kubernetesRegistry) DoUnregister(root string, node string) error {
 	return perrors.New("DoUnregister is not support in kubernetesRegistry")
 }
 
+// DoSubscribe actually subscribe the provider URL
 func (r *kubernetesRegistry) DoSubscribe(svc *common.URL) (registry.Listener, error) {
 
 	var (
@@ -143,10 +151,12 @@ func (r *kubernetesRegistry) DoSubscribe(svc *common.URL) (registry.Listener, er
 	return configListener, nil
 }
 
+// nolint
 func (r *kubernetesRegistry) DoUnsubscribe(conf *common.URL) (registry.Listener, error) {
 	return nil, perrors.New("DoUnsubscribe is not support in kubernetesRegistry")
 }
 
+// InitListeners init listeners of kubernetes registry center
 func (r *kubernetesRegistry) InitListeners() {
 	r.listener = kubernetes.NewEventListener(r.client)
 	r.configListener = NewConfigurationListener(r)
@@ -168,15 +178,14 @@ func newKubernetesRegistry(url *common.URL) (registry.Registry, error) {
 	go r.HandleClientRestart()
 	r.InitListeners()
 
-	logger.Debugf("the kubernetes registry started")
+	logger.Debugf("kubernetes registry started")
 
 	return r, nil
 }
 
 func newMockKubernetesRegistry(
 	url *common.URL,
-	namespace string,
-	clientGeneratorFunc func() (k8s.Interface, error),
+	podsList *v1.PodList,
 ) (registry.Registry, error) {
 
 	var err error
@@ -184,7 +193,7 @@ func newMockKubernetesRegistry(
 	r := &kubernetesRegistry{}
 
 	r.InitBaseRegistry(url, r)
-	r.client, err = kubernetes.NewMockClient(namespace, clientGeneratorFunc)
+	r.client, err = kubernetes.NewMockClient(podsList)
 	if err != nil {
 		return nil, perrors.WithMessage(err, "new mock client")
 	}
@@ -192,6 +201,7 @@ func newMockKubernetesRegistry(
 	return r, nil
 }
 
+// HandleClientRestart will reconnect to  kubernetes registry center
 func (r *kubernetesRegistry) HandleClientRestart() {
 
 	var (
diff --git a/registry/kubernetes/registry_test.go b/registry/kubernetes/registry_test.go
index a650b189c39b94849dee4fbf7fc292e33e87b829..347dadcd2c462e3a1caf9829b051a665ec61e8e3 100644
--- a/registry/kubernetes/registry_test.go
+++ b/registry/kubernetes/registry_test.go
@@ -18,12 +18,17 @@
 package kubernetes
 
 import (
+	"encoding/json"
+	"os"
 	"strconv"
+	"sync"
+	"testing"
 	"time"
 )
 
 import (
 	"github.com/stretchr/testify/assert"
+	v1 "k8s.io/api/core/v1"
 )
 
 import (
@@ -31,11 +36,212 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
-func (s *KubernetesRegistryTestSuite) TestRegister() {
+var clientPodListJsonData = `{
+    "apiVersion": "v1",
+    "items": [
+        {
+            "apiVersion": "v1",
+            "kind": "Pod",
+            "metadata": {
+                "annotations": {
+                    "dubbo.io/annotation": "W3siayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvcHJvdmlkZXJzIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvcHJvdmlkZXJzL2R1YmJvJTNBJTJGJTJGMTcyLjE3LjAuNiUzQTIwMDAwJTJGVXNlclByb3ZpZGVyJTNGYWNjZXNzbG9nJTNEJTI2YW55aG9zdCUzRHRydWUlMjZhcHAudmVyc2lvbiUzRDAuMC4xJTI2YXBwbGljYXRpb24lM0RCRFRTZXJ2aWNlJTI2YXV0aCUzRCUyNmJlYW4ubmFtZSUzRFVzZXJQcm92aWRlciUyNmNsdXN0ZXIlM0RmYWlsb3ZlciUyNmVudmlyb25tZW50JTNEZGV2JTI2ZXhlY3V0ZS5saW1pdCUzRCUyNmV4ZWN1dGUubGltaXQucmVqZWN0ZWQuaGFuZGxlciUzRCUyNmdyb3VwJTNEJTI2aW50ZXJmYWNlJTNEY29tLmlrdXJlbnRvLnVzZXIuVXNlclByb3ZpZGVyJTI2aXAlM0QxNzIuMTcuMC42JTI2bG9hZGJhbGFuY2UlM0RyYW5kb20lMjZtZXRob2RzLkdldFVzZXIubG9hZGJhbGFuY2UlM0RyYW5kb20lMjZtZXRob2RzLkdldFVzZXIucmV0cmllcyUzRDElMjZtZXRob2RzLkdldFVzZXIudHBzLmxpbWl0LmludGVydmFsJTNEJTI2bWV0aG9kcy5HZXRVc2VyLnRwcy5saW1pdC5yYXRlJTNEJTI2bWV0aG9kcy5HZXRVc2VyLnRwcy5saW1pdC5zdHJhdGVneSUzRCUyNm1ldGhvZHMuR2V0VXNlci53ZWlnaHQlM0QwJTI2bW9kdWxlJTNEZHViYm9nbyUyQnVzZXItaW5mbyUyQnNlcnZlciUyNm5hbWUlM0RCRFRTZXJ2aWNlJTI2b3JnYW5pemF0aW9uJTNEaWt1cmVudG8uY29tJTI2b3duZXIlM0RaWCUyNnBhcmFtLnNpZ24lM0QlMjZwaWQlM0Q2JTI2cmVnaXN0cnkucm9sZSUzRDMlMjZyZWxlYXNlJTNEZHViYm8tZ29sYW5nLTEuMy4wJTI2cmV0cmllcyUzRCUyNnNlcnZpY2UuZmlsdGVyJTNEZWNobyUyNTJDdG9rZW4lMjUyQ2FjY2Vzc2xvZyUyNTJDdHBzJTI1MkNnZW5lcmljX3NlcnZpY2UlMjUyQ2V4ZWN1dGUlMjUyQ3BzaHV0ZG93biUyNnNpZGUlM0Rwcm92aWRlciUyNnRpbWVzdGFtcCUzRDE1OTExNTYxNTUlMjZ0cHMubGltaXQuaW50ZXJ2YWwlM0QlMjZ0cHMubGltaXQucmF0ZSUzRCUyNnRwcy5saW1pdC5yZWplY3RlZC5oYW5kbGVyJTNEJTI2dHBzLmxpbWl0LnN0cmF0ZWd5JTNEJTI2dHBzLmxpbWl0ZXIlM0QlMjZ2ZXJzaW9uJTNEJTI2d2FybXVwJTNEMTAwIiwidiI6IiJ9XQ=="
+                },
+                "creationTimestamp": "2020-06-03T03:49:14Z",
+                "generateName": "server-84c864f5bc-",
+                "labels": {
+                    "dubbo.io/label": "dubbo.io-value",
+                    "pod-template-hash": "84c864f5bc",
+                    "role": "server"
+                },
+                "name": "server-84c864f5bc-r8qvz",
+                "namespace": "default",
+                "ownerReferences": [
+                    {
+                        "apiVersion": "apps/v1",
+                        "blockOwnerDeletion": true,
+                        "controller": true,
+                        "kind": "ReplicaSet",
+                        "name": "server-84c864f5bc",
+                        "uid": "fa376dbb-4f37-4705-8e80-727f592c19b3"
+                    }
+                ],
+                "resourceVersion": "517460",
+                "selfLink": "/api/v1/namespaces/default/pods/server-84c864f5bc-r8qvz",
+                "uid": "f4fc811c-200c-4445-8d4f-532144957dcc"
+            },
+            "spec": {
+                "containers": [
+                    {
+                        "env": [
+                            {
+                                "name": "DUBBO_NAMESPACE",
+                                "value": "default"
+                            },
+                            {
+                                "name": "NAMESPACE",
+                                "valueFrom": {
+                                    "fieldRef": {
+                                        "apiVersion": "v1",
+                                        "fieldPath": "metadata.namespace"
+                                    }
+                                }
+                            }
+                        ],
+                        "image": "192.168.240.101:5000/scott/go-server",
+                        "imagePullPolicy": "Always",
+                        "name": "server",
+                        "resources": {},
+                        "terminationMessagePath": "/dev/termination-log",
+                        "terminationMessagePolicy": "File",
+                        "volumeMounts": [
+                            {
+                                "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
+                                "name": "dubbo-sa-token-5qbtb",
+                                "readOnly": true
+                            }
+                        ]
+                    }
+                ],
+                "dnsPolicy": "ClusterFirst",
+                "enableServiceLinks": true,
+                "nodeName": "minikube",
+                "priority": 0,
+                "restartPolicy": "Always",
+                "schedulerName": "default-scheduler",
+                "securityContext": {},
+                "serviceAccount": "dubbo-sa",
+                "serviceAccountName": "dubbo-sa",
+                "terminationGracePeriodSeconds": 30,
+                "tolerations": [
+                    {
+                        "effect": "NoExecute",
+                        "key": "node.kubernetes.io/not-ready",
+                        "operator": "Exists",
+                        "tolerationSeconds": 300
+                    },
+                    {
+                        "effect": "NoExecute",
+                        "key": "node.kubernetes.io/unreachable",
+                        "operator": "Exists",
+                        "tolerationSeconds": 300
+                    }
+                ],
+                "volumes": [
+                    {
+                        "name": "dubbo-sa-token-5qbtb",
+                        "secret": {
+                            "defaultMode": 420,
+                            "secretName": "dubbo-sa-token-5qbtb"
+                        }
+                    }
+                ]
+            },
+            "status": {
+                "conditions": [
+                    {
+                        "lastProbeTime": null,
+                        "lastTransitionTime": "2020-06-03T03:49:14Z",
+                        "status": "True",
+                        "type": "Initialized"
+                    },
+                    {
+                        "lastProbeTime": null,
+                        "lastTransitionTime": "2020-06-03T03:49:15Z",
+                        "status": "True",
+                        "type": "Ready"
+                    },
+                    {
+                        "lastProbeTime": null,
+                        "lastTransitionTime": "2020-06-03T03:49:15Z",
+                        "status": "True",
+                        "type": "ContainersReady"
+                    },
+                    {
+                        "lastProbeTime": null,
+                        "lastTransitionTime": "2020-06-03T03:49:14Z",
+                        "status": "True",
+                        "type": "PodScheduled"
+                    }
+                ],
+                "containerStatuses": [
+                    {
+                        "containerID": "docker://b6421e05ce44f8a1c4fa6b72274980777c7c0f945516209f7c0558cd0cd65406",
+                        "image": "192.168.240.101:5000/scott/go-server:latest",
+                        "imageID": "docker-pullable://192.168.240.101:5000/scott/go-server@sha256:4eecf895054f0ff93d80db64992a561d10504e55582def6dcb6093a6d6d92461",
+                        "lastState": {},
+                        "name": "server",
+                        "ready": true,
+                        "restartCount": 0,
+                        "started": true,
+                        "state": {
+                            "running": {
+                                "startedAt": "2020-06-03T03:49:15Z"
+                            }
+                        }
+                    }
+                ],
+                "hostIP": "10.0.2.15",
+                "phase": "Running",
+                "podIP": "172.17.0.6",
+                "podIPs": [
+                    {
+                        "ip": "172.17.0.6"
+                    }
+                ],
+                "qosClass": "BestEffort",
+                "startTime": "2020-06-03T03:49:14Z"
+            }
+        }
+    ],
+    "kind": "List",
+    "metadata": {
+        "resourceVersion": "",
+        "selfLink": ""
+    }
+}
+`
+
+func getTestRegistry(t *testing.T) *kubernetesRegistry {
+
+	const (
+		podNameKey              = "HOSTNAME"
+		nameSpaceKey            = "NAMESPACE"
+		needWatchedNameSpaceKey = "DUBBO_NAMESPACE"
+	)
+	pl := &v1.PodList{}
+	// 1. install test data
+	if err := json.Unmarshal([]byte(clientPodListJsonData), &pl); err != nil {
+		t.Fatal(err)
+	}
+	currentPod := pl.Items[0]
+
+	env := map[string]string{
+		nameSpaceKey:            currentPod.GetNamespace(),
+		podNameKey:              currentPod.GetName(),
+		needWatchedNameSpaceKey: "default",
+	}
 
-	t := s.T()
+	for k, v := range env {
+		if err := os.Setenv(k, v); err != nil {
+			t.Fatal(err)
+		}
+	}
 
-	r := s.initRegistry()
+	regurl, err := common.NewURL("registry://127.0.0.1:443", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	if err != nil {
+		t.Fatal(err)
+	}
+	out, err := newMockKubernetesRegistry(&regurl, pl)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	return out.(*kubernetesRegistry)
+}
+
+func TestRegister(t *testing.T) {
+
+	r := getTestRegistry(t)
 	defer r.Destroy()
 
 	url, _ := common.NewURL(
@@ -52,41 +258,44 @@ func (s *KubernetesRegistryTestSuite) TestRegister() {
 	}
 }
 
-func (s *KubernetesRegistryTestSuite) TestSubscribe() {
+func TestSubscribe(t *testing.T) {
 
-	t := s.T()
-
-	r := s.initRegistry()
+	r := getTestRegistry(t)
 	defer r.Destroy()
 
-	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	url, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	if err != nil {
+		t.Fatal(err)
+	}
 
 	listener, err := r.DoSubscribe(&url)
 	if err != nil {
 		t.Fatal(err)
 	}
-	time.Sleep(1e9)
 
+	wg := sync.WaitGroup{}
+	wg.Add(1)
 	go func() {
+
+		defer wg.Done()
 		registerErr := r.Register(url)
 		if registerErr != nil {
 			t.Fatal(registerErr)
 		}
 	}()
 
+	wg.Wait()
+
 	serviceEvent, err := listener.Next()
 	if err != nil {
 		t.Fatal(err)
 	}
-
-	t.Logf("got event %s", serviceEvent)
+	t.Logf("get service event %s", serviceEvent)
 }
 
-func (s *KubernetesRegistryTestSuite) TestConsumerDestroy() {
+func TestConsumerDestroy(t *testing.T) {
 
-	t := s.T()
-
-	r := s.initRegistry()
+	r := getTestRegistry(t)
 
 	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
@@ -105,11 +314,9 @@ func (s *KubernetesRegistryTestSuite) TestConsumerDestroy() {
 
 }
 
-func (s *KubernetesRegistryTestSuite) TestProviderDestroy() {
-
-	t := s.T()
+func TestProviderDestroy(t *testing.T) {
 
-	r := s.initRegistry()
+	r := getTestRegistry(t)
 
 	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider",
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
@@ -122,9 +329,7 @@ func (s *KubernetesRegistryTestSuite) TestProviderDestroy() {
 	assert.Equal(t, false, r.IsAvailable())
 }
 
-func (s *KubernetesRegistryTestSuite) TestNewRegistry() {
-
-	t := s.T()
+func TestNewRegistry(t *testing.T) {
 
 	regUrl, err := common.NewURL("registry://127.0.0.1:443",
 		common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
@@ -137,9 +342,9 @@ func (s *KubernetesRegistryTestSuite) TestNewRegistry() {
 	}
 }
 
-func (s *KubernetesRegistryTestSuite) TestHandleClientRestart() {
+func TestHandleClientRestart(t *testing.T) {
 
-	r := s.initRegistry()
+	r := getTestRegistry(t)
 	r.WaitGroup().Add(1)
 	go r.HandleClientRestart()
 	time.Sleep(timeSecondDuration(1))
diff --git a/registry/mock_registry.go b/registry/mock_registry.go
index f39490a26755a96aab1438d965bd8ee6fc75006f..10561d0f49e995c94c93fa0463fc0b0421ff6e20 100644
--- a/registry/mock_registry.go
+++ b/registry/mock_registry.go
@@ -30,13 +30,13 @@ import (
 	"github.com/apache/dubbo-go/common/logger"
 )
 
-// MockRegistry ...
+// MockRegistry is used as mock registry
 type MockRegistry struct {
 	listener  *listener
 	destroyed *atomic.Bool
 }
 
-// NewMockRegistry ...
+// NewMockRegistry creates a mock registry
 func NewMockRegistry(url *common.URL) (Registry, error) {
 	registry := &MockRegistry{
 		destroyed: atomic.NewBool(false),
@@ -46,28 +46,28 @@ func NewMockRegistry(url *common.URL) (Registry, error) {
 	return registry, nil
 }
 
-// Register ...
+// Register is used as a mock registry
 func (*MockRegistry) Register(url common.URL) error {
 	return nil
 }
 
-// UnRegister
+// nolint
 func (r *MockRegistry) UnRegister(conf common.URL) error {
 	return nil
 }
 
-// Destroy ...
+// nolint
 func (r *MockRegistry) Destroy() {
 	if r.destroyed.CAS(false, true) {
 	}
 }
 
-// IsAvailable ...
+// IsAvailable is use for determine a mock registry available
 func (r *MockRegistry) IsAvailable() bool {
 	return !r.destroyed.Load()
 }
 
-// GetUrl ...
+// nolint
 func (r *MockRegistry) GetUrl() common.URL {
 	return common.URL{}
 }
@@ -76,7 +76,7 @@ func (r *MockRegistry) subscribe(*common.URL) (Listener, error) {
 	return r.listener, nil
 }
 
-// Subscribe ...
+// nolint
 func (r *MockRegistry) Subscribe(url *common.URL, notifyListener NotifyListener) error {
 	go func() {
 		for {
@@ -134,7 +134,7 @@ func (*listener) Close() {
 
 }
 
-// MockEvent ...
+// nolint
 func (r *MockRegistry) MockEvent(event *ServiceEvent) {
 	r.listener.listenChan <- event
 }
diff --git a/registry/nacos/listener.go b/registry/nacos/listener.go
index a2237dca265f25b07b19a8e1f4fe5a5f6ea9183e..36f733df5a32f57e3410a2f31f9ab4b0af735d49 100644
--- a/registry/nacos/listener.go
+++ b/registry/nacos/listener.go
@@ -51,7 +51,7 @@ type nacosListener struct {
 	subscribeParam *vo.SubscribeParam
 }
 
-// NewNacosListener ...
+// NewRegistryDataListener creates a data listener for nacos
 func NewNacosListener(url common.URL, namingClient naming_client.INamingClient) (*nacosListener, error) {
 	listener := &nacosListener{
 		namingClient: namingClient,
@@ -109,6 +109,7 @@ func generateUrl(instance model.Instance) *common.URL {
 	)
 }
 
+// Callback will be invoked when got subscribed events.
 func (nl *nacosListener) Callback(services []model.SubscribeService, err error) {
 	if err != nil {
 		logger.Errorf("nacos subscribe callback error:%s , subscribe:%+v ", err.Error(), nl.subscribeParam)
@@ -198,6 +199,7 @@ func (nl *nacosListener) process(configType *config_center.ConfigChangeEvent) {
 	nl.events <- configType
 }
 
+// Next returns the service event from nacos.
 func (nl *nacosListener) Next() (*registry.ServiceEvent, error) {
 	for {
 		select {
@@ -212,6 +214,7 @@ func (nl *nacosListener) Next() (*registry.ServiceEvent, error) {
 	}
 }
 
+// nolint
 func (nl *nacosListener) Close() {
 	nl.stopListen()
 	close(nl.done)
diff --git a/registry/nacos/registry.go b/registry/nacos/registry.go
index 2b6cab45c2f5b552738bce3a352e774aa4b8cbcd..51d3e2f56abac8e4ab8b966870f1ff5bb79c4171 100644
--- a/registry/nacos/registry.go
+++ b/registry/nacos/registry.go
@@ -23,14 +23,13 @@ import (
 	"strconv"
 	"strings"
 	"time"
-
-	"github.com/nacos-group/nacos-sdk-go/clients"
-	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
-	nacosConstant "github.com/nacos-group/nacos-sdk-go/common/constant"
 )
 
 import (
 	gxnet "github.com/dubbogo/gost/net"
+	"github.com/nacos-group/nacos-sdk-go/clients"
+	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
+	nacosConstant "github.com/nacos-group/nacos-sdk-go/common/constant"
 	"github.com/nacos-group/nacos-sdk-go/vo"
 	perrors "github.com/pkg/errors"
 )
@@ -118,6 +117,7 @@ func createRegisterParam(url common.URL, serviceName string) vo.RegisterInstance
 	return instance
 }
 
+// Register will register the service @url to its nacos registry center
 func (nr *nacosRegistry) Register(url common.URL) error {
 	serviceName := getServiceName(url)
 	param := createRegisterParam(url, serviceName)
@@ -180,15 +180,18 @@ func (nr *nacosRegistry) UnSubscribe(url *common.URL, notifyListener registry.No
 	return perrors.New("UnSubscribe not support in nacosRegistry")
 }
 
+// GetUrl gets its registration URL
 func (nr *nacosRegistry) GetUrl() common.URL {
 	return *nr.URL
 }
 
+// IsAvailable determines nacos registry center whether it is available
 func (nr *nacosRegistry) IsAvailable() bool {
 	// TODO
 	return true
 }
 
+// nolint
 func (nr *nacosRegistry) Destroy() {
 	return
 }
diff --git a/registry/nacos/service_discovery.go b/registry/nacos/service_discovery.go
index 5b952e2541d4fd61e247543195786f1141ae2a85..63d92d70fd5e1a00f0ce1ca95b1926fb9c36c84b 100644
--- a/registry/nacos/service_discovery.go
+++ b/registry/nacos/service_discovery.go
@@ -20,23 +20,24 @@ package nacos
 import (
 	"fmt"
 	"sync"
+)
 
+import (
 	"github.com/dubbogo/gost/container/set"
 	"github.com/dubbogo/gost/page"
 	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
 	"github.com/nacos-group/nacos-sdk-go/model"
 	"github.com/nacos-group/nacos-sdk-go/vo"
 	perrors "github.com/pkg/errors"
-
-	"github.com/apache/dubbo-go/config"
-	"github.com/apache/dubbo-go/remoting/nacos"
 )
 
 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/config"
 	"github.com/apache/dubbo-go/registry"
+	"github.com/apache/dubbo-go/remoting/nacos"
 )
 
 const (
diff --git a/registry/nacos/service_discovery_test.go b/registry/nacos/service_discovery_test.go
index 633a1d41c81ed88b40db3a637333e6795abed871..720c44a6f98e4693bb2395a538b2f5e679196647 100644
--- a/registry/nacos/service_discovery_test.go
+++ b/registry/nacos/service_discovery_test.go
@@ -19,8 +19,6 @@ package nacos
 
 import (
 	"testing"
-
-	"github.com/apache/dubbo-go/config"
 )
 
 import (
@@ -32,6 +30,7 @@ import (
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/observer"
 	"github.com/apache/dubbo-go/common/observer/dispatcher"
+	"github.com/apache/dubbo-go/config"
 	"github.com/apache/dubbo-go/registry"
 )
 
diff --git a/registry/protocol/protocol.go b/registry/protocol/protocol.go
index a936db80bf2c3b46ba389142cc40686ed3df17b1..4c669b2cee74b95ceb3bc8287f145ccd6b99bc0b 100644
--- a/registry/protocol/protocol.go
+++ b/registry/protocol/protocol.go
@@ -117,6 +117,7 @@ func (proto *registryProtocol) initConfigurationListeners() {
 	proto.providerConfigurationListener = newProviderConfigurationListener(proto.overrideListeners)
 }
 
+// Refer provider service from registry center
 func (proto *registryProtocol) Refer(url common.URL) protocol.Invoker {
 	var registryUrl = url
 	var serviceUrl = registryUrl.SubURL
@@ -156,6 +157,7 @@ func (proto *registryProtocol) Refer(url common.URL) protocol.Invoker {
 	return invoker
 }
 
+// Export provider service to registry center
 func (proto *registryProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	proto.once.Do(func() {
 		proto.initConfigurationListeners()
@@ -229,6 +231,7 @@ func newOverrideSubscribeListener(overriderUrl *common.URL, invoker protocol.Inv
 	return &overrideSubscribeListener{url: overriderUrl, originInvoker: invoker, protocol: proto}
 }
 
+// Notify will be triggered when a service change notification is received.
 func (nl *overrideSubscribeListener) Notify(event *registry.ServiceEvent) {
 	if isMatched(&(event.Service), nl.url) && event.Action == remoting.EventTypeAdd {
 		nl.configurator = extension.GetDefaultConfigurator(&(event.Service))
@@ -325,6 +328,7 @@ func getSubscribedOverrideUrl(providerUrl *common.URL) *common.URL {
 	return newUrl
 }
 
+// Destroy registry protocol
 func (proto *registryProtocol) Destroy() {
 	for _, ivk := range proto.invokers {
 		ivk.Destroy()
@@ -389,6 +393,7 @@ func newWrappedInvoker(invoker protocol.Invoker, url *common.URL) *wrappedInvoke
 	}
 }
 
+// Invoke remote service base on URL of wrappedInvoker
 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())
@@ -411,6 +416,7 @@ func newProviderConfigurationListener(overrideListeners *sync.Map) *providerConf
 	return listener
 }
 
+// Process notified once there's any change happens on the provider config
 func (listener *providerConfigurationListener) Process(event *config_center.ConfigChangeEvent) {
 	listener.BaseConfigurationListener.Process(event)
 	listener.overrideListeners.Range(func(key, value interface{}) bool {
@@ -435,6 +441,7 @@ func newServiceConfigurationListener(overrideListener *overrideSubscribeListener
 	return listener
 }
 
+// Process notified once there's any change happens on the service config
 func (listener *serviceConfigurationListener) Process(event *config_center.ConfigChangeEvent) {
 	listener.BaseConfigurationListener.Process(event)
 	listener.overrideListener.doOverrideIfNecessary()
diff --git a/registry/registry.go b/registry/registry.go
index ce214c4971b0b00b5e300542ad9172331a0b3d02..bb09ead7ef2af6707345086f8695b35286d76a10 100644
--- a/registry/registry.go
+++ b/registry/registry.go
@@ -58,13 +58,16 @@ type Registry interface {
 	UnSubscribe(*common.URL, NotifyListener) error
 }
 
-// NotifyListener ...
+// nolint
 type NotifyListener interface {
+	// Notify supports notifications on the service interface and the dimension of the data type.
 	Notify(*ServiceEvent)
 }
 
 // Listener Deprecated!
 type Listener interface {
+	// Next returns next service event once received
 	Next() (*ServiceEvent, error)
+	// Close closes this listener
 	Close()
 }
diff --git a/registry/service_discovery.go b/registry/service_discovery.go
index a8228a4abe8ed07e3c5afda300702f778daea4ae..cb7a3c0182ff88995ab9dd6c920523225c3cb36c 100644
--- a/registry/service_discovery.go
+++ b/registry/service_discovery.go
@@ -28,6 +28,7 @@ import (
 
 const DefaultPageSize = 100
 
+// ServiceDiscovery is the common operations of Service Discovery
 type ServiceDiscovery interface {
 	fmt.Stringer
 
diff --git a/registry/service_instance.go b/registry/service_instance.go
index 08ca79ecbf5ae96832516335f7d55fdfb2996938..dbb458284d48aa350f2d5d3408b187b437ac81cd 100644
--- a/registry/service_instance.go
+++ b/registry/service_instance.go
@@ -21,6 +21,7 @@ import (
 	gxsort "github.com/dubbogo/gost/sort"
 )
 
+// ServiceInstance is the model class of an instance of a service, which is used for service registration and discovery.
 type ServiceInstance interface {
 
 	// GetId will return this instance's id. It should be unique.
diff --git a/registry/servicediscovery/service_discovery_registry.go b/registry/servicediscovery/service_discovery_registry.go
index 41054824a24ab68fe2d18ac47e03d0e6532aae0f..d6cce32f929ad7a4558e3af099a0dd3dbcd779af 100644
--- a/registry/servicediscovery/service_discovery_registry.go
+++ b/registry/servicediscovery/service_discovery_registry.go
@@ -23,12 +23,17 @@ import (
 	"strconv"
 	"strings"
 	"sync"
+)
 
+import (
 	cm "github.com/Workiva/go-datastructures/common"
 	gxset "github.com/dubbogo/gost/container/set"
 	gxnet "github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
+	"go.uber.org/atomic"
+)
 
+import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
@@ -177,10 +182,16 @@ func (s *serviceDiscoveryRegistry) Register(url common.URL) error {
 	if err != nil {
 		return perrors.WithMessage(err, "could not create servcie instance, please check your service url")
 	}
+
 	err = s.serviceDiscovery.Register(ins)
 	if err != nil {
 		return perrors.WithMessage(err, "register the service failed")
 	}
+
+	err = s.metaDataService.PublishServiceDefinition(url)
+	if err != nil {
+		return perrors.WithMessage(err, "publish the service definition failed. ")
+	}
 	return s.serviceNameMapping.Map(url.GetParam(constant.INTERFACE_KEY, ""),
 		url.GetParam(constant.GROUP_KEY, ""),
 		url.GetParam(constant.Version, ""),
@@ -668,8 +679,12 @@ func (icn *InstanceChangeNotify) Notify(event observer.Event) {
 	}
 }
 
-var exporting = false
+var (
+	exporting = &atomic.Bool{}
+)
 
+// tryInitMetadataService will try to initialize metadata service
+// TODO (move to somewhere)
 func tryInitMetadataService() {
 
 	ms, err := extension.GetMetadataService(config.GetApplicationConfig().MetadataType)
@@ -677,11 +692,16 @@ func tryInitMetadataService() {
 		logger.Errorf("could not init metadata service", err)
 	}
 
-	if !config.IsProvider() || exporting {
+	if !config.IsProvider() || exporting.Load() {
 		return
 	}
 
-	exporting = true
+	// In theory, we can use sync.Once
+	// But sync.Once is not reentrant.
+	// Now the invocation chain is createRegistry -> tryInitMetadataService -> metadataServiceExporter.export
+	// -> createRegistry -> initMetadataService...
+	// So using sync.Once will result in dead lock
+	exporting.Store(true)
 
 	expt := configurable.NewMetadataServiceExporter(ms)
 
diff --git a/registry/servicediscovery/service_discovery_registry_test.go b/registry/servicediscovery/service_discovery_registry_test.go
index 247cfd65eb0de5e85a4c046dbda844b2606bc3ac..53eb86507e635be32eb362519922f7042f945519 100644
--- a/registry/servicediscovery/service_discovery_registry_test.go
+++ b/registry/servicediscovery/service_discovery_registry_test.go
@@ -21,29 +21,226 @@ import (
 	"testing"
 )
 
+import (
+	"github.com/dubbogo/gost/container/set"
+	"github.com/dubbogo/gost/page"
+	"github.com/stretchr/testify/assert"
+)
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/common/observer"
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/metadata/mapping"
+	"github.com/apache/dubbo-go/metadata/service"
+	"github.com/apache/dubbo-go/registry"
+)
+
 var (
-	SERVICE_INTERFACE = "org.apache.dubbo.metadata.MetadataService"
-	GROUP             = "dubbo-provider"
-	VERSION           = "1.0.0"
+	serviceInterface = "org.apache.dubbo.metadata.MetadataService"
+	group            = "dubbo-provider"
+	version          = "1.0.0"
 )
 
 func TestServiceDiscoveryRegistry_Register(t *testing.T) {
-	// registryURL,_:=event.NewURL("in-memory://localhost:12345",
-	//	event.WithParamsValue("registry-type","service"),
-	//	event.WithParamsValue("subscribed-services","a, b , c,d,e ,"))
-	// url,_:=event.NewURL("dubbo://192.168.0.102:20880/"+ SERVICE_INTERFACE +
-	//	"?&application=" + GROUP +
-	//	"&interface=" + SERVICE_INTERFACE +
-	//	"&group=" + GROUP +
-	//	"&version=" + VERSION +
-	//	"&methods=getAllServiceKeys,getServiceRestMetadata,getExportedURLs,getAllExportedURLs" +
-	//	"&side=provider")
-	//registry,err:=newServiceDiscoveryRegistry(&registryURL)
-	//if err!=nil{
-	//	logger.Errorf("create service discovery registry catch error:%s",err.Error())
-	//}
-	//assert.Nil(t,err)
-	//assert.NotNil(t,registry)
-	//registry.Register(url)
+	config.GetApplicationConfig().MetadataType = "mock"
+	extension.SetMetadataService("mock", func() (service service.MetadataService, err error) {
+		service = &mockMetadataService{}
+		return
+	})
+
+	extension.SetServiceDiscovery("mock", func(name string) (discovery registry.ServiceDiscovery, err error) {
+		return &mockServiceDiscovery{}, nil
+	})
+
+	extension.SetGlobalServiceNameMapping(func() mapping.ServiceNameMapping {
+		return &mockServiceNameMapping{}
+	})
+
+	extension.SetEventDispatcher("mock", func() observer.EventDispatcher {
+		return &mockEventDispatcher{}
+	})
+	extension.SetAndInitGlobalDispatcher("mock")
+
+	config.GetBaseConfig().ServiceDiscoveries["mock"] = &config.ServiceDiscoveryConfig{
+		Protocol: "mock",
+	}
+	registryURL, _ := common.NewURL("service-discovery://localhost:12345",
+		common.WithParamsValue("service_discovery", "mock"),
+		common.WithParamsValue("subscribed-services", "a, b , c,d,e ,"))
+	url, _ := common.NewURL("dubbo://192.168.0.102:20880/" + serviceInterface +
+		"?&application=" + group +
+		"&interface=" + serviceInterface +
+		"&group=" + group +
+		"&version=" + version +
+		"&service_discovery=mock" +
+		"&methods=getAllServiceKeys,getServiceRestMetadata,getExportedURLs,getAllExportedURLs" +
+		"&side=provider")
+	registry, err := newServiceDiscoveryRegistry(&registryURL)
+	assert.Nil(t, err)
+	assert.NotNil(t, registry)
+	registry.Register(url)
+}
+
+type mockEventDispatcher struct {
+}
+
+func (m *mockEventDispatcher) AddEventListener(listener observer.EventListener) {
+
+}
+
+func (m *mockEventDispatcher) AddEventListeners(listenersSlice []observer.EventListener) {
+
+}
+
+func (m *mockEventDispatcher) RemoveEventListener(listener observer.EventListener) {
+	panic("implement me")
+}
+
+func (m *mockEventDispatcher) RemoveEventListeners(listenersSlice []observer.EventListener) {
+	panic("implement me")
+}
+
+func (m *mockEventDispatcher) GetAllEventListeners() []observer.EventListener {
+	return []observer.EventListener{}
+}
+
+func (m *mockEventDispatcher) RemoveAllEventListeners() {
+	panic("implement me")
+}
+
+func (m *mockEventDispatcher) Dispatch(event observer.Event) {
+}
+
+type mockServiceNameMapping struct {
+}
+
+func (m *mockServiceNameMapping) Map(serviceInterface string, group string, version string, protocol string) error {
+	return nil
+}
+
+func (m *mockServiceNameMapping) Get(serviceInterface string, group string, version string, protocol string) (*gxset.HashSet, error) {
+	panic("implement me")
+}
+
+type mockServiceDiscovery struct {
+}
+
+func (m *mockServiceDiscovery) String() string {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) Destroy() error {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) Register(instance registry.ServiceInstance) error {
+	return nil
+}
+
+func (m *mockServiceDiscovery) Update(instance registry.ServiceInstance) error {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) GetDefaultPageSize() int {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) GetServices() *gxset.HashSet {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) DispatchEventByServiceName(serviceName string) error {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) DispatchEventForInstances(serviceName string, instances []registry.ServiceInstance) error {
+	panic("implement me")
+}
+
+func (m *mockServiceDiscovery) DispatchEvent(event *registry.ServiceInstancesChangedEvent) error {
+	panic("implement me")
+}
+
+type mockMetadataService struct {
+}
+
+func (m *mockMetadataService) Reference() string {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) ServiceName() (string, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) ExportURL(url common.URL) (bool, error) {
+	return true, nil
+}
+
+func (m *mockMetadataService) UnexportURL(url common.URL) error {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) SubscribeURL(url common.URL) (bool, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) UnsubscribeURL(url common.URL) error {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) PublishServiceDefinition(url common.URL) error {
+	return nil
+}
+
+func (m *mockMetadataService) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) MethodMapper() map[string]string {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) GetSubscribedURLs() ([]common.URL, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) GetServiceDefinition(interfaceName string, group string, version string) (string, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) GetServiceDefinitionByServiceKey(serviceKey string) (string, error) {
+	panic("implement me")
+}
+
+func (m *mockMetadataService) RefreshMetadata(exportedRevision string, subscribedRevision string) (bool, error) {
+	panic("implement me")
+}
 
+func (m *mockMetadataService) Version() (string, error) {
+	panic("implement me")
 }
diff --git a/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer.go b/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer.go
index a7d2f3ee98f20bf16437008135e4964195680abb..949a5822c237de413b59d35efe94f807975795cf 100644
--- a/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer.go
+++ b/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer.go
@@ -23,8 +23,8 @@ import (
 )
 
 type SubscribedURLsSynthesizer interface {
-	//Supports the synthesis of the subscribed url or not
+	// Supports the synthesis of the subscribed url or not
 	Support(subscribedURL *common.URL) bool
-	//synthesize the subscribed url
+	// synthesize the subscribed url
 	Synthesize(subscribedURL *common.URL, serviceInstances []registry.ServiceInstance) []common.URL
 }
diff --git a/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer_factory.go b/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer_factory.go
index f8c76f6e84eb2ceba47481d5f856f6885525f09c..ba7887223c4553a368f2f698bbb861ba8e10fe26 100644
--- a/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer_factory.go
+++ b/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer_factory.go
@@ -21,10 +21,12 @@ var (
 	synthesizers []SubscribedURLsSynthesizer
 )
 
+// nolint
 func AddSynthesizer(synthesizer SubscribedURLsSynthesizer) {
 	synthesizers = append(synthesizers, synthesizer)
 }
 
+// nolint
 func GetAllSynthesizer() []SubscribedURLsSynthesizer {
 	return synthesizers
 }
diff --git a/registry/zookeeper/registry.go b/registry/zookeeper/registry.go
index 5d5f9e0526b7b8a9c5a2e2524f27f03573d758a8..8f2ac1023b8ad34938b9996b480e3bbc4adbaaea 100644
--- a/registry/zookeeper/registry.go
+++ b/registry/zookeeper/registry.go
@@ -87,12 +87,12 @@ func newZkRegistry(url *common.URL) (registry.Registry, error) {
 	return r, nil
 }
 
-// Options ...
+// nolint
 type Options struct {
 	client *zookeeper.ZookeeperClient
 }
 
-// Option ...
+// nolint
 type Option func(*Options)
 
 func newMockZkRegistry(url *common.URL, opts ...zookeeper.Option) (*zk.TestCluster, *zkRegistry, error) {
@@ -117,6 +117,7 @@ func newMockZkRegistry(url *common.URL, opts ...zookeeper.Option) (*zk.TestClust
 	return c, r, nil
 }
 
+// InitListeners initializes listeners of zookeeper registry center
 func (r *zkRegistry) InitListeners() {
 	r.listener = zookeeper.NewZkEventListener(r.client)
 	newDataListener := NewRegistryDataListener()
@@ -147,10 +148,12 @@ func (r *zkRegistry) InitListeners() {
 	r.dataListener = newDataListener
 }
 
+// CreatePath creates the path in the registry center of zookeeper
 func (r *zkRegistry) CreatePath(path string) error {
 	return r.ZkClient().Create(path)
 }
 
+// DoRegister actually do the register job in the registry center of zookeeper
 func (r *zkRegistry) DoRegister(root string, node string) error {
 	return r.registerTempZookeeperNode(root, node)
 }
@@ -164,6 +167,7 @@ func (r *zkRegistry) DoUnregister(root string, node string) error {
 	return r.ZkClient().Delete(path.Join(root, node))
 }
 
+// DoSubscribe actually subscribes the provider URL
 func (r *zkRegistry) DoSubscribe(conf *common.URL) (registry.Listener, error) {
 	return r.getListener(conf)
 }
@@ -172,23 +176,28 @@ func (r *zkRegistry) DoUnsubscribe(conf *common.URL) (registry.Listener, error)
 	return r.getCloseListener(conf)
 }
 
+// CloseAndNilClient closes listeners and clear client
 func (r *zkRegistry) CloseAndNilClient() {
 	r.client.Close()
 	r.client = nil
 }
 
+// nolint
 func (r *zkRegistry) ZkClient() *zookeeper.ZookeeperClient {
 	return r.client
 }
 
+// nolint
 func (r *zkRegistry) SetZkClient(client *zookeeper.ZookeeperClient) {
 	r.client = client
 }
 
+// nolint
 func (r *zkRegistry) ZkClientLock() *sync.Mutex {
 	return &r.cltLock
 }
 
+// CloseListener closes listeners
 func (r *zkRegistry) CloseListener() {
 	if r.dataListener != nil {
 		r.dataListener.Close()
diff --git a/remoting/etcdv3/client.go b/remoting/etcdv3/client.go
index ba3ea6e864923b1e70cc4a0d31ee98415807699c..080c9411442b4cbb9701e00152f3a03f562d0d05 100644
--- a/remoting/etcdv3/client.go
+++ b/remoting/etcdv3/client.go
@@ -19,7 +19,6 @@ package etcdv3
 
 import (
 	"context"
-	"path"
 	"sync"
 	"time"
 )
@@ -42,16 +41,17 @@ const (
 	MaxFailTimes = 15
 	// RegistryETCDV3Client client name
 	RegistryETCDV3Client = "etcd registry"
+	// metadataETCDV3Client client name
+	MetadataETCDV3Client = "etcd metadata"
 )
 
 var (
-	// ErrNilETCDV3Client ...
+	// Defines related errors
 	ErrNilETCDV3Client = perrors.New("etcd raw client is nil") // full describe the ERR
-	// ErrKVPairNotFound ...
-	ErrKVPairNotFound = perrors.New("k/v pair not found")
+	ErrKVPairNotFound  = perrors.New("k/v pair not found")
 )
 
-// Options ...
+// nolint
 type Options struct {
 	name      string
 	endpoints []string
@@ -60,38 +60,38 @@ type Options struct {
 	heartbeat int // heartbeat second
 }
 
-// Option ...
+// Option will define a function of handling Options
 type Option func(*Options)
 
-// WithEndpoints ...
+// WithEndpoints sets etcd client endpoints
 func WithEndpoints(endpoints ...string) Option {
 	return func(opt *Options) {
 		opt.endpoints = endpoints
 	}
 }
 
-// WithName ...
+// WithName sets etcd client name
 func WithName(name string) Option {
 	return func(opt *Options) {
 		opt.name = name
 	}
 }
 
-// WithTimeout ...
+// WithTimeout sets etcd client timeout
 func WithTimeout(timeout time.Duration) Option {
 	return func(opt *Options) {
 		opt.timeout = timeout
 	}
 }
 
-// WithHeartbeat ...
+// WithHeartbeat sets etcd client heartbeat
 func WithHeartbeat(heartbeat int) Option {
 	return func(opt *Options) {
 		opt.heartbeat = heartbeat
 	}
 }
 
-// ValidateClient ...
+// ValidateClient validates client and sets options
 func ValidateClient(container clientFacade, opts ...Option) error {
 
 	options := &Options{
@@ -107,7 +107,7 @@ func ValidateClient(container clientFacade, opts ...Option) error {
 
 	// new Client
 	if container.Client() == nil {
-		newClient, err := newClient(options.name, options.endpoints, options.timeout, options.heartbeat)
+		newClient, err := NewClient(options.name, options.endpoints, options.timeout, options.heartbeat)
 		if err != nil {
 			logger.Warnf("new etcd client (name{%s}, etcd addresses{%v}, timeout{%d}) = error{%v}",
 				options.name, options.endpoints, options.timeout, err)
@@ -119,7 +119,7 @@ func ValidateClient(container clientFacade, opts ...Option) error {
 	// Client lose connection with etcd server
 	if container.Client().rawClient == nil {
 
-		newClient, err := newClient(options.name, options.endpoints, options.timeout, options.heartbeat)
+		newClient, err := NewClient(options.name, options.endpoints, options.timeout, options.heartbeat)
 		if err != nil {
 			logger.Warnf("new etcd client (name{%s}, etcd addresses{%v}, timeout{%d}) = error{%v}",
 				options.name, options.endpoints, options.timeout, err)
@@ -131,7 +131,27 @@ func ValidateClient(container clientFacade, opts ...Option) error {
 	return nil
 }
 
-// Client ...
+//  NewServiceDiscoveryClient
+func NewServiceDiscoveryClient(opts ...Option) *Client {
+	options := &Options{
+		heartbeat: 1, // default heartbeat
+	}
+
+	for _, opt := range opts {
+		opt(options)
+	}
+
+	newClient, err := NewClient(options.name, options.endpoints, options.timeout, options.heartbeat)
+	if err != nil {
+		logger.Errorf("new etcd client (name{%s}, etcd addresses{%v}, timeout{%d}) = error{%v}",
+			options.name, options.endpoints, options.timeout, err)
+		return nil
+	}
+
+	return newClient
+}
+
+// Client represents etcd client Configuration
 type Client struct {
 	lock sync.RWMutex
 
@@ -142,14 +162,14 @@ type Client struct {
 	heartbeat int
 
 	ctx       context.Context    // if etcd server connection lose, the ctx.Done will be sent msg
-	cancel    context.CancelFunc // cancel the ctx,  all watcher will stopped
+	cancel    context.CancelFunc // cancel the ctx, all watcher will stopped
 	rawClient *clientv3.Client
 
 	exit chan struct{}
 	Wait sync.WaitGroup
 }
 
-func newClient(name string, endpoints []string, timeout time.Duration, heartbeat int) (*Client, error) {
+func NewClient(name string, endpoints []string, timeout time.Duration, heartbeat int) (*Client, error) {
 
 	ctx, cancel := context.WithCancel(context.Background())
 	rawClient, err := clientv3.New(clientv3.Config{
@@ -206,7 +226,7 @@ func (c *Client) stop() bool {
 	return false
 }
 
-// Close ...
+// nolint
 func (c *Client) Close() {
 
 	if c == nil {
@@ -265,8 +285,7 @@ func (c *Client) maintenanceStatusLoop(s *concurrency.Session) {
 	}
 }
 
-// if k not exist will put k/v in etcd
-// if k is already exist in etcd, return nil
+// if k not exist will put k/v in etcd, otherwise return nil
 func (c *Client) put(k string, v string, opts ...clientv3.OpOption) error {
 
 	c.lock.RLock()
@@ -287,6 +306,28 @@ func (c *Client) put(k string, v string, opts ...clientv3.OpOption) error {
 	return nil
 }
 
+// if k not exist will put k/v in etcd
+// if k is already exist in etcd, replace it
+func (c *Client) update(k string, v string, opts ...clientv3.OpOption) error {
+
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	if c.rawClient == nil {
+		return ErrNilETCDV3Client
+	}
+
+	_, err := c.rawClient.Txn(c.ctx).
+		If(clientv3.Compare(clientv3.Version(k), "!=", -1)).
+		Then(clientv3.OpPut(k, v, opts...)).
+		Commit()
+	if err != nil {
+		return err
+
+	}
+	return nil
+}
+
 func (c *Client) delete(k string) error {
 
 	c.lock.RLock()
@@ -325,7 +366,7 @@ func (c *Client) get(k string) (string, error) {
 	return string(resp.Kvs[0].Value), nil
 }
 
-// CleanKV ...
+// nolint
 func (c *Client) CleanKV() error {
 
 	c.lock.RLock()
@@ -425,12 +466,12 @@ func (c *Client) keepAliveKV(k string, v string) error {
 	return nil
 }
 
-// Done ...
+// nolint
 func (c *Client) Done() <-chan struct{} {
 	return c.exit
 }
 
-// Valid ...
+// nolint
 func (c *Client) Valid() bool {
 	select {
 	case <-c.exit:
@@ -447,7 +488,7 @@ func (c *Client) Valid() bool {
 	return true
 }
 
-// Create ...
+// nolint
 func (c *Client) Create(k string, v string) error {
 
 	err := c.put(k, v)
@@ -457,7 +498,16 @@ func (c *Client) Create(k string, v string) error {
 	return nil
 }
 
-// Delete ...
+// Update key value ...
+func (c *Client) Update(k, v string) error {
+	err := c.update(k, v)
+	if err != nil {
+		return perrors.WithMessagef(err, "Update k/v (key: %s value %s)", k, v)
+	}
+	return nil
+}
+
+// nolint
 func (c *Client) Delete(k string) error {
 
 	err := c.delete(k)
@@ -468,20 +518,18 @@ func (c *Client) Delete(k string) error {
 	return nil
 }
 
-// RegisterTemp ...
-func (c *Client) RegisterTemp(basePath string, node string) (string, error) {
+// RegisterTemp registers a temporary node
+func (c *Client) RegisterTemp(k, v string) error {
 
-	completeKey := path.Join(basePath, node)
-
-	err := c.keepAliveKV(completeKey, "")
+	err := c.keepAliveKV(k, v)
 	if err != nil {
-		return "", perrors.WithMessagef(err, "keepalive kv (key %s)", completeKey)
+		return perrors.WithMessagef(err, "keepalive kv (key %s)", k)
 	}
 
-	return completeKey, nil
+	return nil
 }
 
-// GetChildrenKVList ...
+// GetChildrenKVList gets children kv list by @k
 func (c *Client) GetChildrenKVList(k string) ([]string, []string, error) {
 
 	kList, vList, err := c.getChildren(k)
@@ -491,7 +539,7 @@ func (c *Client) GetChildrenKVList(k string) ([]string, []string, error) {
 	return kList, vList, nil
 }
 
-// Get ...
+// Get gets value by @k
 func (c *Client) Get(k string) (string, error) {
 
 	v, err := c.get(k)
@@ -502,7 +550,7 @@ func (c *Client) Get(k string) (string, error) {
 	return v, nil
 }
 
-// Watch ...
+// Watch watches on spec key
 func (c *Client) Watch(k string) (clientv3.WatchChan, error) {
 
 	wc, err := c.watch(k)
@@ -512,7 +560,7 @@ func (c *Client) Watch(k string) (clientv3.WatchChan, error) {
 	return wc, nil
 }
 
-// WatchWithPrefix ...
+// WatchWithPrefix watches on spec prefix
 func (c *Client) WatchWithPrefix(prefix string) (clientv3.WatchChan, error) {
 
 	wc, err := c.watchWithPrefix(prefix)
diff --git a/remoting/etcdv3/client_test.go b/remoting/etcdv3/client_test.go
index e37b6383df55f1c7e7b64be62fc2eb22d1034616..a321eea9ec22e41b807dd9e6912547d6ca5a084e 100644
--- a/remoting/etcdv3/client_test.go
+++ b/remoting/etcdv3/client_test.go
@@ -120,7 +120,7 @@ func (suite *ClientTestSuite) TearDownSuite() {
 }
 
 func (suite *ClientTestSuite) setUpClient() *Client {
-	c, err := newClient(suite.etcdConfig.name,
+	c, err := NewClient(suite.etcdConfig.name,
 		suite.etcdConfig.endpoints,
 		suite.etcdConfig.timeout,
 		suite.etcdConfig.heartbeat)
@@ -384,7 +384,7 @@ func (suite *ClientTestSuite) TestClientRegisterTemp() {
 		assert.Contains(t, events, eDelete)
 	}()
 
-	_, err := c.RegisterTemp("scott", "wang")
+	err := c.RegisterTemp("scott/wang", "test")
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/remoting/etcdv3/facade.go b/remoting/etcdv3/facade.go
index 35befc85e449ec02a6377faec300aa6b46bcc8bf..3f5999fdf3c5a0791d780e8f5521ef3ea51e9372 100644
--- a/remoting/etcdv3/facade.go
+++ b/remoting/etcdv3/facade.go
@@ -43,7 +43,7 @@ type clientFacade interface {
 	common.Node
 }
 
-// HandleClientRestart ...
+// HandleClientRestart keeps the connection between client and server
 func HandleClientRestart(r clientFacade) {
 
 	var (
diff --git a/remoting/etcdv3/listener.go b/remoting/etcdv3/listener.go
index c65c4d127c691f5f8e30cae5b612e1a9920e7887..4f80a89dfb713036a5d4d812bc7a2d5551f42284 100644
--- a/remoting/etcdv3/listener.go
+++ b/remoting/etcdv3/listener.go
@@ -33,7 +33,7 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
-// EventListener ...
+// nolint
 type EventListener struct {
 	client     *Client
 	keyMapLock sync.Mutex
@@ -41,7 +41,7 @@ type EventListener struct {
 	wg         sync.WaitGroup
 }
 
-// NewEventListener ...
+// NewEventListener returns a EventListener instance
 func NewEventListener(client *Client) *EventListener {
 	return &EventListener{
 		client: client,
@@ -92,12 +92,10 @@ func (l *EventListener) ListenServiceNodeEvent(key string, listener ...remoting.
 			}
 		}
 	}
-
-	return false
 }
 
-// return true mean the event type is DELETE
-// return false mean the event type is CREATE || UPDATE
+// return true means the event type is DELETE
+// return false means the event type is CREATE || UPDATE
 func (l *EventListener) handleEvents(event *clientv3.Event, listeners ...remoting.DataListener) bool {
 
 	logger.Infof("got a etcd event {type: %s, key: %s}", event.Type, event.Kv.Key)
@@ -135,7 +133,7 @@ func (l *EventListener) handleEvents(event *clientv3.Event, listeners ...remotin
 	panic("unreachable")
 }
 
-// ListenServiceNodeEventWithPrefix Listen on a set of key with spec prefix
+// ListenServiceNodeEventWithPrefix listens on a set of key with spec prefix
 func (l *EventListener) ListenServiceNodeEventWithPrefix(prefix string, listener ...remoting.DataListener) {
 	defer l.wg.Done()
 	for {
@@ -151,12 +149,12 @@ func (l *EventListener) ListenServiceNodeEventWithPrefix(prefix string, listener
 			logger.Warnf("etcd client stopped")
 			return
 
-			// client ctx stop
+		// client ctx stop
 		case <-l.client.ctx.Done():
 			logger.Warnf("etcd client ctx cancel")
 			return
 
-			// etcd event stream
+		// etcd event stream
 		case e, ok := <-wc:
 
 			if !ok {
@@ -230,7 +228,7 @@ func (l *EventListener) ListenServiceEvent(key string, listener remoting.DataLis
 	}(key)
 }
 
-// Close ...
+// nolint
 func (l *EventListener) Close() {
 	l.wg.Wait()
 }
diff --git a/remoting/kubernetes/client.go b/remoting/kubernetes/client.go
index 0c9ffd2b914e6ad584023725867a3aaa4b641224..0a0548959a3e6d839321d03a627bb6aba66d8474 100644
--- a/remoting/kubernetes/client.go
+++ b/remoting/kubernetes/client.go
@@ -19,444 +19,62 @@ package kubernetes
 
 import (
 	"context"
-	"encoding/base64"
-	"encoding/json"
-	"os"
+	"strconv"
 	"sync"
-	"time"
 )
 
 import (
 	perrors "github.com/pkg/errors"
-	"k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/fields"
-	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/apimachinery/pkg/util/strategicpatch"
-	"k8s.io/apimachinery/pkg/watch"
+	v1 "k8s.io/api/core/v1"
 	"k8s.io/client-go/kubernetes"
-	"k8s.io/client-go/rest"
+	"k8s.io/client-go/kubernetes/fake"
 )
 
 import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/logger"
 )
 
-const (
-	// kubernetes inject the var
-	podNameKey   = "HOSTNAME"
-	nameSpaceKey = "NAMESPACE"
-	// all pod annotation key
-	DubboIOAnnotationKey = "dubbo.io/annotation"
-
-	DubboIOLabelKey   = "dubbo.io/label"
-	DubboIOLabelValue = "dubbo.io-value"
-)
-
-var (
-	ErrDubboLabelAlreadyExist = perrors.New("dubbo label already exist")
-)
-
 type Client struct {
-
-	// kubernetes connection config
-	cfg *rest.Config
-
-	// the kubernetes interface
-	rawClient kubernetes.Interface
-
-	// current pod config
-	currentPodName string
-
-	ns string
-
-	// current resource version
-	lastResourceVersion string
-
-	// the memory watcherSet
-	watcherSet WatcherSet
-
-	// protect the wg && currentPod
 	lock sync.RWMutex
-	// current pod status
-	currentPod *v1.Pod
-	// protect the watchPods loop && watcher
-	wg sync.WaitGroup
 
 	// manage the  client lifecycle
 	ctx    context.Context
 	cancel context.CancelFunc
-}
 
-// load CurrentPodName
-func getCurrentPodName() (string, error) {
-
-	v := os.Getenv(podNameKey)
-	if len(v) == 0 {
-		return "", perrors.New("read value from env by key (HOSTNAME)")
-	}
-	return v, nil
+	controller *dubboRegistryController
 }
 
-// load CurrentNameSpace
-func getCurrentNameSpace() (string, error) {
-
-	v := os.Getenv(nameSpaceKey)
-	if len(v) == 0 {
-		return "", perrors.New("read value from env by key (NAMESPACE)")
-	}
-	return v, nil
-}
-
-// NewMockClient
-// export for registry package test
-func NewMockClient(namespace string, mockClientGenerator func() (kubernetes.Interface, error)) (*Client, error) {
-	return newMockClient(namespace, mockClientGenerator)
-}
-
-// newMockClient
-// new a client for  test
-func newMockClient(namespace string, mockClientGenerator func() (kubernetes.Interface, error)) (*Client, error) {
-
-	rawClient, err := mockClientGenerator()
-	if err != nil {
-		return nil, perrors.WithMessage(err, "call mock generator")
-	}
-
-	currentPodName, err := getCurrentPodName()
-	if err != nil {
-		return nil, perrors.WithMessage(err, "get pod name")
-	}
+// newClient returns Client instance for registry
+func newClient(url common.URL) (*Client, error) {
 
 	ctx, cancel := context.WithCancel(context.Background())
 
-	c := &Client{
-		currentPodName: currentPodName,
-		ns:             namespace,
-		rawClient:      rawClient,
-		ctx:            ctx,
-		watcherSet:     newWatcherSet(ctx),
-		cancel:         cancel,
-	}
-
-	currentPod, err := c.initCurrentPod()
+	// read type
+	r, err := strconv.Atoi(url.GetParams().Get(constant.ROLE_KEY))
 	if err != nil {
-		return nil, perrors.WithMessage(err, "init current pod")
-	}
-
-	// record current status
-	c.currentPod = currentPod
-
-	// init the watcherSet by current pods
-	if err := c.initWatchSet(); err != nil {
-		return nil, perrors.WithMessage(err, "init watcherSet")
+		return nil, perrors.WithMessage(err, "atoi role")
 	}
-
-	c.lastResourceVersion = c.currentPod.GetResourceVersion()
-
-	// start kubernetes watch loop
-	if err := c.watchPods(); err != nil {
-		return nil, perrors.WithMessage(err, "watch pods")
-	}
-
-	logger.Infof("init kubernetes registry client success @namespace = %q @Podname = %q", namespace, c.currentPod.Name)
-	return c, nil
-}
-
-// newClient
-// new a client for registry
-func newClient(namespace string) (*Client, error) {
-
-	cfg, err := rest.InClusterConfig()
-	if err != nil {
-		return nil, perrors.WithMessage(err, "get in-cluster config")
-	}
-
-	rawClient, err := kubernetes.NewForConfig(cfg)
-	if err != nil {
-		return nil, perrors.WithMessage(err, "new kubernetes client by in cluster config")
-	}
-
-	currentPodName, err := getCurrentPodName()
+	controller, err := newDubboRegistryController(ctx, common.RoleType(r), GetInClusterKubernetesClient)
 	if err != nil {
-		return nil, perrors.WithMessage(err, "get pod name")
+		return nil, perrors.WithMessage(err, "new dubbo-registry controller")
 	}
 
-	ctx, cancel := context.WithCancel(context.Background())
-
 	c := &Client{
-		currentPodName: currentPodName,
-		ns:             namespace,
-		cfg:            cfg,
-		rawClient:      rawClient,
-		ctx:            ctx,
-		watcherSet:     newWatcherSet(ctx),
-		cancel:         cancel,
+		ctx:        ctx,
+		cancel:     cancel,
+		controller: controller,
 	}
 
-	currentPod, err := c.initCurrentPod()
-	if err != nil {
-		return nil, perrors.WithMessage(err, "init current pod")
+	if r == common.CONSUMER {
+		// only consumer have to start informer factory
+		c.controller.startALLInformers()
 	}
-
-	// record current status
-	c.currentPod = currentPod
-
-	// init the watcherSet by current pods
-	if err := c.initWatchSet(); err != nil {
-		return nil, perrors.WithMessage(err, "init watcherSet")
-	}
-
-	// start kubernetes watch loop
-	if err := c.watchPods(); err != nil {
-		return nil, perrors.WithMessage(err, "watch pods")
-	}
-
-	logger.Infof("init kubernetes registry client success @namespace = %q @Podname = %q", namespace, c.currentPod.Name)
 	return c, nil
 }
 
-// initCurrentPod
-// 1. get current pod
-// 2. give the dubbo-label for this pod
-func (c *Client) initCurrentPod() (*v1.Pod, error) {
-
-	// read the current pod status
-	currentPod, err := c.rawClient.CoreV1().Pods(c.ns).Get(c.currentPodName, metav1.GetOptions{})
-	if err != nil {
-		return nil, perrors.WithMessagef(err, "get current (%s) pod in namespace (%s)", c.currentPodName, c.ns)
-	}
-
-	oldPod, newPod, err := c.assembleDUBBOLabel(currentPod)
-	if err != nil {
-		if err != ErrDubboLabelAlreadyExist {
-			return nil, perrors.WithMessage(err, "assemble dubbo label")
-		}
-		// current pod don't have label
-	}
-
-	p, err := c.getPatch(oldPod, newPod)
-	if err != nil {
-		return nil, perrors.WithMessage(err, "get patch")
-	}
-
-	currentPod, err = c.patchCurrentPod(p)
-	if err != nil {
-		return nil, perrors.WithMessage(err, "patch to current pod")
-	}
-
-	return currentPod, nil
-}
-
-// initWatchSet
-// 1. get all with dubbo label pods
-// 2. put every element to watcherSet
-func (c *Client) initWatchSet() error {
-
-	pods, err := c.rawClient.CoreV1().Pods(c.ns).List(metav1.ListOptions{
-		LabelSelector: fields.OneTermEqualSelector(DubboIOLabelKey, DubboIOLabelValue).String(),
-	})
-	if err != nil {
-		return perrors.WithMessagef(err, "list pods  in namespace (%s)", c.ns)
-	}
-
-	// set resource version
-	c.lastResourceVersion = pods.GetResourceVersion()
-
-	for _, pod := range pods.Items {
-		logger.Debugf("got the pod (name: %s), (label: %v), (annotations: %v)", pod.Name, pod.GetLabels(), pod.GetAnnotations())
-		c.handleWatchedPodEvent(&pod, watch.Added)
-	}
-
-	return nil
-}
-
-// watchPods
-// try to watch kubernetes pods
-func (c *Client) watchPods() error {
-
-	// try once
-	watcher, err := c.rawClient.CoreV1().Pods(c.ns).Watch(metav1.ListOptions{
-		LabelSelector:   fields.OneTermEqualSelector(DubboIOLabelKey, DubboIOLabelValue).String(),
-		Watch:           true,
-		ResourceVersion: c.lastResourceVersion,
-	})
-	if err != nil {
-		return perrors.WithMessagef(err, "try to watch the namespace (%s) pods", c.ns)
-	}
-
-	watcher.Stop()
-
-	c.wg.Add(1)
-	// add wg, grace close the client
-	go c.watchPodsLoop()
-	return nil
-}
-
-type resourceVersionGetter interface {
-	GetResourceVersion() string
-}
-
-// watchPods
-// try to notify
-func (c *Client) watchPodsLoop() {
-
-	defer func() {
-		// notify other goroutine, this loop over
-		c.wg.Done()
-		logger.Info("watchPodsLoop goroutine game over")
-	}()
-
-	for {
-	onceWatch:
-		wc, err := c.rawClient.CoreV1().Pods(c.ns).Watch(metav1.ListOptions{
-			LabelSelector:   fields.OneTermEqualSelector(DubboIOLabelKey, DubboIOLabelValue).String(),
-			Watch:           true,
-			ResourceVersion: c.lastResourceVersion,
-		})
-		if err != nil {
-			logger.Warnf("watch the namespace (%s) pods: %v, retry after 2 seconds", c.ns, err)
-			time.Sleep(2 * time.Second)
-			continue
-		}
-
-		logger.Infof("the old kubernetes client broken, collect the resource status from resource version (%s)", c.lastResourceVersion)
-
-		for {
-			select {
-			// double check ctx
-			case <-c.ctx.Done():
-				logger.Infof("the kubernetes client stopped, resultChan len %d", len(wc.ResultChan()))
-				return
-
-				// get one element from result-chan
-			case event, ok := <-wc.ResultChan():
-				if !ok {
-					wc.Stop()
-					logger.Info("kubernetes watch chan die, create new")
-					goto onceWatch
-				}
-
-				if event.Type == watch.Error {
-					// watched a error event
-					logger.Warnf("kubernetes watch api report err (%#v)", event)
-					continue
-				}
-
-				o, ok := event.Object.(resourceVersionGetter)
-				if !ok {
-					logger.Warnf("kubernetes response object not a versioned object, its real type %T", event.Object)
-					continue
-				}
-
-				// record the last resource version avoid to sync all pod
-				c.lastResourceVersion = o.GetResourceVersion()
-				logger.Infof("kubernetes get the current resource version %v", c.lastResourceVersion)
-
-				// check event object type
-				p, ok := event.Object.(*v1.Pod)
-				if !ok {
-					logger.Warnf("kubernetes response object not a Pod, its real type %T", event.Object)
-					continue
-				}
-
-				logger.Debugf("kubernetes got pod %#v", p)
-				// handle the watched pod
-				go c.handleWatchedPodEvent(p, event.Type)
-			}
-		}
-	}
-}
-
-// handleWatchedPodEvent
-// handle watched pod event
-func (c *Client) handleWatchedPodEvent(p *v1.Pod, eventType watch.EventType) {
-
-	for ak, av := range p.GetAnnotations() {
-
-		// not dubbo interest annotation
-		if ak != DubboIOAnnotationKey {
-			continue
-		}
-
-		ol, err := c.unmarshalRecord(av)
-		if err != nil {
-			logger.Errorf("there a pod with dubbo annotation, but unmarshal dubbo value %v", err)
-			return
-		}
-
-		for _, o := range ol {
-
-			switch eventType {
-			case watch.Added:
-				// if pod is added, the record always be create
-				o.EventType = Create
-			case watch.Modified:
-				o.EventType = Update
-			case watch.Deleted:
-				o.EventType = Delete
-			default:
-				logger.Errorf("no valid kubernetes event-type (%s) ", eventType)
-				return
-			}
-
-			logger.Debugf("prepare to put object (%#v) to kubernetes-watcherSet", o)
-
-			if err := c.watcherSet.Put(o); err != nil {
-				logger.Errorf("put (%#v) to cache watcherSet: %v ", o, err)
-				return
-			}
-
-		}
-
-	}
-}
-
-// unmarshalRecord
-// unmarshal the kubernetes dubbo annotation value
-func (c *Client) unmarshalRecord(record string) ([]*WatcherEvent, error) {
-
-	if len(record) == 0 {
-		// []*WatcherEvent is nil.
-		return nil, nil
-	}
-
-	rawMsg, err := base64.URLEncoding.DecodeString(record)
-	if err != nil {
-		return nil, perrors.WithMessagef(err, "decode record (%s)", record)
-	}
-
-	var out []*WatcherEvent
-	if err := json.Unmarshal(rawMsg, &out); err != nil {
-		return nil, perrors.WithMessage(err, "decode json")
-	}
-	return out, nil
-}
-
-// marshalRecord
-// marshal the kubernetes dubbo annotation value
-func (c *Client) marshalRecord(ol []*WatcherEvent) (string, error) {
-
-	msg, err := json.Marshal(ol)
-	if err != nil {
-		return "", perrors.WithMessage(err, "json encode object list")
-	}
-	return base64.URLEncoding.EncodeToString(msg), nil
-}
-
-// readCurrentPod
-// read the current pod status from kubernetes api
-func (c *Client) readCurrentPod() (*v1.Pod, error) {
-
-	currentPod, err := c.rawClient.CoreV1().Pods(c.ns).Get(c.currentPodName, metav1.GetOptions{})
-	if err != nil {
-		return nil, perrors.WithMessagef(err, "get current (%s) pod in namespace (%s)", c.currentPodName, c.ns)
-	}
-	return currentPod, nil
-}
-
-// Create
-// create k/v pair in watcher-set
+// Create creates k/v pair in watcher-set
 func (c *Client) Create(k, v string) error {
 
 	// the read current pod must be lock, protect every
@@ -464,132 +82,18 @@ func (c *Client) Create(k, v string) error {
 	c.lock.Lock()
 	defer c.lock.Unlock()
 
-	// 1. accord old pod && (k, v) assemble new pod dubbo annotion v
-	// 2. get patch data
-	// 3. PATCH the pod
-	currentPod, err := c.readCurrentPod()
-	if err != nil {
-		return perrors.WithMessage(err, "read current pod")
+	if err := c.controller.addAnnotationForCurrentPod(k, v); err != nil {
+		return perrors.WithMessagef(err, "add annotation @key = %s @value = %s", k, v)
 	}
 
-	oldPod, newPod, err := c.assembleDUBBOAnnotations(k, v, currentPod)
-	if err != nil {
-		return perrors.WithMessage(err, "assemble")
-	}
-
-	patchBytes, err := c.getPatch(oldPod, newPod)
-	if err != nil {
-		return perrors.WithMessage(err, "get patch")
-	}
-
-	updatedPod, err := c.patchCurrentPod(patchBytes)
-	if err != nil {
-		return perrors.WithMessage(err, "patch current pod")
-	}
-
-	c.currentPod = updatedPod
 	logger.Debugf("put the @key = %s @value = %s success", k, v)
-	// not update the watcherSet, the watcherSet should be write by the  watchPodsLoop
 	return nil
 }
 
-// patch current pod
-// write new meta for current pod
-func (c *Client) patchCurrentPod(patch []byte) (*v1.Pod, error) {
-
-	updatedPod, err := c.rawClient.CoreV1().Pods(c.ns).Patch(c.currentPodName, types.StrategicMergePatchType, patch)
-	if err != nil {
-		return nil, perrors.WithMessage(err, "patch in kubernetes pod ")
-	}
-	return updatedPod, nil
-}
-
-// assemble the dubbo kubernetes label
-// every dubbo instance should be labeled spec {"dubbo.io/label":"dubbo.io/label-value"} label
-func (c *Client) assembleDUBBOLabel(currentPod *v1.Pod) (*v1.Pod, *v1.Pod, error) {
-
-	var (
-		oldPod = &v1.Pod{}
-		newPod = &v1.Pod{}
-	)
-
-	oldPod.Labels = make(map[string]string, 8)
-	newPod.Labels = make(map[string]string, 8)
-
-	if currentPod.GetLabels() != nil {
-
-		if currentPod.GetLabels()[DubboIOLabelKey] == DubboIOLabelValue {
-			// already have label
-			return nil, nil, ErrDubboLabelAlreadyExist
-		}
-	}
-
-	// copy current pod labels to oldPod && newPod
-	for k, v := range currentPod.GetLabels() {
-		oldPod.Labels[k] = v
-		newPod.Labels[k] = v
-	}
-	// assign new label for current pod
-	newPod.Labels[DubboIOLabelKey] = DubboIOLabelValue
-	return oldPod, newPod, nil
-}
-
-// assemble the dubbo kubernetes annotations
-// accord the current pod && (k,v) assemble the old-pod, new-pod
-func (c *Client) assembleDUBBOAnnotations(k, v string, currentPod *v1.Pod) (oldPod *v1.Pod, newPod *v1.Pod, err error) {
-
-	oldPod = &v1.Pod{}
-	newPod = &v1.Pod{}
-	oldPod.Annotations = make(map[string]string, 8)
-	newPod.Annotations = make(map[string]string, 8)
-
-	for k, v := range currentPod.GetAnnotations() {
-		oldPod.Annotations[k] = v
-		newPod.Annotations[k] = v
-	}
-
-	al, err := c.unmarshalRecord(oldPod.GetAnnotations()[DubboIOAnnotationKey])
-	if err != nil {
-		err = perrors.WithMessage(err, "unmarshal record")
-		return
-	}
-
-	newAnnotations, err := c.marshalRecord(append(al, &WatcherEvent{Key: k, Value: v}))
-	if err != nil {
-		err = perrors.WithMessage(err, "marshal record")
-		return
-	}
-
-	newPod.Annotations[DubboIOAnnotationKey] = newAnnotations
-	return
-}
-
-// getPatch
-// get the kubernetes pod patch bytes
-func (c *Client) getPatch(oldPod, newPod *v1.Pod) ([]byte, error) {
-
-	oldData, err := json.Marshal(oldPod)
-	if err != nil {
-		return nil, perrors.WithMessage(err, "marshal old pod")
-	}
-
-	newData, err := json.Marshal(newPod)
-	if err != nil {
-		return nil, perrors.WithMessage(err, "marshal newPod pod")
-	}
-
-	patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Pod{})
-	if err != nil {
-		return nil, perrors.WithMessage(err, "create two-way-merge-patch")
-	}
-	return patchBytes, nil
-}
-
-// GetChildren
-// get k children list from kubernetes-watcherSet
+// GetChildren gets k children list from kubernetes-watcherSet
 func (c *Client) GetChildren(k string) ([]string, []string, error) {
 
-	objectList, err := c.watcherSet.Get(k, true)
+	objectList, err := c.controller.watcherSet.Get(k, true)
 	if err != nil {
 		return nil, nil, perrors.WithMessagef(err, "get children from watcherSet on (%s)", k)
 	}
@@ -605,11 +109,10 @@ func (c *Client) GetChildren(k string) ([]string, []string, error) {
 	return kList, vList, nil
 }
 
-// Watch
-// watch on spec key
+// Watch watches on spec key
 func (c *Client) Watch(k string) (<-chan *WatcherEvent, <-chan struct{}, error) {
 
-	w, err := c.watcherSet.Watch(k, false)
+	w, err := c.controller.watcherSet.Watch(k, false)
 	if err != nil {
 		return nil, nil, perrors.WithMessagef(err, "watch on (%s)", k)
 	}
@@ -617,11 +120,10 @@ func (c *Client) Watch(k string) (<-chan *WatcherEvent, <-chan struct{}, error)
 	return w.ResultChan(), w.done(), nil
 }
 
-// Watch
-// watch on spec prefix
+// WatchWithPrefix watches on spec prefix
 func (c *Client) WatchWithPrefix(prefix string) (<-chan *WatcherEvent, <-chan struct{}, error) {
 
-	w, err := c.watcherSet.Watch(prefix, true)
+	w, err := c.controller.watcherSet.Watch(prefix, true)
 	if err != nil {
 		return nil, nil, perrors.WithMessagef(err, "watch on prefix (%s)", prefix)
 	}
@@ -629,9 +131,7 @@ func (c *Client) WatchWithPrefix(prefix string) (<-chan *WatcherEvent, <-chan st
 	return w.ResultChan(), w.done(), nil
 }
 
-// Valid
-// Valid the client
-// if return false, the client is die
+// if returns false, the client is die
 func (c *Client) Valid() bool {
 
 	select {
@@ -641,17 +141,15 @@ func (c *Client) Valid() bool {
 	}
 	c.lock.RLock()
 	defer c.lock.RUnlock()
-	return c.rawClient != nil
+	return c.controller != nil
 }
 
-// Done
-// read the client status
+// nolint
 func (c *Client) Done() <-chan struct{} {
 	return c.ctx.Done()
 }
 
-// Stop
-// read the client status
+// nolint
 func (c *Client) Close() {
 
 	select {
@@ -665,28 +163,44 @@ func (c *Client) Close() {
 	// the client ctx be canceled
 	// will trigger the watcherSet watchers all stopped
 	// so, just wait
-	c.wg.Wait()
 }
 
-// ValidateClient
-// validate the kubernetes client
+// ValidateClient validates the kubernetes client
 func ValidateClient(container clientFacade) error {
 
 	client := container.Client()
 
 	// new Client
 	if client == nil || client.Valid() {
-		ns, err := getCurrentNameSpace()
-		if err != nil {
-			return perrors.WithMessage(err, "get current namespace")
-		}
-		newClient, err := newClient(ns)
+
+		newClient, err := newClient(container.GetUrl())
 		if err != nil {
-			logger.Warnf("new kubernetes client (namespace{%s}: %v)", ns, err)
-			return perrors.WithMessagef(err, "new kubernetes client (:%+v)", ns)
+			logger.Warnf("new kubernetes client: %v)", err)
+			return perrors.WithMessage(err, "new kubernetes client")
 		}
 		container.SetClient(newClient)
 	}
 
 	return nil
 }
+
+// NewMockClient exports for registry package test
+func NewMockClient(podList *v1.PodList) (*Client, error) {
+
+	ctx, cancel := context.WithCancel(context.Background())
+	controller, err := newDubboRegistryController(ctx, common.CONSUMER, func() (kubernetes.Interface, error) {
+		return fake.NewSimpleClientset(podList), nil
+	})
+	if err != nil {
+		return nil, perrors.WithMessage(err, "new dubbo-registry controller")
+	}
+
+	c := &Client{
+		ctx:        ctx,
+		cancel:     cancel,
+		controller: controller,
+	}
+
+	c.controller.startALLInformers()
+	return c, nil
+}
diff --git a/remoting/kubernetes/client_test.go b/remoting/kubernetes/client_test.go
index 342285b345b5e45682fe792d35f2f910e7d86d9d..e116c48b1aa85b9b2331045dfbc42891aee1f2e1 100644
--- a/remoting/kubernetes/client_test.go
+++ b/remoting/kubernetes/client_test.go
@@ -20,20 +20,15 @@ package kubernetes
 import (
 	"encoding/json"
 	"fmt"
-	"net/http"
+	_ "net/http/pprof"
 	"os"
-	"runtime"
 	"strings"
 	"sync"
 	"testing"
-	"time"
 )
 
 import (
-	"github.com/stretchr/testify/suite"
 	v1 "k8s.io/api/core/v1"
-	"k8s.io/client-go/kubernetes"
-	"k8s.io/client-go/kubernetes/fake"
 )
 
 // tests dataset
@@ -64,220 +59,203 @@ var tests = []struct {
 // test dataset prefix
 const prefix = "name"
 
-var clientPodJsonData = `{
+var clientPodListJsonData = `{
     "apiVersion": "v1",
-    "kind": "Pod",
-    "metadata": {
-        "annotations": {
-            "dubbo.io/annotation": "W3siayI6Ii9kdWJibyIsInYiOiIifSx7ImsiOiIvZHViYm8vY29tLmlrdXJlbnRvLnVzZXIuVXNlclByb3ZpZGVyIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvY29uc3VtZXJzIiwidiI6IiJ9LHsiayI6Ii9kdWJibyIsInYiOiIifSx7ImsiOiIvZHViYm8vY29tLmlrdXJlbnRvLnVzZXIuVXNlclByb3ZpZGVyIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvcHJvdmlkZXJzIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvY29uc3VtZXJzL2NvbnN1bWVyJTNBJTJGJTJGMTcyLjE3LjAuOCUyRlVzZXJQcm92aWRlciUzRmNhdGVnb3J5JTNEY29uc3VtZXJzJTI2ZHViYm8lM0RkdWJib2dvLWNvbnN1bWVyLTIuNi4wJTI2cHJvdG9jb2wlM0RkdWJibyIsInYiOiIifV0="
-        },
-        "creationTimestamp": "2020-03-13T03:38:57Z",
-        "labels": {
-            "dubbo.io/label": "dubbo.io-value"
-        },
-        "name": "client",
-        "namespace": "default",
-        "resourceVersion": "2449700",
-        "selfLink": "/api/v1/namespaces/default/pods/client",
-        "uid": "3ec394f5-dcc6-49c3-8061-57b4b2b41344"
-    },
-    "spec": {
-        "containers": [
-            {
-                "env": [
+    "items": [
+        {
+            "apiVersion": "v1",
+            "kind": "Pod",
+            "metadata": {
+                "annotations": {
+                    "dubbo.io/annotation": "W3siayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvcHJvdmlkZXJzIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvcHJvdmlkZXJzL2R1YmJvJTNBJTJGJTJGMTcyLjE3LjAuNiUzQTIwMDAwJTJGVXNlclByb3ZpZGVyJTNGYWNjZXNzbG9nJTNEJTI2YW55aG9zdCUzRHRydWUlMjZhcHAudmVyc2lvbiUzRDAuMC4xJTI2YXBwbGljYXRpb24lM0RCRFRTZXJ2aWNlJTI2YXV0aCUzRCUyNmJlYW4ubmFtZSUzRFVzZXJQcm92aWRlciUyNmNsdXN0ZXIlM0RmYWlsb3ZlciUyNmVudmlyb25tZW50JTNEZGV2JTI2ZXhlY3V0ZS5saW1pdCUzRCUyNmV4ZWN1dGUubGltaXQucmVqZWN0ZWQuaGFuZGxlciUzRCUyNmdyb3VwJTNEJTI2aW50ZXJmYWNlJTNEY29tLmlrdXJlbnRvLnVzZXIuVXNlclByb3ZpZGVyJTI2aXAlM0QxNzIuMTcuMC42JTI2bG9hZGJhbGFuY2UlM0RyYW5kb20lMjZtZXRob2RzLkdldFVzZXIubG9hZGJhbGFuY2UlM0RyYW5kb20lMjZtZXRob2RzLkdldFVzZXIucmV0cmllcyUzRDElMjZtZXRob2RzLkdldFVzZXIudHBzLmxpbWl0LmludGVydmFsJTNEJTI2bWV0aG9kcy5HZXRVc2VyLnRwcy5saW1pdC5yYXRlJTNEJTI2bWV0aG9kcy5HZXRVc2VyLnRwcy5saW1pdC5zdHJhdGVneSUzRCUyNm1ldGhvZHMuR2V0VXNlci53ZWlnaHQlM0QwJTI2bW9kdWxlJTNEZHViYm9nbyUyQnVzZXItaW5mbyUyQnNlcnZlciUyNm5hbWUlM0RCRFRTZXJ2aWNlJTI2b3JnYW5pemF0aW9uJTNEaWt1cmVudG8uY29tJTI2b3duZXIlM0RaWCUyNnBhcmFtLnNpZ24lM0QlMjZwaWQlM0Q2JTI2cmVnaXN0cnkucm9sZSUzRDMlMjZyZWxlYXNlJTNEZHViYm8tZ29sYW5nLTEuMy4wJTI2cmV0cmllcyUzRCUyNnNlcnZpY2UuZmlsdGVyJTNEZWNobyUyNTJDdG9rZW4lMjUyQ2FjY2Vzc2xvZyUyNTJDdHBzJTI1MkNnZW5lcmljX3NlcnZpY2UlMjUyQ2V4ZWN1dGUlMjUyQ3BzaHV0ZG93biUyNnNpZGUlM0Rwcm92aWRlciUyNnRpbWVzdGFtcCUzRDE1OTExNTYxNTUlMjZ0cHMubGltaXQuaW50ZXJ2YWwlM0QlMjZ0cHMubGltaXQucmF0ZSUzRCUyNnRwcy5saW1pdC5yZWplY3RlZC5oYW5kbGVyJTNEJTI2dHBzLmxpbWl0LnN0cmF0ZWd5JTNEJTI2dHBzLmxpbWl0ZXIlM0QlMjZ2ZXJzaW9uJTNEJTI2d2FybXVwJTNEMTAwIiwidiI6IiJ9XQ=="
+                },
+                "creationTimestamp": "2020-06-03T03:49:14Z",
+                "generateName": "server-84c864f5bc-",
+                "labels": {
+                    "dubbo.io/label": "dubbo.io-value",
+                    "pod-template-hash": "84c864f5bc",
+                    "role": "server"
+                },
+                "name": "server-84c864f5bc-r8qvz",
+                "namespace": "default",
+                "ownerReferences": [
+                    {
+                        "apiVersion": "apps/v1",
+                        "blockOwnerDeletion": true,
+                        "controller": true,
+                        "kind": "ReplicaSet",
+                        "name": "server-84c864f5bc",
+                        "uid": "fa376dbb-4f37-4705-8e80-727f592c19b3"
+                    }
+                ],
+                "resourceVersion": "517460",
+                "selfLink": "/api/v1/namespaces/default/pods/server-84c864f5bc-r8qvz",
+                "uid": "f4fc811c-200c-4445-8d4f-532144957dcc"
+            },
+            "spec": {
+                "containers": [
                     {
-                        "name": "NAMESPACE",
-                        "valueFrom": {
-                            "fieldRef": {
-                                "apiVersion": "v1",
-                                "fieldPath": "metadata.namespace"
+                        "env": [
+                            {
+                                "name": "DUBBO_NAMESPACE",
+                                "value": "default"
+                            },
+                            {
+                                "name": "NAMESPACE",
+                                "valueFrom": {
+                                    "fieldRef": {
+                                        "apiVersion": "v1",
+                                        "fieldPath": "metadata.namespace"
+                                    }
+                                }
                             }
-                        }
+                        ],
+                        "image": "192.168.240.101:5000/scott/go-server",
+                        "imagePullPolicy": "Always",
+                        "name": "server",
+                        "resources": {},
+                        "terminationMessagePath": "/dev/termination-log",
+                        "terminationMessagePolicy": "File",
+                        "volumeMounts": [
+                            {
+                                "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
+                                "name": "dubbo-sa-token-5qbtb",
+                                "readOnly": true
+                            }
+                        ]
                     }
                 ],
-                "image": "registry.cn-hangzhou.aliyuncs.com/scottwang/dubbogo-client",
-                "imagePullPolicy": "Always",
-                "name": "client",
-                "resources": {},
-                "terminationMessagePath": "/dev/termination-log",
-                "terminationMessagePolicy": "File",
-                "volumeMounts": [
+                "dnsPolicy": "ClusterFirst",
+                "enableServiceLinks": true,
+                "nodeName": "minikube",
+                "priority": 0,
+                "restartPolicy": "Always",
+                "schedulerName": "default-scheduler",
+                "securityContext": {},
+                "serviceAccount": "dubbo-sa",
+                "serviceAccountName": "dubbo-sa",
+                "terminationGracePeriodSeconds": 30,
+                "tolerations": [
+                    {
+                        "effect": "NoExecute",
+                        "key": "node.kubernetes.io/not-ready",
+                        "operator": "Exists",
+                        "tolerationSeconds": 300
+                    },
                     {
-                        "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
-                        "name": "dubbo-sa-token-l2lzh",
-                        "readOnly": true
+                        "effect": "NoExecute",
+                        "key": "node.kubernetes.io/unreachable",
+                        "operator": "Exists",
+                        "tolerationSeconds": 300
+                    }
+                ],
+                "volumes": [
+                    {
+                        "name": "dubbo-sa-token-5qbtb",
+                        "secret": {
+                            "defaultMode": 420,
+                            "secretName": "dubbo-sa-token-5qbtb"
+                        }
                     }
                 ]
-            }
-        ],
-        "dnsPolicy": "ClusterFirst",
-        "enableServiceLinks": true,
-        "nodeName": "minikube",
-        "priority": 0,
-        "restartPolicy": "Never",
-        "schedulerName": "default-scheduler",
-        "securityContext": {},
-        "serviceAccount": "dubbo-sa",
-        "serviceAccountName": "dubbo-sa",
-        "terminationGracePeriodSeconds": 30,
-        "tolerations": [
-            {
-                "effect": "NoExecute",
-                "key": "node.kubernetes.io/not-ready",
-                "operator": "Exists",
-                "tolerationSeconds": 300
-            },
-            {
-                "effect": "NoExecute",
-                "key": "node.kubernetes.io/unreachable",
-                "operator": "Exists",
-                "tolerationSeconds": 300
-            }
-        ],
-        "volumes": [
-            {
-                "name": "dubbo-sa-token-l2lzh",
-                "secret": {
-                    "defaultMode": 420,
-                    "secretName": "dubbo-sa-token-l2lzh"
-                }
-            }
-        ]
-    },
-    "status": {
-        "conditions": [
-            {
-                "lastProbeTime": null,
-                "lastTransitionTime": "2020-03-13T03:38:57Z",
-                "status": "True",
-                "type": "Initialized"
             },
-            {
-                "lastProbeTime": null,
-                "lastTransitionTime": "2020-03-13T03:40:18Z",
-                "status": "True",
-                "type": "Ready"
-            },
-            {
-                "lastProbeTime": null,
-                "lastTransitionTime": "2020-03-13T03:40:18Z",
-                "status": "True",
-                "type": "ContainersReady"
-            },
-            {
-                "lastProbeTime": null,
-                "lastTransitionTime": "2020-03-13T03:38:57Z",
-                "status": "True",
-                "type": "PodScheduled"
-            }
-        ],
-        "containerStatuses": [
-            {
-                "containerID": "docker://2870d6abc19ca7fe22ca635ebcfac5d48c6d5550a659bafd74fb48104f6dfe3c",
-                "image": "registry.cn-hangzhou.aliyuncs.com/scottwang/dubbogo-client:latest",
-                "imageID": "docker-pullable://registry.cn-hangzhou.aliyuncs.com/scottwang/dubbogo-client@sha256:1f075131f708a0d400339e81549d7c4d4ed917ab0b6bd38ef458dd06ad25a559",
-                "lastState": {},
-                "name": "client",
-                "ready": true,
-                "restartCount": 0,
-                "state": {
-                    "running": {
-                        "startedAt": "2020-03-13T03:40:17Z"
+            "status": {
+                "conditions": [
+                    {
+                        "lastProbeTime": null,
+                        "lastTransitionTime": "2020-06-03T03:49:14Z",
+                        "status": "True",
+                        "type": "Initialized"
+                    },
+                    {
+                        "lastProbeTime": null,
+                        "lastTransitionTime": "2020-06-03T03:49:15Z",
+                        "status": "True",
+                        "type": "Ready"
+                    },
+                    {
+                        "lastProbeTime": null,
+                        "lastTransitionTime": "2020-06-03T03:49:15Z",
+                        "status": "True",
+                        "type": "ContainersReady"
+                    },
+                    {
+                        "lastProbeTime": null,
+                        "lastTransitionTime": "2020-06-03T03:49:14Z",
+                        "status": "True",
+                        "type": "PodScheduled"
+                    }
+                ],
+                "containerStatuses": [
+                    {
+                        "containerID": "docker://b6421e05ce44f8a1c4fa6b72274980777c7c0f945516209f7c0558cd0cd65406",
+                        "image": "192.168.240.101:5000/scott/go-server:latest",
+                        "imageID": "docker-pullable://192.168.240.101:5000/scott/go-server@sha256:4eecf895054f0ff93d80db64992a561d10504e55582def6dcb6093a6d6d92461",
+                        "lastState": {},
+                        "name": "server",
+                        "ready": true,
+                        "restartCount": 0,
+                        "started": true,
+                        "state": {
+                            "running": {
+                                "startedAt": "2020-06-03T03:49:15Z"
+                            }
+                        }
+                    }
+                ],
+                "hostIP": "10.0.2.15",
+                "phase": "Running",
+                "podIP": "172.17.0.6",
+                "podIPs": [
+                    {
+                        "ip": "172.17.0.6"
                     }
-                }
+                ],
+                "qosClass": "BestEffort",
+                "startTime": "2020-06-03T03:49:14Z"
             }
-        ],
-        "hostIP": "10.0.2.15",
-        "phase": "Running",
-        "podIP": "172.17.0.8",
-        "qosClass": "BestEffort",
-        "startTime": "2020-03-13T03:38:57Z"
+        }
+    ],
+    "kind": "List",
+    "metadata": {
+        "resourceVersion": "",
+        "selfLink": ""
     }
 }
 `
 
-type KubernetesClientTestSuite struct {
-	suite.Suite
-
-	currentPod v1.Pod
-}
-
-func (s *KubernetesClientTestSuite) initClient() *Client {
-
-	t := s.T()
-
-	client, err := newMockClient(s.currentPod.GetNamespace(), func() (kubernetes.Interface, error) {
-
-		out := fake.NewSimpleClientset()
-
-		// mock current pod
-		if _, err := out.CoreV1().Pods(s.currentPod.GetNamespace()).Create(&s.currentPod); err != nil {
-			t.Fatal(err)
-		}
-		return out, nil
-	})
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	time.Sleep(time.Second)
-	return client
-}
-
-func (s *KubernetesClientTestSuite) SetupSuite() {
-
-	runtime.GOMAXPROCS(1)
-
-	t := s.T()
+func getTestClient(t *testing.T) *Client {
 
+	pl := &v1.PodList{}
 	// 1. install test data
-	if err := json.Unmarshal([]byte(clientPodJsonData), &s.currentPod); err != nil {
+	if err := json.Unmarshal([]byte(clientPodListJsonData), &pl); err != nil {
 		t.Fatal(err)
 	}
+	currentPod := pl.Items[0]
 
-	// 2. set downward-api inject env
-	if err := os.Setenv(podNameKey, s.currentPod.GetName()); err != nil {
-		t.Fatal(err)
-	}
-	if err := os.Setenv(nameSpaceKey, s.currentPod.GetNamespace()); err != nil {
-		t.Fatal(err)
-	}
-
-	go http.ListenAndServe(":6061", nil)
-
-}
-
-func (s *KubernetesClientTestSuite) TestReadCurrentPodName() {
-	t := s.T()
-
-	n, err := getCurrentPodName()
-	if err != nil {
-		t.Fatal(err)
+	env := map[string]string{
+		nameSpaceKey:            currentPod.GetNamespace(),
+		podNameKey:              currentPod.GetName(),
+		needWatchedNameSpaceKey: "default",
 	}
 
-	if n != s.currentPod.GetName() {
-		t.Fatalf("expect %s but got %s", s.currentPod.GetName(), n)
+	for k, v := range env {
+		if err := os.Setenv(k, v); err != nil {
+			t.Fatal(err)
+		}
 	}
 
-}
-func (s *KubernetesClientTestSuite) TestReadCurrentNameSpace() {
-	t := s.T()
-
-	ns, err := getCurrentNameSpace()
+	client, err := NewMockClient(pl)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	if ns != s.currentPod.GetNamespace() {
-		t.Fatalf("expect %s but got %s", s.currentPod.GetNamespace(), ns)
-	}
-
+	return client
 }
-func (s *KubernetesClientTestSuite) TestClientValid() {
 
-	t := s.T()
+func TestClientValid(t *testing.T) {
 
-	client := s.initClient()
+	client := getTestClient(t)
 	defer client.Close()
 
 	if client.Valid() != true {
@@ -290,29 +268,24 @@ func (s *KubernetesClientTestSuite) TestClientValid() {
 	}
 }
 
-func (s *KubernetesClientTestSuite) TestClientDone() {
-
-	t := s.T()
+func TestClientDone(t *testing.T) {
 
-	client := s.initClient()
+	client := getTestClient(t)
 
 	go func() {
-		time.Sleep(time.Second)
 		client.Close()
 	}()
 
 	<-client.Done()
 
 	if client.Valid() == true {
-		t.Fatal("client should be invalid then")
+		t.Fatal("client should be invalid")
 	}
 }
 
-func (s *KubernetesClientTestSuite) TestClientCreateKV() {
+func TestClientCreateKV(t *testing.T) {
 
-	t := s.T()
-
-	client := s.initClient()
+	client := getTestClient(t)
 	defer client.Close()
 
 	for _, tc := range tests {
@@ -327,11 +300,9 @@ func (s *KubernetesClientTestSuite) TestClientCreateKV() {
 	}
 }
 
-func (s *KubernetesClientTestSuite) TestClientGetChildrenKVList() {
-
-	t := s.T()
+func TestClientGetChildrenKVList(t *testing.T) {
 
-	client := s.initClient()
+	client := getTestClient(t)
 	defer client.Close()
 
 	wg := sync.WaitGroup{}
@@ -407,11 +378,9 @@ func (s *KubernetesClientTestSuite) TestClientGetChildrenKVList() {
 
 }
 
-func (s *KubernetesClientTestSuite) TestClientWatchPrefix() {
+func TestClientWatchPrefix(t *testing.T) {
 
-	t := s.T()
-
-	client := s.initClient()
+	client := getTestClient(t)
 
 	wg := sync.WaitGroup{}
 	wg.Add(1)
@@ -452,22 +421,9 @@ func (s *KubernetesClientTestSuite) TestClientWatchPrefix() {
 	client.Close()
 }
 
-func (s *KubernetesClientTestSuite) TestNewClient() {
-
-	t := s.T()
-
-	_, err := newClient(s.currentPod.GetNamespace())
-	if err == nil {
-		t.Fatal("the out of cluster test should fail")
-	}
-
-}
-
-func (s *KubernetesClientTestSuite) TestClientWatch() {
-
-	t := s.T()
+func TestClientWatch(t *testing.T) {
 
-	client := s.initClient()
+	client := getTestClient(t)
 
 	wg := sync.WaitGroup{}
 	wg.Add(1)
@@ -507,7 +463,3 @@ func (s *KubernetesClientTestSuite) TestClientWatch() {
 
 	client.Close()
 }
-
-func TestKubernetesClient(t *testing.T) {
-	suite.Run(t, new(KubernetesClientTestSuite))
-}
diff --git a/remoting/kubernetes/facade.go b/remoting/kubernetes/facade.go
index dd15c918b45c353b8395e0b82aee82216f48cd0e..dc060bbb0eb673c6e380dfa3e9d5f7bacbd3fc0b 100644
--- a/remoting/kubernetes/facade.go
+++ b/remoting/kubernetes/facade.go
@@ -17,7 +17,10 @@
 
 package kubernetes
 
+import "github.com/apache/dubbo-go/common"
+
 type clientFacade interface {
 	Client() *Client
 	SetClient(*Client)
+	common.Node
 }
diff --git a/remoting/kubernetes/facade_test.go b/remoting/kubernetes/facade_test.go
index 024264ffdee14c2ad3fb01a8a5279084c0f085d9..4323c0ec565d64f445f15c3e5c265451b2b87ce7 100644
--- a/remoting/kubernetes/facade_test.go
+++ b/remoting/kubernetes/facade_test.go
@@ -18,14 +18,18 @@
 package kubernetes
 
 import (
+	"strconv"
 	"sync"
+	"testing"
 )
+
 import (
-	"k8s.io/client-go/kubernetes"
-	"k8s.io/client-go/kubernetes/fake"
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 )
 
 type mockFacade struct {
+	*common.URL
 	client  *Client
 	cltLock sync.Mutex
 	done    chan struct{}
@@ -39,25 +43,31 @@ func (r *mockFacade) SetClient(client *Client) {
 	r.client = client
 }
 
-func (s *KubernetesClientTestSuite) Test_Facade() {
+func (r *mockFacade) GetUrl() common.URL {
+	return *r.URL
+}
 
-	t := s.T()
+func (r *mockFacade) Destroy() {
+}
 
-	mockClient, err := newMockClient(s.currentPod.GetNamespace(), func() (kubernetes.Interface, error) {
+func (r *mockFacade) RestartCallBack() bool {
+	return true
+}
 
-		out := fake.NewSimpleClientset()
+func (r *mockFacade) IsAvailable() bool {
+	return true
+}
+func Test_Facade(t *testing.T) {
 
-		// mock current pod
-		if _, err := out.CoreV1().Pods(s.currentPod.GetNamespace()).Create(&s.currentPod); err != nil {
-			t.Fatal(err)
-		}
-		return out, nil
-	})
+	regUrl, err := common.NewURL("registry://127.0.0.1:443",
+		common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER)))
 	if err != nil {
 		t.Fatal(err)
 	}
 
+	mockClient := getTestClient(t)
 	m := &mockFacade{
+		URL:    &regUrl,
 		client: mockClient,
 	}
 
diff --git a/remoting/kubernetes/listener.go b/remoting/kubernetes/listener.go
index 4c198c66cc3e02006291a195af9d023ec5a02340..a737f4e0d4eae7d78bb17c47e9c216661c8b9c86 100644
--- a/remoting/kubernetes/listener.go
+++ b/remoting/kubernetes/listener.go
@@ -45,8 +45,8 @@ func NewEventListener(client *Client) *EventListener {
 }
 
 // Listen on a spec key
-// this method will return true when spec key deleted,
-// this method will return false when deep layer connection lose
+// this method returns true when spec key deleted,
+// this method returns false when deep layer connection lose
 func (l *EventListener) ListenServiceNodeEvent(key string, listener ...remoting.DataListener) bool {
 	defer l.wg.Done()
 	for {
@@ -81,12 +81,10 @@ func (l *EventListener) ListenServiceNodeEvent(key string, listener ...remoting.
 			}
 		}
 	}
-
-	return false
 }
 
-// return true mean the event type is DELETE
-// return false mean the event type is CREATE || UPDATE
+// return true means the event type is DELETE
+// return false means the event type is CREATE || UPDATE
 func (l *EventListener) handleEvents(event *WatcherEvent, listeners ...remoting.DataListener) bool {
 
 	logger.Infof("got a kubernetes-watcherSet event {type: %d, key: %s}", event.EventType, event.Key)
diff --git a/remoting/kubernetes/listener_test.go b/remoting/kubernetes/listener_test.go
index a9446782a5c336268c3d6418e5882031d1566ae8..1f398485b2f16defddf44ce1a08a7ecfd9760dd1 100644
--- a/remoting/kubernetes/listener_test.go
+++ b/remoting/kubernetes/listener_test.go
@@ -18,7 +18,7 @@
 package kubernetes
 
 import (
-	"time"
+	"testing"
 )
 
 import (
@@ -67,9 +67,7 @@ func (m *mockDataListener) DataChange(eventType remoting.Event) bool {
 	return true
 }
 
-func (s *KubernetesClientTestSuite) TestListener() {
-
-	t := s.T()
+func TestListener(t *testing.T) {
 
 	var tests = []struct {
 		input struct {
@@ -83,15 +81,13 @@ func (s *KubernetesClientTestSuite) TestListener() {
 		}{k: "/dubbo", v: changedData}},
 	}
 
-	c := s.initClient()
+	c := getTestClient(t)
 	defer c.Close()
 
 	listener := NewEventListener(c)
 	dataListener := &mockDataListener{client: c, changedData: changedData, rc: make(chan remoting.Event)}
 	listener.ListenServiceEvent("/dubbo", dataListener)
 
-	// NOTICE:  direct listen will lose create msg
-	time.Sleep(time.Second)
 	for _, tc := range tests {
 
 		k := tc.input.k
diff --git a/remoting/kubernetes/registry_controller.go b/remoting/kubernetes/registry_controller.go
new file mode 100644
index 0000000000000000000000000000000000000000..f93a00a6f2df6022d0436f56e8c719f108be66f3
--- /dev/null
+++ b/remoting/kubernetes/registry_controller.go
@@ -0,0 +1,598 @@
+/*
+ * 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 kubernetes
+
+import (
+	"context"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+import (
+	perrors "github.com/pkg/errors"
+	v1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/labels"
+	"k8s.io/apimachinery/pkg/selection"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/apimachinery/pkg/util/strategicpatch"
+	"k8s.io/apimachinery/pkg/watch"
+	"k8s.io/client-go/informers"
+	informerscorev1 "k8s.io/client-go/informers/core/v1"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/rest"
+	"k8s.io/client-go/tools/cache"
+	"k8s.io/client-go/util/workqueue"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/logger"
+)
+
+const (
+	// kubernetes inject env var
+	podNameKey              = "HOSTNAME"
+	nameSpaceKey            = "NAMESPACE"
+	needWatchedNameSpaceKey = "DUBBO_NAMESPACE"
+
+	// all pod annotation key
+	DubboIOAnnotationKey = "dubbo.io/annotation"
+	// all pod label key and value pair
+	DubboIOLabelKey           = "dubbo.io/label"
+	DubboIOConsumerLabelValue = "dubbo.io.consumer"
+	DubboIOProviderLabelValue = "dubbo.io.provider"
+
+	// kubernetes suggest resync
+	defaultResync = 5 * time.Minute
+)
+
+var (
+	ErrDubboLabelAlreadyExist = perrors.New("dubbo label already exist")
+)
+
+// dubboRegistryController works like a kubernetes controller
+type dubboRegistryController struct {
+
+	// clone from client
+	// manage lifecycle
+	ctx context.Context
+
+	role common.RoleType
+
+	// protect patch current pod operation
+	lock sync.Mutex
+
+	// current pod config
+	needWatchedNamespace map[string]struct{}
+	namespace            string
+	name                 string
+
+	watcherSet WatcherSet
+
+	// kubernetes
+	kc                               kubernetes.Interface
+	listAndWatchStartResourceVersion uint64
+	namespacedInformerFactory        map[string]informers.SharedInformerFactory
+	namespacedPodInformers           map[string]informerscorev1.PodInformer
+	queue                            workqueue.Interface //shared by namespaced informers
+}
+
+func newDubboRegistryController(
+	ctx context.Context,
+	// different provider and consumer have behavior
+	roleType common.RoleType,
+	// used to inject mock kubernetes client
+	kcGetter func() (kubernetes.Interface, error),
+) (*dubboRegistryController, error) {
+
+	kc, err := kcGetter()
+	if err != nil {
+		return nil, perrors.WithMessage(err, "get kubernetes client")
+	}
+
+	c := &dubboRegistryController{
+		ctx:                       ctx,
+		role:                      roleType,
+		watcherSet:                newWatcherSet(ctx),
+		needWatchedNamespace:      make(map[string]struct{}),
+		namespacedInformerFactory: make(map[string]informers.SharedInformerFactory),
+		namespacedPodInformers:    make(map[string]informerscorev1.PodInformer),
+		kc:                        kc,
+	}
+
+	if err := c.readConfig(); err != nil {
+		return nil, perrors.WithMessage(err, "read config")
+	}
+
+	if err := c.initCurrentPod(); err != nil {
+		return nil, perrors.WithMessage(err, "init current pod")
+	}
+
+	if err := c.initWatchSet(); err != nil {
+		return nil, perrors.WithMessage(err, "init watch set")
+	}
+
+	if err := c.initPodInformer(); err != nil {
+		return nil, perrors.WithMessage(err, "init pod informer")
+	}
+
+	go c.run()
+
+	return c, nil
+}
+
+// GetInClusterKubernetesClient
+// current pod running in kubernetes-cluster
+func GetInClusterKubernetesClient() (kubernetes.Interface, error) {
+
+	// read in-cluster config
+	cfg, err := rest.InClusterConfig()
+	if err != nil {
+		return nil, perrors.WithMessage(err, "get in-cluster config")
+	}
+
+	return kubernetes.NewForConfig(cfg)
+}
+
+// initWatchSet
+// 1. get all with dubbo label pods
+// 2. put every element to watcherSet
+// 3. refresh watch book-mark
+func (c *dubboRegistryController) initWatchSet() error {
+
+	req, err := labels.NewRequirement(DubboIOLabelKey, selection.In, []string{DubboIOConsumerLabelValue, DubboIOProviderLabelValue})
+	if err != nil {
+		return perrors.WithMessage(err, "new requirement")
+	}
+
+	for ns := range c.needWatchedNamespace {
+		pods, err := c.kc.CoreV1().Pods(ns).List(metav1.ListOptions{
+			LabelSelector: req.String(),
+		})
+		if err != nil {
+			return perrors.WithMessagef(err, "list pods in namespace (%s)", ns)
+		}
+		for _, p := range pods.Items {
+			// set resource version
+			rv, err := strconv.ParseUint(p.GetResourceVersion(), 10, 0)
+			if err != nil {
+				return perrors.WithMessagef(err, "parse resource version %s", p.GetResourceVersion())
+			}
+			if c.listAndWatchStartResourceVersion < rv {
+				c.listAndWatchStartResourceVersion = rv
+			}
+			c.handleWatchedPodEvent(&p, watch.Added)
+		}
+	}
+	return nil
+}
+
+// read dubbo-registry controller config
+// 1. current pod name
+// 2. current pod working namespace
+func (c *dubboRegistryController) readConfig() error {
+
+	// read current pod name && namespace
+	c.name = os.Getenv(podNameKey)
+	if len(c.name) == 0 {
+		return perrors.New("read value from env by key (HOSTNAME)")
+	}
+	c.namespace = os.Getenv(nameSpaceKey)
+	if len(c.namespace) == 0 {
+		return perrors.New("read value from env by key (NAMESPACE)")
+	}
+	return nil
+}
+
+func (c *dubboRegistryController) initNamespacedPodInformer(ns string) error {
+
+	req, err := labels.NewRequirement(DubboIOLabelKey, selection.In, []string{DubboIOConsumerLabelValue, DubboIOProviderLabelValue})
+	if err != nil {
+		return perrors.WithMessage(err, "new requirement")
+	}
+
+	informersFactory := informers.NewSharedInformerFactoryWithOptions(
+		c.kc,
+		defaultResync,
+		informers.WithNamespace(ns),
+		informers.WithTweakListOptions(func(options *metav1.ListOptions) {
+			options.LabelSelector = req.String()
+			options.ResourceVersion = strconv.FormatUint(c.listAndWatchStartResourceVersion, 10)
+		}),
+	)
+	podInformer := informersFactory.Core().V1().Pods()
+
+	podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
+		AddFunc:    c.addPod,
+		UpdateFunc: c.updatePod,
+		DeleteFunc: c.deletePod,
+	})
+
+	c.namespacedInformerFactory[ns] = informersFactory
+	c.namespacedPodInformers[ns] = podInformer
+
+	return nil
+}
+
+func (c *dubboRegistryController) initPodInformer() error {
+
+	if c.role == common.PROVIDER {
+		return nil
+	}
+
+	// read need watched namespaces list
+	needWatchedNameSpaceList := os.Getenv(needWatchedNameSpaceKey)
+	if len(needWatchedNameSpaceList) == 0 {
+		return perrors.New("read value from env by key (DUBBO_NAMESPACE)")
+	}
+	for _, ns := range strings.Split(needWatchedNameSpaceList, ",") {
+		c.needWatchedNamespace[ns] = struct{}{}
+	}
+	// current work namespace should be watched
+	c.needWatchedNamespace[c.namespace] = struct{}{}
+
+	c.queue = workqueue.New()
+
+	// init all watch needed pod-informer
+	for watchedNS := range c.needWatchedNamespace {
+		if err := c.initNamespacedPodInformer(watchedNS); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+type kubernetesEvent struct {
+	p *v1.Pod
+	t watch.EventType
+}
+
+func (c *dubboRegistryController) addPod(obj interface{}) {
+	p, ok := obj.(*v1.Pod)
+	if !ok {
+		logger.Warnf("pod-informer got object %T not *v1.Pod", obj)
+		return
+	}
+	c.queue.Add(&kubernetesEvent{
+		t: watch.Added,
+		p: p,
+	})
+}
+
+func (c *dubboRegistryController) updatePod(oldObj, newObj interface{}) {
+	op, ok := oldObj.(*v1.Pod)
+	if !ok {
+		logger.Warnf("pod-informer got object %T not *v1.Pod", oldObj)
+		return
+	}
+	np, ok := newObj.(*v1.Pod)
+	if !ok {
+		logger.Warnf("pod-informer got object %T not *v1.Pod", newObj)
+		return
+	}
+	if op.GetResourceVersion() == np.GetResourceVersion() {
+		return
+	}
+	c.queue.Add(&kubernetesEvent{
+		p: np,
+		t: watch.Modified,
+	})
+}
+
+func (c *dubboRegistryController) deletePod(obj interface{}) {
+	p, ok := obj.(*v1.Pod)
+	if !ok {
+		logger.Warnf("pod-informer got object %T not *v1.Pod", obj)
+		return
+	}
+	c.queue.Add(&kubernetesEvent{
+		p: p,
+		t: watch.Deleted,
+	})
+}
+
+func (c *dubboRegistryController) startALLInformers() {
+	logger.Debugf("starting namespaced informer-factory")
+	for _, factory := range c.namespacedInformerFactory {
+		go factory.Start(c.ctx.Done())
+	}
+}
+
+// run
+// controller process every event in work-queue
+func (c *dubboRegistryController) run() {
+
+	if c.role == common.PROVIDER {
+		return
+	}
+
+	defer logger.Warn("dubbo registry controller work stopped")
+	defer c.queue.ShutDown()
+
+	for ns, podInformer := range c.namespacedPodInformers {
+		if !cache.WaitForCacheSync(c.ctx.Done(), podInformer.Informer().HasSynced) {
+			logger.Errorf("wait for cache sync finish @namespace %s fail", ns)
+			return
+		}
+	}
+
+	logger.Infof("kubernetes registry-controller running @Namespace = %q @PodName = %q", c.namespace, c.name)
+
+	// start work
+	go c.work()
+	// block wait context cancel
+	<-c.ctx.Done()
+}
+
+func (c *dubboRegistryController) work() {
+	for c.processNextWorkItem() {
+	}
+}
+
+// processNextWorkItem process work-queue elements
+func (c *dubboRegistryController) processNextWorkItem() bool {
+	item, shutdown := c.queue.Get()
+	if shutdown {
+		return false
+	}
+	defer c.queue.Done(item)
+	o := item.(*kubernetesEvent)
+	c.handleWatchedPodEvent(o.p, o.t)
+	return true
+}
+
+// handleWatchedPodEvent handles watched pod event
+func (c *dubboRegistryController) handleWatchedPodEvent(p *v1.Pod, eventType watch.EventType) {
+	logger.Debugf("get @type = %s event from @pod = %s", eventType, p.GetName())
+
+	for ak, av := range p.GetAnnotations() {
+		// not dubbo interest annotation
+		if ak != DubboIOAnnotationKey {
+			continue
+		}
+		ol, err := c.unmarshalRecord(av)
+		if err != nil {
+			logger.Errorf("there a pod with dubbo annotation, but unmarshal dubbo value %v", err)
+			return
+		}
+		for _, o := range ol {
+			switch eventType {
+			case watch.Added:
+				// if pod is added, the record always be create
+				o.EventType = Create
+			case watch.Modified:
+				o.EventType = Update
+			case watch.Deleted:
+				o.EventType = Delete
+			default:
+				logger.Errorf("no valid kubernetes event-type (%s) ", eventType)
+				return
+			}
+
+			logger.Debugf("putting @key=%s @value=%s to watcherSet", o.Key, o.Value)
+			if err := c.watcherSet.Put(o); err != nil {
+				logger.Errorf("put (%#v) to cache watcherSet: %v ", o, err)
+				return
+			}
+		}
+	}
+}
+
+// unmarshalRecord unmarshals the kubernetes dubbo annotation value
+func (c *dubboRegistryController) unmarshalRecord(record string) ([]*WatcherEvent, error) {
+
+	if len(record) == 0 {
+		// []*WatcherEvent is nil.
+		return nil, nil
+	}
+
+	rawMsg, err := base64.URLEncoding.DecodeString(record)
+	if err != nil {
+		return nil, perrors.WithMessagef(err, "decode record (%s)", record)
+	}
+
+	var out []*WatcherEvent
+	if err := json.Unmarshal(rawMsg, &out); err != nil {
+		return nil, perrors.WithMessage(err, "decode json")
+	}
+	return out, nil
+}
+
+// initCurrentPod
+// 1. get current pod
+// 2. give the dubbo-label for this pod
+func (c *dubboRegistryController) initCurrentPod() error {
+	currentPod, err := c.readCurrentPod()
+	if err != nil {
+		return perrors.WithMessagef(err, "get current (%s) pod in namespace (%s)", c.name, c.namespace)
+	}
+
+	oldPod, newPod, err := c.assembleDUBBOLabel(currentPod)
+	if err != nil {
+		if err == ErrDubboLabelAlreadyExist {
+			return nil
+		}
+		return perrors.WithMessage(err, "assemble dubbo label")
+	}
+	// current pod don't have label
+	p, err := c.getPatch(oldPod, newPod)
+	if err != nil {
+		return perrors.WithMessage(err, "get patch")
+	}
+
+	currentPod, err = c.patchCurrentPod(p)
+	if err != nil {
+		return perrors.WithMessage(err, "patch to current pod")
+	}
+
+	return nil
+}
+
+// patchCurrentPod writes new meta for current pod
+func (c *dubboRegistryController) patchCurrentPod(patch []byte) (*v1.Pod, error) {
+	updatedPod, err := c.kc.CoreV1().Pods(c.namespace).Patch(c.name, types.StrategicMergePatchType, patch)
+	if err != nil {
+		return nil, perrors.WithMessage(err, "patch in kubernetes pod ")
+	}
+	return updatedPod, nil
+}
+
+// assembleDUBBOLabel assembles the dubbo kubernetes label
+// every dubbo instance should be labeled spec {"dubbo.io/label":"dubbo.io/label-value"} label
+func (c *dubboRegistryController) assembleDUBBOLabel(p *v1.Pod) (*v1.Pod, *v1.Pod, error) {
+	var (
+		oldPod = &v1.Pod{}
+		newPod = &v1.Pod{}
+	)
+	oldPod.Labels = make(map[string]string, 8)
+	newPod.Labels = make(map[string]string, 8)
+
+	if p.GetLabels() != nil {
+		if _, ok := p.GetLabels()[DubboIOLabelKey]; ok {
+			// already have label
+			return nil, nil, ErrDubboLabelAlreadyExist
+		}
+	}
+
+	// copy current pod labels to oldPod && newPod
+	for k, v := range p.GetLabels() {
+		oldPod.Labels[k] = v
+		newPod.Labels[k] = v
+	}
+
+	// assign new label for current pod
+	switch c.role {
+	case common.CONSUMER:
+		newPod.Labels[DubboIOLabelKey] = DubboIOConsumerLabelValue
+	case common.PROVIDER:
+		newPod.Labels[DubboIOLabelKey] = DubboIOProviderLabelValue
+	default:
+		return nil, nil, perrors.New(fmt.Sprintf("unknown role %s", c.role))
+	}
+	return oldPod, newPod, nil
+}
+
+// assembleDUBBOAnnotations assembles the dubbo kubernetes annotations
+// accord the current pod && (k,v) assemble the old-pod, new-pod
+func (c *dubboRegistryController) assembleDUBBOAnnotations(k, v string, currentPod *v1.Pod) (oldPod *v1.Pod, newPod *v1.Pod, err error) {
+
+	oldPod = &v1.Pod{}
+	newPod = &v1.Pod{}
+	oldPod.Annotations = make(map[string]string, 8)
+	newPod.Annotations = make(map[string]string, 8)
+
+	for k, v := range currentPod.GetAnnotations() {
+		oldPod.Annotations[k] = v
+		newPod.Annotations[k] = v
+	}
+
+	al, err := c.unmarshalRecord(oldPod.GetAnnotations()[DubboIOAnnotationKey])
+	if err != nil {
+		err = perrors.WithMessage(err, "unmarshal record")
+		return
+	}
+
+	newAnnotations, err := c.marshalRecord(append(al, &WatcherEvent{Key: k, Value: v}))
+	if err != nil {
+		err = perrors.WithMessage(err, "marshal record")
+		return
+	}
+
+	newPod.Annotations[DubboIOAnnotationKey] = newAnnotations
+	return
+}
+
+// getPatch gets the kubernetes pod patch bytes
+func (c *dubboRegistryController) getPatch(oldPod, newPod *v1.Pod) ([]byte, error) {
+	oldData, err := json.Marshal(oldPod)
+	if err != nil {
+		return nil, perrors.WithMessage(err, "marshal old pod")
+	}
+
+	newData, err := json.Marshal(newPod)
+	if err != nil {
+		return nil, perrors.WithMessage(err, "marshal newPod pod")
+	}
+
+	patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Pod{})
+	if err != nil {
+		return nil, perrors.WithMessage(err, "create two-way-merge-patch")
+	}
+	return patchBytes, nil
+}
+
+// marshalRecord marshals the kubernetes dubbo annotation value
+func (c *dubboRegistryController) marshalRecord(ol []*WatcherEvent) (string, error) {
+	msg, err := json.Marshal(ol)
+	if err != nil {
+		return "", perrors.WithMessage(err, "json encode object list")
+	}
+	return base64.URLEncoding.EncodeToString(msg), nil
+}
+
+// readCurrentPod reads from kubernetes-env current pod status
+func (c *dubboRegistryController) readCurrentPod() (*v1.Pod, error) {
+	currentPod, err := c.kc.CoreV1().Pods(c.namespace).Get(c.name, metav1.GetOptions{})
+	if err != nil {
+		return nil, perrors.WithMessagef(err, "get current (%s) pod in namespace (%s)", c.name, c.namespace)
+	}
+	return currentPod, nil
+}
+
+// addAnnotationForCurrentPod adds annotation for current pod
+func (c *dubboRegistryController) addAnnotationForCurrentPod(k string, v string) error {
+
+	c.lock.Lock()
+	defer c.lock.Unlock()
+
+	// 1. accord old pod && (k, v) assemble new pod dubbo annotion v
+	// 2. get patch data
+	// 3. PATCH the pod
+	currentPod, err := c.readCurrentPod()
+	if err != nil {
+		return perrors.WithMessage(err, "read current pod")
+	}
+
+	oldPod, newPod, err := c.assembleDUBBOAnnotations(k, v, currentPod)
+	if err != nil {
+		return perrors.WithMessage(err, "assemble")
+	}
+
+	patchBytes, err := c.getPatch(oldPod, newPod)
+	if err != nil {
+		return perrors.WithMessage(err, "get patch")
+	}
+
+	_, err = c.patchCurrentPod(patchBytes)
+	if err != nil {
+		return perrors.WithMessage(err, "patch current pod")
+	}
+
+	return c.watcherSet.Put(&WatcherEvent{
+		Key:       k,
+		Value:     v,
+		EventType: Create,
+	})
+}
diff --git a/remoting/kubernetes/watch.go b/remoting/kubernetes/watch.go
index c99a3ebcc041f2fed0160f1f286e72937d2c9aee..07eeb09b4dd4627fdd3b18ee4d59356911b3a9b1 100644
--- a/remoting/kubernetes/watch.go
+++ b/remoting/kubernetes/watch.go
@@ -71,6 +71,7 @@ type WatcherEvent struct {
 }
 
 // Watchable WatcherSet
+// thread-safe
 type WatcherSet interface {
 
 	// put the watch event to the watch set
@@ -139,17 +140,15 @@ func (s *watcherSetImpl) Watch(key string, prefix bool) (Watcher, error) {
 	return s.addWatcher(key, prefix)
 }
 
-// Done
-// get the watcher-set status
+// Done gets the watcher-set status
 func (s *watcherSetImpl) Done() <-chan struct{} {
 	return s.ctx.Done()
 }
 
-// Put
-// put the watch event to watcher-set
+// Put puts the watch event to watcher-set
 func (s *watcherSetImpl) Put(watcherEvent *WatcherEvent) error {
 
-	sendMsg := func(object *WatcherEvent, w *watcher) {
+	blockSendMsg := func(object *WatcherEvent, w *watcher) {
 
 		select {
 		case <-w.done():
@@ -167,40 +166,40 @@ func (s *watcherSetImpl) Put(watcherEvent *WatcherEvent) error {
 	}
 
 	// put to watcher-set
-	if watcherEvent.EventType == Delete {
+	switch watcherEvent.EventType {
+	case Delete:
+		// delete from store
 		delete(s.cache, watcherEvent.Key)
-	} else {
-
-		old, ok := s.cache[watcherEvent.Key]
-		if ok {
-			if old.Value == watcherEvent.Value {
-				// already have this k/v pair
-				return nil
-			}
+	case Update, Create:
+		o, ok := s.cache[watcherEvent.Key]
+		if !ok {
+			// pod update, but create new k/v pair
+			watcherEvent.EventType = Create
+			s.cache[watcherEvent.Key] = watcherEvent
+			break
 		}
-
-		// refresh the watcherEvent
+		// k/v pair already latest
+		if o.Value == watcherEvent.Value {
+			return nil
+		}
+		// update to latest status
 		s.cache[watcherEvent.Key] = watcherEvent
 	}
 
 	// notify watcher
 	for _, w := range s.watchers {
-
-		w := w
-
 		if !strings.Contains(watcherEvent.Key, w.interested.key) {
 			//  this watcher no interest in this element
 			continue
 		}
-
 		if !w.interested.prefix {
 			if watcherEvent.Key == w.interested.key {
-				go sendMsg(watcherEvent, w)
+				blockSendMsg(watcherEvent, w)
 			}
 			// not interest
 			continue
 		}
-		go sendMsg(watcherEvent, w)
+		blockSendMsg(watcherEvent, w)
 	}
 	return nil
 }
@@ -242,8 +241,7 @@ func (s *watcherSetImpl) addWatcher(key string, prefix bool) (Watcher, error) {
 	return w, nil
 }
 
-// Get
-// get elements from watcher-set
+// Get gets elements from watcher-set
 func (s *watcherSetImpl) Get(key string, prefix bool) ([]*WatcherEvent, error) {
 
 	s.lock.RLock()
@@ -296,19 +294,17 @@ type watcher struct {
 	exit      chan struct{}
 }
 
-// ResultChan
+// nolint
 func (w *watcher) ResultChan() <-chan *WatcherEvent {
 	return w.ch
 }
 
-// ID
-// the watcher's id
+// nolint
 func (w *watcher) ID() string {
 	return strconv.FormatUint(w.id, 10)
 }
 
-// stop
-// stop the watcher
+// nolint
 func (w *watcher) stop() {
 
 	// double close will panic
@@ -317,14 +313,12 @@ func (w *watcher) stop() {
 	})
 }
 
-// done
-// check watcher status
+// done checks watcher status
 func (w *watcher) done() <-chan struct{} {
 	return w.exit
 }
 
-// newWatcherSet
-// new watcher set from parent context
+// newWatcherSet returns new watcher set from parent context
 func newWatcherSet(ctx context.Context) WatcherSet {
 	s := &watcherSetImpl{
 		ctx:      ctx,
diff --git a/remoting/listener.go b/remoting/listener.go
index 3713ba0ccf9d98d4470741785a9490e657cf051c..6cbb883181ff8ec1c9124f8d8cc3d7ec0920abd9 100644
--- a/remoting/listener.go
+++ b/remoting/listener.go
@@ -21,7 +21,7 @@ import (
 	"fmt"
 )
 
-// DataListener ...
+// DataListener defines common data listener interface
 type DataListener interface {
 	DataChange(eventType Event) bool //bool is return for interface implement is interesting
 }
@@ -30,15 +30,15 @@ type DataListener interface {
 // event type
 //////////////////////////////////////////
 
-// EventType ...
+// EventType means SourceObjectEventType
 type EventType int
 
 const (
-	// EventTypeAdd ...
+	// EventTypeAdd means add event
 	EventTypeAdd = iota
-	// EventTypeDel ...
+	// EventTypeDel means del event
 	EventTypeDel
-	// EventTypeUpdate ...
+	// EventTypeUpdate means update event
 	EventTypeUpdate
 )
 
@@ -56,7 +56,7 @@ func (t EventType) String() string {
 // service event
 //////////////////////////////////////////
 
-// Event ...
+// Event defines common elements for service event
 type Event struct {
 	Path    string
 	Action  EventType
diff --git a/remoting/nacos/builder.go b/remoting/nacos/builder.go
index 545a1e268cabe5cef829ff1cf44ef40b1161d590..4319627c6da6a5a19874f188d9eba6b032645ff1 100644
--- a/remoting/nacos/builder.go
+++ b/remoting/nacos/builder.go
@@ -22,8 +22,6 @@ import (
 	"strconv"
 	"strings"
 	"time"
-
-	"github.com/apache/dubbo-go/config"
 )
 
 import (
@@ -37,16 +35,10 @@ import (
 import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/config"
 )
 
-func NewNacosNamingClient(url *common.URL) (naming_client.INamingClient, error) {
-	nacosConfig, err := getNacosConfig(url)
-	if err != nil {
-		return nil, err
-	}
-	return clients.CreateNamingClient(nacosConfig)
-}
-
+// NewNacosConfigClient read the config from url and build an instance
 func NewNacosConfigClient(url *common.URL) (config_client.IConfigClient, error) {
 	nacosConfig, err := getNacosConfig(url)
 	if err != nil {
@@ -102,6 +94,7 @@ func getNacosConfig(url *common.URL) (map[string]interface{}, error) {
 	return configMap, nil
 }
 
+// NewNacosClient creates an instance with the config
 func NewNacosClient(rc *config.RemoteConfig) (naming_client.INamingClient, error) {
 	if len(rc.Address) == 0 {
 		return nil, perrors.New("nacos address is empty!")
diff --git a/remoting/zookeeper/client.go b/remoting/zookeeper/client.go
index f2d4f40106b69f90f6abd7ff11fe8a3b931fdefe..349faff2b07f2b2b6c7a086c1730f996b06ee63c 100644
--- a/remoting/zookeeper/client.go
+++ b/remoting/zookeeper/client.go
@@ -47,7 +47,7 @@ var (
 	errNilNode         = perrors.Errorf("node does not exist")
 )
 
-// ZookeeperClient ...
+// ZookeeperClient represents zookeeper client Configuration
 type ZookeeperClient struct {
 	name         string
 	ZkAddrs      []string
@@ -61,7 +61,7 @@ type ZookeeperClient struct {
 	eventRegistryLock sync.RWMutex
 }
 
-// StateToString ...
+// nolint
 func StateToString(state zk.State) string {
 	switch state {
 	case zk.StateDisconnected:
@@ -91,7 +91,7 @@ func StateToString(state zk.State) string {
 	}
 }
 
-// Options ...
+// nolint
 type Options struct {
 	zkName string
 	client *ZookeeperClient
@@ -99,17 +99,17 @@ type Options struct {
 	ts *zk.TestCluster
 }
 
-// Option ...
+// Option will define a function of handling Options
 type Option func(*Options)
 
-// WithZkName ...
+// WithZkName sets zk client name
 func WithZkName(name string) Option {
 	return func(opt *Options) {
 		opt.zkName = name
 	}
 }
 
-// ValidateZookeeperClient ...
+// ValidateZookeeperClient validates client and sets options
 func ValidateZookeeperClient(container ZkClientFacade, opts ...Option) error {
 	var (
 		err error
@@ -190,14 +190,14 @@ func newZookeeperClient(name string, zkAddrs []string, timeout time.Duration) (*
 	return z, nil
 }
 
-// WithTestCluster ...
+// WithTestCluster sets test cluser for zk client
 func WithTestCluster(ts *zk.TestCluster) Option {
 	return func(opt *Options) {
 		opt.ts = ts
 	}
 }
 
-// NewMockZookeeperClient ...
+// NewMockZookeeperClient returns a mock client instance
 func NewMockZookeeperClient(name string, timeout time.Duration, opts ...Option) (*zk.TestCluster, *ZookeeperClient, <-chan zk.Event, error) {
 	var (
 		err   error
@@ -237,7 +237,7 @@ func NewMockZookeeperClient(name string, timeout time.Duration, opts ...Option)
 	return ts, z, event, nil
 }
 
-// HandleZkEvent ...
+// HandleZkEvent handles zookeeper events
 func (z *ZookeeperClient) HandleZkEvent(session <-chan zk.Event) {
 	var (
 		state int
@@ -298,7 +298,7 @@ func (z *ZookeeperClient) HandleZkEvent(session <-chan zk.Event) {
 	}
 }
 
-// RegisterEvent ...
+// RegisterEvent registers zookeeper events
 func (z *ZookeeperClient) RegisterEvent(zkPath string, event *chan struct{}) {
 	if zkPath == "" || event == nil {
 		return
@@ -312,7 +312,7 @@ func (z *ZookeeperClient) RegisterEvent(zkPath string, event *chan struct{}) {
 	logger.Debugf("zkClient{%s} register event{path:%s, ptr:%p}", z.name, zkPath, event)
 }
 
-// UnregisterEvent ...
+// UnregisterEvent unregisters zookeeper events
 func (z *ZookeeperClient) UnregisterEvent(zkPath string, event *chan struct{}) {
 	if zkPath == "" {
 		return
@@ -339,7 +339,7 @@ func (z *ZookeeperClient) UnregisterEvent(zkPath string, event *chan struct{}) {
 	}
 }
 
-// Done ...
+// nolint
 func (z *ZookeeperClient) Done() <-chan struct{} {
 	return z.exit
 }
@@ -355,7 +355,7 @@ func (z *ZookeeperClient) stop() bool {
 	return false
 }
 
-// ZkConnValid ...
+// ZkConnValid validates zookeeper connection
 func (z *ZookeeperClient) ZkConnValid() bool {
 	select {
 	case <-z.exit:
@@ -373,7 +373,7 @@ func (z *ZookeeperClient) ZkConnValid() bool {
 	return valid
 }
 
-// Close ...
+// nolint
 func (z *ZookeeperClient) Close() {
 	if z == nil {
 		return
@@ -432,7 +432,7 @@ func (z *ZookeeperClient) CreateWithValue(basePath string, value []byte) error {
 	return nil
 }
 
-// Delete ...
+// nolint
 func (z *ZookeeperClient) Delete(basePath string) error {
 	err := errNilZkClientConn
 	conn := z.getConn()
@@ -443,7 +443,7 @@ func (z *ZookeeperClient) Delete(basePath string) error {
 	return perrors.WithMessagef(err, "Delete(basePath:%s)", basePath)
 }
 
-// RegisterTemp ...
+// RegisterTemp registers temporary node by @basePath and @node
 func (z *ZookeeperClient) RegisterTemp(basePath string, node string) (string, error) {
 	var (
 		err     error
@@ -467,7 +467,7 @@ func (z *ZookeeperClient) RegisterTemp(basePath string, node string) (string, er
 	return tmpPath, nil
 }
 
-// RegisterTempSeq ...
+// RegisterTempSeq register temporary sequence node by @basePath and @data
 func (z *ZookeeperClient) RegisterTempSeq(basePath string, data []byte) (string, error) {
 	var (
 		err     error
@@ -496,7 +496,7 @@ func (z *ZookeeperClient) RegisterTempSeq(basePath string, data []byte) (string,
 	return tmpPath, nil
 }
 
-// GetChildrenW ...
+// GetChildrenW gets children watch by @path
 func (z *ZookeeperClient) GetChildrenW(path string) ([]string, <-chan zk.Event, error) {
 	var (
 		err      error
@@ -531,7 +531,7 @@ func (z *ZookeeperClient) GetChildrenW(path string) ([]string, <-chan zk.Event,
 	return children, watcher.EvtCh, nil
 }
 
-// GetChildren ...
+// GetChildren gets children by @path
 func (z *ZookeeperClient) GetChildren(path string) ([]string, error) {
 	var (
 		err      error
@@ -562,7 +562,7 @@ func (z *ZookeeperClient) GetChildren(path string) ([]string, error) {
 	return children, nil
 }
 
-// ExistW ...
+// ExistW to judge watch whether it exists or not by @zkPath
 func (z *ZookeeperClient) ExistW(zkPath string) (<-chan zk.Event, error) {
 	var (
 		exist   bool
@@ -588,7 +588,7 @@ func (z *ZookeeperClient) ExistW(zkPath string) (<-chan zk.Event, error) {
 	return watcher.EvtCh, nil
 }
 
-// GetContent ...
+// GetContent gets content by @zkPath
 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 34741700ca2a9d86ee5321b0b19ed64b2b1a25a8..1b83a8f6fa793564684c6ab02aa9a8bfc43548c6 100644
--- a/remoting/zookeeper/client_test.go
+++ b/remoting/zookeeper/client_test.go
@@ -111,7 +111,8 @@ func TestCreateDelete(t *testing.T) {
 	assert.NoError(t, err)
 	err = z.Delete("/test1/test2/test3/test4")
 	assert.NoError(t, err)
-	// verifyEventOrder(t, event, []zk.EventType{zk.EventNodeCreated}, "event channel")
+	err2 := z.Delete("/test1/test2/test3/test4")
+	assert.NoError(t, err2)
 }
 
 func TestRegisterTemp(t *testing.T) {
diff --git a/remoting/zookeeper/facade.go b/remoting/zookeeper/facade.go
index 504395f76e6cfe26db35cc4b4336291133ee2709..5b8d19ea60932d6e8765c520e38a4eb3e8a996c3 100644
--- a/remoting/zookeeper/facade.go
+++ b/remoting/zookeeper/facade.go
@@ -40,7 +40,7 @@ type ZkClientFacade interface {
 	GetUrl() common.URL
 }
 
-// HandleClientRestart ...
+// HandleClientRestart keeps the connection between client and server
 func HandleClientRestart(r ZkClientFacade) {
 	var (
 		err error
diff --git a/remoting/zookeeper/listener.go b/remoting/zookeeper/listener.go
index fd7f0db3192b97cd225812ea6d76963f190cc21c..d47cafc8d14306fa72bd968f9564d5a5c38505c9 100644
--- a/remoting/zookeeper/listener.go
+++ b/remoting/zookeeper/listener.go
@@ -37,7 +37,7 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
-// ZkEventListener ...
+// nolint
 type ZkEventListener struct {
 	client      *ZookeeperClient
 	pathMapLock sync.Mutex
@@ -45,7 +45,7 @@ type ZkEventListener struct {
 	wg          sync.WaitGroup
 }
 
-// NewZkEventListener ...
+// NewZkEventListener returns a EventListener instance
 func NewZkEventListener(client *ZookeeperClient) *ZkEventListener {
 	return &ZkEventListener{
 		client:  client,
@@ -53,7 +53,7 @@ func NewZkEventListener(client *ZookeeperClient) *ZkEventListener {
 	}
 }
 
-// SetClient ...
+// nolint
 func (l *ZkEventListener) SetClient(client *ZookeeperClient) {
 	l.client = client
 }
@@ -70,7 +70,7 @@ func (l *ZkEventListener) ListenServiceNodeEvent(zkPath string, listener remotin
 	}(zkPath, listener)
 }
 
-// listenServiceNodeEvent ...
+// nolint
 func (l *ZkEventListener) listenServiceNodeEvent(zkPath string, listener ...remoting.DataListener) bool {
 	defer l.wg.Done()
 	var zkEvent zk.Event
diff --git a/test/integrate/dubbo/go-client/client.go b/test/integrate/dubbo/go-client/client.go
index c075ec22c3991aaea1b24ec4f59b3ab7e58520b4..4c62674d33dba7caca72ca7552e73c4c0fdf14c9 100644
--- a/test/integrate/dubbo/go-client/client.go
+++ b/test/integrate/dubbo/go-client/client.go
@@ -25,7 +25,7 @@ import (
 
 import (
 	hessian "github.com/apache/dubbo-go-hessian2"
-	_ "github.com/apache/dubbo-go/event/proxy/proxy_factory"
+	_ "github.com/apache/dubbo-go/common/proxy/proxy_factory"
 	"github.com/apache/dubbo-go/config"
 	_ "github.com/apache/dubbo-go/protocol/dubbo"
 	_ "github.com/apache/dubbo-go/registry/protocol"
diff --git a/test/integrate/dubbo/go-client/go.sum b/test/integrate/dubbo/go-client/go.sum
deleted file mode 100644
index 687fd0f337095443e2627b70a48c524fe335aba1..0000000000000000000000000000000000000000
--- a/test/integrate/dubbo/go-client/go.sum
+++ /dev/null
@@ -1,389 +0,0 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/Azure/azure-sdk-for-go v16.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
-github.com/Azure/go-autorest v10.7.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest v10.15.3+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
-github.com/Jeffail/gabs v1.1.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
-github.com/Microsoft/go-winio v0.4.3/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
-github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
-github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
-github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
-github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/SAP/go-hdb v0.12.0/go.mod h1:etBT+FAi1t5k3K3tf5vQTnosgYmhDkRi8jEnQqCnxF0=
-github.com/SermoDigital/jose v0.0.0-20180104203859-803625baeddc/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA=
-github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
-github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
-github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw=
-github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-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 v1.4.1/go.mod h1:hzP9PQkcYFcBUgedttDeimugDNqbmGzh18QQy/vBjnw=
-github.com/apache/dubbo-go-hessian2 v1.4.0/go.mod h1:VwEnsOMidkM1usya2uPfGpSLO9XUF//WQcWn3y+jFz8=
-github.com/apache/dubbo-go-hessian2 v1.5.0/go.mod h1:VwEnsOMidkM1usya2uPfGpSLO9XUF//WQcWn3y+jFz8=
-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=
-github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/asaskevich/govalidator v0.0.0-20180319081651-7d2e70ef918f/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/aws/aws-sdk-go v1.15.24/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
-github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
-github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
-github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
-github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
-github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
-github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/coredns/coredns v1.1.2/go.mod h1:zASH/MVDgR6XZTbxvOnsZfffS+31vg6Ackf/wo1+AM0=
-github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/creasty/defaults v1.3.0/go.mod h1:CIEEvs7oIVZm30R8VxtFJs+4k201gReYyuYHJxZc68I=
-github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/denisenkom/go-mssqldb v0.0.0-20180620032804-94c9c97e8c9f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
-github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/digitalocean/godo v1.1.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
-github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
-github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
-github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/dubbogo/getty v1.3.3/go.mod h1:U92BDyJ6sW9Jpohr2Vlz8w2uUbIbNZ3d+6rJvFTSPp0=
-github.com/dubbogo/go-zookeeper v1.0.0/go.mod h1:fn6n2CAEer3novYgk9ULLwAjuV8/g4DdC2ENwRb6E+c=
-github.com/dubbogo/gost v1.5.1/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
-github.com/dubbogo/gost v1.5.2/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
-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/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
-github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/emicklei/go-restful/v3 v3.0.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-github.com/envoyproxy/go-control-plane v0.8.0/go.mod h1:GSSbY9P1neVhdY7G4wu+IK1rk/dqhiCC/4ExuWJZVuk=
-github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fatih/structs v0.0.0-20180123065059-ebf56d35bba7/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
-github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
-github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
-github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
-github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
-github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
-github.com/go-resty/resty/v2 v2.1.0/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
-github.com/go-sql-driver/mysql v0.0.0-20180618115901-749ddf1598b4/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
-github.com/gocql/gocql v0.0.0-20180617115710-e06f8c1bcd78/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
-github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
-github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
-github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
-github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
-github.com/gophercloud/gophercloud v0.0.0-20180828235145-f29afc2cceca/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
-github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
-github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
-github.com/hashicorp/consul v1.5.3/go.mod h1:61E2GJCPEP3oq8La7sfDdWGQ66+Zbxzw5ecOdFD7xIE=
-github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
-github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-bexpr v0.1.0/go.mod h1:ANbpTX1oAql27TZkKVeW8p1w8NTdnyzPe/0qqPCKohU=
-github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de/go.mod h1:xIwEieBHERyEvaeKF/TcHh1Hu+lxPM+n2vT1+g9I4m4=
-github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-discover v0.0.0-20190403160810-22221edb15cd/go.mod h1:ueUgD9BeIocT7QNuvxSyJyPAM9dfifBcaWmeybb67OY=
-github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
-github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-memdb v0.0.0-20180223233045-1289e7fffe71/go.mod h1:kbfItVoBJwCfKXDXN4YoAXjxcFVZ7MRrJzyTX6H4giE=
-github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116/go.mod h1:JSqWYsict+jzcj0+xElxyrBQRPNoiWQuddnxArJ7XHQ=
-github.com/hashicorp/go-raftchunking v0.6.1/go.mod h1:cGlg3JtDy7qy6c/3Bu660Mic1JF+7lWqIwCFSb08fX0=
-github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
-github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
-github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v0.0.0-20170202080759-03c5bf6be031/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/hcl v0.0.0-20180906183839-65a6292f0157/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hashicorp/hil v0.0.0-20160711231837-1e86c6b523c5/go.mod h1:KHvg/R2/dPtaePb16oW4qIyzkMxXOL38xjRN64adsts=
-github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
-github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
-github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
-github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69/go.mod h1:/z+jUGRBlwVpUZfjute9jWaF6/HuhjuFQuL1YXzVD1Q=
-github.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
-github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk=
-github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hashicorp/vault v0.10.3/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0=
-github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20190318174639-195e0e9d07f1/go.mod h1:VJHHT2SC1tAPrfENQeBhLlb5FbZoKZM+oC/ROmEftz0=
-github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo=
-github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
-github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee/go.mod h1:N0t2vlmpe8nyZB5ouIbJQPDSR+mH6oe7xHB9VZHSUzM=
-github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag=
-github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
-github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA=
-github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/keybase/go-crypto v0.0.0-20180614160407-5114a9a81e1b/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE=
-github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f/go.mod h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8=
-github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0=
-github.com/lib/pq v0.0.0-20180523175426-90697d60dd84/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
-github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
-github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
-github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb/go.mod h1:CEkSvEpoveoYjA81m4HNeYQ0sge0LFGKSEqO3JKHllo=
-github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk=
-github.com/oklog/run v0.0.0-20180308005104-6934b124db28/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
-github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
-github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
-github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
-github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/patrickmn/go-cache v0.0.0-20180527043350-9f6ff22cfff8/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
-github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-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/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/shirou/gopsutil v0.0.0-20181107111621-48177ef5f880/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
-github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
-github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
-github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw=
-github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-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/go.mod h1:3UvtWlqm8j5JbwYZh80D/PVBt0mJ1eJiYgZMibh0H/k=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE=
-github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
-github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/zouyx/agollo v0.0.0-20191114083447-dde9fc9f35b8/go.mod h1:S1cAa98KMFv4Sa8SbJ6ZtvOmf0VlgH0QJ1gXI0lBfBY=
-go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
-go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190508220229-2d0786266e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-google.golang.org/api v0.0.0-20180829000535-087779f1d2c9/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
-gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
-gopkg.in/ory-am/dockertest.v3 v3.3.4/go.mod h1:s9mmoLkaGeAh97qygnNj4xWkiN7e1SKekYC6CovU+ek=
-gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
-gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-istio.io/gogo-genproto v0.0.0-20190124151557-6d926a6e6feb/go.mod h1:eIDJ6jNk/IeJz6ODSksHl5Aiczy5JUq6vFhJWI5OtiI=
-k8s.io/api v0.0.0-20180806132203-61b11ee65332/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
-k8s.io/api v0.0.0-20190325185214-7544f9db76f6/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
-k8s.io/apimachinery v0.0.0-20180821005732-488889b0007f/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
-k8s.io/apimachinery v0.0.0-20190223001710-c182ff3b9841/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
-k8s.io/client-go v8.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
-k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
-sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
-sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
diff --git a/test/integrate/dubbo/go-server/server.go b/test/integrate/dubbo/go-server/server.go
index 4cc6c490835d7ba29d139d71892b5e6e19d628e5..115bf0a4d78f171eb7f786808def91879ed93947 100644
--- a/test/integrate/dubbo/go-server/server.go
+++ b/test/integrate/dubbo/go-server/server.go
@@ -25,7 +25,7 @@ import (
 	hessian "github.com/apache/dubbo-go-hessian2"
 	_ "github.com/apache/dubbo-go/cluster/cluster_impl"
 	_ "github.com/apache/dubbo-go/cluster/loadbalance"
-	_ "github.com/apache/dubbo-go/event/proxy/proxy_factory"
+	_ "github.com/apache/dubbo-go/common/proxy/proxy_factory"
 	"github.com/apache/dubbo-go/config"
 	_ "github.com/apache/dubbo-go/filter/filter_impl"
 	_ "github.com/apache/dubbo-go/protocol/dubbo"