diff --git a/.asf.yaml b/.asf.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8d84e695a59e8064cf06a2f8879564efd5588d44
--- /dev/null
+++ b/.asf.yaml
@@ -0,0 +1,5 @@
+notifications:
+    commits:      commits@dubbo.apache.org
+    issues:       notifications@dubbo.apache.org
+    pullrequests: notifications@dubbo.apache.org
+    jira_options: link label link label
diff --git a/.travis.yml b/.travis.yml
index 1b46f5d872932b7ed307ceaf802c95997b2800e6..566c88ece05bd80175eea2d1de8fd061a279e273 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,23 +1,32 @@
-language: go
+dist: trusty
+sudo: required
 
+# define the dependence env
+language: go
 os:
   - linux
-
 go:
   - "1.13"
-
+services:
+  - docker
 env:
   - GO111MODULE=on
-
 install: true
 
+# define ci-stage
 script:
+  # license-check
+  - echo 'start license check'
   - go fmt ./... && [[ -z `git status -s` ]]
   - sh before_validate_license.sh
   - chmod u+x /tmp/tools/license/license-header-checker
   - /tmp/tools/license/license-header-checker -v -a -r -i vendor  /tmp/tools/license/license.txt . go  && [[ -z `git status -s` ]]
+  # unit-test
+  - echo 'start unit-test'
   - chmod u+x before_ut.sh && ./before_ut.sh
   - go mod vendor && go test ./... -coverprofile=coverage.txt -covermode=atomic
+  # integrate-test
+  - chmod +x integrate_test.sh && ./integrate_test.sh
 
 after_success:
   - bash <(curl -s https://codecov.io/bash)
diff --git a/README.md b/README.md
index 5c4de0559d534e03b23d136da5f5f23ff6768d55..3f8394536f944518f8d969289147272c32f169da 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ Apache License, Version 2.0
 
 ## Release note ##
 
-[v1.4.0-rc1 - Mar 12, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.4.0-rc1)
+[v1.4.0 - Mar 17, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.4.0)
 
 [v1.3.0 - Mar 1, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.3.0)
 
@@ -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 5dec68fd6134fc58bf265ea382473d724332ecc6..582c5cf04cba08d4167c87b40fd0e86a3aa2ceb0 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -15,7 +15,7 @@ Apache License, Version 2.0
 
 ## 鍙戝竷鏃ュ織 ##
 
-[v1.4.0-rc1 - 2020骞�3鏈�12鏃(https://github.com/apache/dubbo-go/releases/tag/v1.4.0-rc1)
+[v1.4.0 - 2020骞�3鏈�17鏃(https://github.com/apache/dubbo-go/releases/tag/v1.4.0)
 
 [v1.3.0 - 2020骞�3鏈�1鏃(https://github.com/apache/dubbo-go/releases/tag/v1.3.0)
 
@@ -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 c2cebd3843d453a2d46d031e711e0efebd240fda..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,10 +41,11 @@ 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(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker {
+func registerAvailable(invoker *mock.MockInvoker) protocol.Invoker {
 	extension.SetLoadbalance("random", loadbalance.NewRandomLoadBalance)
 	availableCluster := NewAvailableCluster()
 
@@ -60,7 +63,7 @@ func TestAvailableClusterInvokerSuccess(t *testing.T) {
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerAvailable(t, invoker)
+	clusterInvoker := registerAvailable(invoker)
 
 	mockResult := &protocol.RPCResult{Rest: rest{tried: 0, success: true}}
 	invoker.EXPECT().IsAvailable().Return(true)
@@ -76,7 +79,7 @@ func TestAvailableClusterInvokerNoAvail(t *testing.T) {
 	defer ctrl.Finish()
 
 	invoker := mock.NewMockInvoker(ctrl)
-	clusterInvoker := registerAvailable(t, invoker)
+	clusterInvoker := registerAvailable(invoker)
 
 	invoker.EXPECT().IsAvailable().Return(false)
 
diff --git a/cluster/cluster_impl/base_cluster_invoker.go b/cluster/cluster_impl/base_cluster_invoker.go
index 12799994125c4bf5d968dfc811cda374effbf85c..bbdfa715d7cdc461689e60a5a41171ad5c9770e1 100644
--- a/cluster/cluster_impl/base_cluster_invoker.go
+++ b/cluster/cluster_impl/base_cluster_invoker.go
@@ -87,8 +87,11 @@ 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
@@ -98,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..8121e5c0eab16b92b323fbc0e6e944231d1ed1b9 100644
--- a/cluster/cluster_impl/base_cluster_invoker_test.go
+++ b/cluster/cluster_impl/base_cluster_invoker_test.go
@@ -33,25 +33,33 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-func Test_StickyNormal(t *testing.T) {
+const (
+	baseClusterInvokerMethodName = "getUser"
+	baseClusterInvokerFormat     = "dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider"
+)
+
+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))
+		url, _ := common.NewURL(fmt.Sprintf(baseClusterInvokerFormat, i))
 		url.SetParam("sticky", "true")
 		invokers = append(invokers, NewMockInvoker(url, 1))
 	}
 	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(baseClusterInvokerMethodName, 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))
+		url, _ := common.NewURL(fmt.Sprintf(baseClusterInvokerFormat, i))
 		url.SetParam("sticky", "true")
 		invokers = append(invokers, NewMockInvoker(url, 1))
 	}
@@ -59,8 +67,8 @@ func Test_StickyNormalWhenError(t *testing.T) {
 	base.availablecheck = true
 
 	invoked := []protocol.Invoker{}
-	result := base.doSelect(loadbalance.NewRandomLoadBalance(), invocation.NewRPCInvocation("getUser", nil, nil), invokers, invoked)
+	result := base.doSelect(loadbalance.NewRandomLoadBalance(), invocation.NewRPCInvocation(baseClusterInvokerMethodName, nil, nil), invokers, invoked)
 	invoked = append(invoked, result)
-	result1 := base.doSelect(loadbalance.NewRandomLoadBalance(), invocation.NewRPCInvocation("getUser", nil, nil), invokers, invoked)
+	result1 := base.doSelect(loadbalance.NewRandomLoadBalance(), invocation.NewRPCInvocation(baseClusterInvokerMethodName, nil, nil), invokers, invoked)
 	assert.NotEqual(t, result, result1)
 }
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_invoker.go b/cluster/cluster_impl/failback_cluster_invoker.go
index 46b0ff634e56c45223a5aeb5566b9b1401518960..af17a93756a6f558c7da063eec9d8052b83cbe69 100644
--- a/cluster/cluster_impl/failback_cluster_invoker.go
+++ b/cluster/cluster_impl/failback_cluster_invoker.go
@@ -72,6 +72,19 @@ func newFailbackClusterInvoker(directory cluster.Directory) protocol.Invoker {
 	return invoker
 }
 
+func (invoker *failbackClusterInvoker) tryTimerTaskProc(ctx context.Context, retryTask *retryTimerTask) {
+	invoked := make([]protocol.Invoker, 0)
+	invoked = append(invoked, retryTask.lastInvoker)
+
+	retryInvoker := invoker.doSelect(retryTask.loadbalance, retryTask.invocation, retryTask.invokers, invoked)
+	var result protocol.Result
+	result = retryInvoker.Invoke(ctx, retryTask.invocation)
+	if result.Error() != nil {
+		retryTask.lastInvoker = retryInvoker
+		invoker.checkRetry(retryTask, result.Error())
+	}
+}
+
 func (invoker *failbackClusterInvoker) process(ctx context.Context) {
 	invoker.ticker = time.NewTicker(time.Second * 1)
 	for range invoker.ticker.C {
@@ -91,25 +104,11 @@ func (invoker *failbackClusterInvoker) process(ctx context.Context) {
 			}
 
 			// ignore return. the get must success.
-			_, err = invoker.taskList.Get(1)
-			if err != nil {
+			if _, err = invoker.taskList.Get(1); err != nil {
 				logger.Warnf("get task found err: %v\n", err)
 				break
 			}
-
-			go func(retryTask *retryTimerTask) {
-				invoked := make([]protocol.Invoker, 0)
-				invoked = append(invoked, retryTask.lastInvoker)
-
-				retryInvoker := invoker.doSelect(retryTask.loadbalance, retryTask.invocation, retryTask.invokers, invoked)
-				var result protocol.Result
-				result = retryInvoker.Invoke(ctx, retryTask.invocation)
-				if result.Error() != nil {
-					retryTask.lastInvoker = retryInvoker
-					invoker.checkRetry(retryTask, result.Error())
-				}
-			}(retryTask)
-
+			go invoker.tryTimerTaskProc(ctx, retryTask)
 		}
 	}
 }
@@ -129,29 +128,26 @@ func (invoker *failbackClusterInvoker) checkRetry(retryTask *retryTimerTask, err
 
 func (invoker *failbackClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	invokers := invoker.directory.List(invocation)
-	err := invoker.checkInvokers(invokers, invocation)
-	if err != nil {
+	if err := invoker.checkInvokers(invokers, invocation); err != nil {
 		logger.Errorf("Failed to invoke the method %v in the service %v, wait for retry in background. Ignored exception: %v.\n",
 			invocation.MethodName(), invoker.GetUrl().Service(), err)
 		return &protocol.RPCResult{}
 	}
-	url := invokers[0].GetUrl()
-	methodName := invocation.MethodName()
+
 	//Get the service loadbalance config
+	url := invokers[0].GetUrl()
 	lb := url.GetParam(constant.LOADBALANCE_KEY, constant.DEFAULT_LOADBALANCE)
-
 	//Get the service method loadbalance config if have
+	methodName := invocation.MethodName()
 	if v := url.GetMethodParam(methodName, constant.LOADBALANCE_KEY, ""); v != "" {
 		lb = v
 	}
-	loadbalance := extension.GetLoadbalance(lb)
 
+	loadBalance := extension.GetLoadbalance(lb)
 	invoked := make([]protocol.Invoker, 0, len(invokers))
-	var result protocol.Result
-
-	ivk := invoker.doSelect(loadbalance, invocation, invokers, invoked)
+	ivk := invoker.doSelect(loadBalance, invocation, invokers, invoked)
 	//DO INVOKE
-	result = ivk.Invoke(ctx, invocation)
+	result := ivk.Invoke(ctx, invocation)
 	if result.Error() != nil {
 		invoker.once.Do(func() {
 			invoker.taskList = queue.New(invoker.failbackTasks)
@@ -164,7 +160,7 @@ func (invoker *failbackClusterInvoker) Invoke(ctx context.Context, invocation pr
 			return &protocol.RPCResult{}
 		}
 
-		timerTask := newRetryTimerTask(loadbalance, invocation, invokers, ivk)
+		timerTask := newRetryTimerTask(loadBalance, invocation, invokers, ivk)
 		invoker.taskList.Put(timerTask)
 
 		logger.Errorf("Failback to invoke the method %v in the service %v, wait for retry in background. Ignored exception: %v.\n",
@@ -172,7 +168,6 @@ func (invoker *failbackClusterInvoker) Invoke(ctx context.Context, invocation pr
 		// ignore
 		return &protocol.RPCResult{}
 	}
-
 	return result
 }
 
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 1be21067a6a9045cb6ae6f84655d516fea1f844b..e05b79202cd202334db1c19421e3163ee28bac26 100644
--- a/cluster/cluster_impl/failover_cluster_test.go
+++ b/cluster/cluster_impl/failover_cluster_test.go
@@ -101,14 +101,14 @@ 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()
 
 	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), common.WithParams(urlParam))
-		invokers = append(invokers, NewMockInvoker(url, successCount))
+		newUrl, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i), common.WithParams(urlParam))
+		invokers = append(invokers, NewMockInvoker(newUrl, successCount))
 	}
 
 	staticDir := directory.NewStaticDirectory(invokers)
@@ -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.go b/cluster/directory/base_directory.go
index 75d9ef26567df0fbd83f5d9f94c8548d1e8e633d..7865b807ad4bedfd045aadffbfdbf2f19186e293 100644
--- a/cluster/directory/base_directory.go
+++ b/cluster/directory/base_directory.go
@@ -83,16 +83,16 @@ func (dir *BaseDirectory) SetRouters(urls []*common.URL) {
 		return
 	}
 
-	routers := make([]router.Router, 0, len(urls))
+	routers := make([]router.PriorityRouter, 0, len(urls))
 
 	for _, url := range urls {
 		routerKey := url.GetParam(constant.ROUTER_KEY, "")
 
 		if len(routerKey) > 0 {
 			factory := extension.GetRouterFactory(url.Protocol)
-			r, err := factory.NewRouter(url)
+			r, err := factory.NewPriorityRouter(url)
 			if err != nil {
-				logger.Errorf("Create router fail. router key: %s, error: %v", routerKey, url.Service(), err)
+				logger.Errorf("Create router fail. router key: %s, url:%s, error: %+v", routerKey, url.Service(), err)
 				return
 			}
 			routers = append(routers, r)
diff --git a/cluster/directory/base_directory_test.go b/cluster/directory/base_directory_test.go
index d5993959f1d37f343a612e2bee305461d49535d0..8b60163b79b7120829e51f69238474a127133fb4 100644
--- a/cluster/directory/base_directory_test.go
+++ b/cluster/directory/base_directory_test.go
@@ -34,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(fmt.Sprintf("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(fmt.Sprintf("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider"))
 	directory := NewBaseDirectory(&url)
 
 	assert.NotNil(t, directory)
@@ -63,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.go b/cluster/directory/static_directory.go
index 9f600fedc40cf29a40abca6c11652935f20473b4..87f51356495dbd0a956c42bf4f34022b4d21ad4d 100644
--- a/cluster/directory/static_directory.go
+++ b/cluster/directory/static_directory.go
@@ -61,7 +61,7 @@ func (dir *staticDirectory) IsAvailable() bool {
 // List List invokers
 func (dir *staticDirectory) List(invocation protocol.Invocation) []protocol.Invoker {
 	l := len(dir.invokers)
-	invokers := make([]protocol.Invoker, l, l)
+	invokers := make([]protocol.Invoker, l)
 	copy(invokers, dir.invokers)
 	routerChain := dir.RouterChain()
 
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 957c110663d6c56ada15543d372e210fa83bf74b..84fbb268c7a8ec32f007a734e2d6da56ef3c6d25 100644
--- a/cluster/loadbalance/consistent_hash.go
+++ b/cluster/loadbalance/consistent_hash.go
@@ -27,7 +27,9 @@ import (
 	"strconv"
 	"strings"
 )
-
+import (
+	gxsort "github.com/dubbogo/gost/sort"
+)
 import (
 	"github.com/apache/dubbo-go/cluster"
 	"github.com/apache/dubbo-go/common/constant"
@@ -40,7 +42,7 @@ const (
 	ConsistentHash = "consistenthash"
 	// HashNodes ...
 	HashNodes = "hash.nodes"
-	// HashArguments ...
+	// HashArguments  key of hash arguments  in url
 	HashArguments = "hash.arguments"
 )
 
@@ -53,16 +55,18 @@ func init() {
 	extension.SetLoadbalance(ConsistentHash, NewConsistentHashLoadBalance)
 }
 
-// ConsistentHashLoadBalance ...
+// ConsistentHashLoadBalance implementation of load balancing: using consistent hashing
 type ConsistentHashLoadBalance struct {
 }
 
-// NewConsistentHashLoadBalance ...
+// NewConsistentHashLoadBalance creates NewConsistentHashLoadBalance
+//
+// The same parameters of the request is always sent to the same provider.
 func NewConsistentHashLoadBalance() cluster.LoadBalance {
 	return &ConsistentHashLoadBalance{}
 }
 
-// Select ...
+// Select gets invoker based on load balancing strategy
 func (lb *ConsistentHashLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker {
 	methodName := invocation.MethodName()
 	key := invokers[0].GetUrl().ServiceKey() + "." + methodName
@@ -85,27 +89,12 @@ func (lb *ConsistentHashLoadBalance) Select(invokers []protocol.Invoker, invocat
 	return selector.Select(invocation)
 }
 
-// Uint32Slice ...
-type Uint32Slice []uint32
-
-func (s Uint32Slice) Len() int {
-	return len(s)
-}
-
-func (s Uint32Slice) Less(i, j int) bool {
-	return s[i] < s[j]
-}
-
-func (s Uint32Slice) Swap(i, j int) {
-	s[i], s[j] = s[j], s[i]
-}
-
-// ConsistentHashSelector ...
+// ConsistentHashSelector implementation of Selector:get invoker based on load balancing strategy
 type ConsistentHashSelector struct {
 	hashCode        uint32
 	replicaNum      int
 	virtualInvokers map[uint32]protocol.Invoker
-	keys            Uint32Slice
+	keys            gxsort.Uint32Slice
 	argumentIndex   []int
 }
 
@@ -141,7 +130,7 @@ func newConsistentHashSelector(invokers []protocol.Invoker, methodName string,
 	return selector
 }
 
-// Select ...
+// Select gets invoker based on load balancing strategy
 func (c *ConsistentHashSelector) Select(invocation protocol.Invocation) protocol.Invoker {
 	key := c.toKey(invocation.Arguments())
 	digest := md5.Sum([]byte(key))
diff --git a/cluster/loadbalance/consistent_hash_test.go b/cluster/loadbalance/consistent_hash_test.go
index a44293172c6e2c96bd098a19306f69260b713689..9f22d39dc46243dddda89151e07dbea39ab933fb 100644
--- a/cluster/loadbalance/consistent_hash_test.go
+++ b/cluster/loadbalance/consistent_hash_test.go
@@ -18,6 +18,7 @@
 package loadbalance
 
 import (
+	"fmt"
 	"testing"
 )
 
@@ -32,6 +33,19 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
+const (
+	ip       = "192.168.1.0"
+	port8080 = 8080
+	port8082 = 8082
+
+	url8080Short = "dubbo://192.168.1.0:8080"
+	url8081Short = "dubbo://192.168.1.0:8081"
+	url20000     = "dubbo://192.168.1.0:20000/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1"
+	url8080      = "dubbo://192.168.1.0:8080/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1"
+	url8081      = "dubbo://192.168.1.0:8081/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1"
+	url8082      = "dubbo://192.168.1.0:8082/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1"
+)
+
 func TestConsistentHashSelectorSuite(t *testing.T) {
 	suite.Run(t, new(consistentHashSelectorSuite))
 }
@@ -43,8 +57,7 @@ type consistentHashSelectorSuite struct {
 
 func (s *consistentHashSelectorSuite) SetupTest() {
 	var invokers []protocol.Invoker
-	url, _ := common.NewURL(
-		"dubbo://192.168.1.0:20000/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	url, _ := common.NewURL(url20000)
 	invokers = append(invokers, protocol.NewBaseInvoker(url))
 	s.selector = newConsistentHashSelector(invokers, "echo", 999944)
 }
@@ -55,14 +68,14 @@ func (s *consistentHashSelectorSuite) TestToKey() {
 }
 
 func (s *consistentHashSelectorSuite) TestSelectForKey() {
-	url1, _ := common.NewURL("dubbo://192.168.1.0:8080")
-	url2, _ := common.NewURL("dubbo://192.168.1.0:8081")
+	url1, _ := common.NewURL(url8080Short)
+	url2, _ := common.NewURL(url8081Short)
 	s.selector.virtualInvokers = make(map[uint32]protocol.Invoker)
 	s.selector.virtualInvokers[99874] = protocol.NewBaseInvoker(url1)
 	s.selector.virtualInvokers[9999945] = protocol.NewBaseInvoker(url2)
 	s.selector.keys = []uint32{99874, 9999945}
 	result := s.selector.selectForKey(9999944)
-	s.Equal(result.GetUrl().String(), "dubbo://192.168.1.0:8081?")
+	s.Equal(result.GetUrl().String(), url8081Short+"?")
 }
 
 func TestConsistentHashLoadBalanceSuite(t *testing.T) {
@@ -83,11 +96,11 @@ type consistentHashLoadBalanceSuite struct {
 
 func (s *consistentHashLoadBalanceSuite) SetupTest() {
 	var err error
-	s.url1, err = common.NewURL("dubbo://192.168.1.0:8080/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	s.url1, err = common.NewURL(url8080)
 	s.NoError(err)
-	s.url2, err = common.NewURL("dubbo://192.168.1.0:8081/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	s.url2, err = common.NewURL(url8081)
 	s.NoError(err)
-	s.url3, err = common.NewURL("dubbo://192.168.1.0:8082/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	s.url3, err = common.NewURL(url8082)
 	s.NoError(err)
 
 	s.invoker1 = protocol.NewBaseInvoker(s.url1)
@@ -101,9 +114,9 @@ func (s *consistentHashLoadBalanceSuite) SetupTest() {
 func (s *consistentHashLoadBalanceSuite) TestSelect() {
 	args := []interface{}{"name", "password", "age"}
 	invoker := s.lb.Select(s.invokers, invocation.NewRPCInvocation("echo", args, nil))
-	s.Equal(invoker.GetUrl().Location, "192.168.1.0:8080")
+	s.Equal(invoker.GetUrl().Location, fmt.Sprintf("%s:%d", ip, port8080))
 
 	args = []interface{}{"ok", "abc"}
 	invoker = s.lb.Select(s.invokers, invocation.NewRPCInvocation("echo", args, nil))
-	s.Equal(invoker.GetUrl().Location, "192.168.1.0:8082")
+	s.Equal(invoker.GetUrl().Location, fmt.Sprintf("%s:%d", ip, port8082))
 }
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..b94d7da43d5bd42e6798fca750c8616830a8df8f 100644
--- a/cluster/loadbalance/random_test.go
+++ b/cluster/loadbalance/random_test.go
@@ -36,35 +36,41 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-func Test_RandomlbSelect(t *testing.T) {
+const (
+	tmpUrl       = "dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"
+	tmpUrlFormat = "dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider"
+	tmpIp        = "192.168.1.100"
+)
+
+func TestRandomlbSelect(t *testing.T) {
 	randomlb := NewRandomLoadBalance()
 
 	invokers := []protocol.Invoker{}
 
-	url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", 0))
+	url, _ := common.NewURL(fmt.Sprintf(tmpUrlFormat, 0))
 	invokers = append(invokers, protocol.NewBaseInvoker(url))
 	i := randomlb.Select(invokers, &invocation.RPCInvocation{})
 	assert.True(t, i.GetUrl().URLEqual(url))
 
 	for i := 1; i < 10; i++ {
-		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url, _ := common.NewURL(fmt.Sprintf(tmpUrlFormat, i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 	randomlb.Select(invokers, &invocation.RPCInvocation{})
 }
 
-func Test_RandomlbSelectWeight(t *testing.T) {
+func TestRandomlbSelectWeight(t *testing.T) {
 	randomlb := NewRandomLoadBalance()
 
 	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))
+		url, _ := common.NewURL(fmt.Sprintf(tmpUrlFormat, i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 
 	urlParams := url.Values{}
 	urlParams.Set("methods.test."+constant.WEIGHT_KEY, "10000000000000")
-	urll, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"), common.WithParams(urlParams))
+	urll, _ := common.NewURL(tmpUrl, common.WithParams(urlParams))
 	invokers = append(invokers, protocol.NewBaseInvoker(urll))
 	ivc := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("test"))
 
@@ -72,7 +78,7 @@ func Test_RandomlbSelectWeight(t *testing.T) {
 	var selected float64
 	for i := 0; i < 10000; i++ {
 		s := randomlb.Select(invokers, ivc)
-		if s.GetUrl().Ip == "192.168.1.100" {
+		if s.GetUrl().Ip == tmpIp {
 			selected++
 		}
 		selectedInvoker = append(selectedInvoker, s)
@@ -84,18 +90,18 @@ func Test_RandomlbSelectWeight(t *testing.T) {
 	})
 }
 
-func Test_RandomlbSelectWarmup(t *testing.T) {
+func TestRandomlbSelectWarmup(t *testing.T) {
 	randomlb := NewRandomLoadBalance()
 
 	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))
+		url, _ := common.NewURL(fmt.Sprintf(tmpUrlFormat, i))
 		invokers = append(invokers, protocol.NewBaseInvoker(url))
 	}
 
 	urlParams := url.Values{}
 	urlParams.Set(constant.REMOTE_TIMESTAMP_KEY, strconv.FormatInt(time.Now().Add(time.Minute*(-9)).Unix(), 10))
-	urll, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"), common.WithParams(urlParams))
+	urll, _ := common.NewURL(tmpUrl, common.WithParams(urlParams))
 	invokers = append(invokers, protocol.NewBaseInvoker(urll))
 	ivc := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("test"))
 
@@ -103,7 +109,7 @@ func Test_RandomlbSelectWarmup(t *testing.T) {
 	var selected float64
 	for i := 0; i < 10000; i++ {
 		s := randomlb.Select(invokers, ivc)
-		if s.GetUrl().Ip == "192.168.1.100" {
+		if s.GetUrl().Ip == tmpIp {
 			selected++
 		}
 		selectedInvoker = append(selectedInvoker, s)
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.go b/cluster/router/chain/chain.go
index d48a837eba2080867f370b0cd90e38a0bdf5e417..97d20ac5fca0688d3f1f48c6ffc12314f5dc3904 100644
--- a/cluster/router/chain/chain.go
+++ b/cluster/router/chain/chain.go
@@ -40,19 +40,21 @@ type RouterChain struct {
 	// Full list of addresses from registry, classified by method name.
 	invokers []protocol.Invoker
 	// Containing all routers, reconstruct every time 'route://' urls change.
-	routers []router.Router
+	routers []router.PriorityRouter
 	// Fixed router instances: ConfigConditionRouter, TagRouter, e.g., the rule for each instance may change but the
 	// instance will never delete or recreate.
-	builtinRouters []router.Router
+	builtinRouters []router.PriorityRouter
 
 	mutex sync.RWMutex
+
+	url common.URL
 }
 
 // Route Loop routers in RouterChain and call Route method to determine the target invokers list.
 func (c *RouterChain) Route(invoker []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
 	finalInvokers := invoker
 	l := len(c.routers)
-	rs := make([]router.Router, l, int(math.Ceil(float64(l)*1.2)))
+	rs := make([]router.PriorityRouter, l, int(math.Ceil(float64(l)*1.2)))
 	c.mutex.RLock()
 	copy(rs, c.routers)
 	c.mutex.RUnlock()
@@ -67,8 +69,8 @@ func (c *RouterChain) Route(invoker []protocol.Invoker, url *common.URL, invocat
 // New a array add builtinRouters which is not sorted in RouterChain and routers
 // Sort the array
 // Replace router array in RouterChain
-func (c *RouterChain) AddRouters(routers []router.Router) {
-	newRouters := make([]router.Router, 0, len(c.builtinRouters)+len(routers))
+func (c *RouterChain) AddRouters(routers []router.PriorityRouter) {
+	newRouters := make([]router.PriorityRouter, 0, len(c.builtinRouters)+len(routers))
 	newRouters = append(newRouters, c.builtinRouters...)
 	newRouters = append(newRouters, routers...)
 	sortRouter(newRouters)
@@ -77,6 +79,11 @@ func (c *RouterChain) AddRouters(routers []router.Router) {
 	c.routers = newRouters
 }
 
+// URL Return URL in RouterChain
+func (c *RouterChain) URL() common.URL {
+	return c.url
+}
+
 // NewRouterChain Use url to init router chain
 // Loop routerFactories and call NewRouter method
 func NewRouterChain(url *common.URL) (*RouterChain, error) {
@@ -84,9 +91,9 @@ func NewRouterChain(url *common.URL) (*RouterChain, error) {
 	if len(routerFactories) == 0 {
 		return nil, perrors.Errorf("No routerFactory exits , create one please")
 	}
-	routers := make([]router.Router, 0, len(routerFactories))
+	routers := make([]router.PriorityRouter, 0, len(routerFactories))
 	for key, routerFactory := range routerFactories {
-		r, err := routerFactory().NewRouter(url)
+		r, err := routerFactory().NewPriorityRouter(url)
 		if r == nil || err != nil {
 			logger.Errorf("router chain build router fail! routerFactories key:%s  error:%s", key, err.Error())
 			continue
@@ -94,7 +101,7 @@ func NewRouterChain(url *common.URL) (*RouterChain, error) {
 		routers = append(routers, r)
 	}
 
-	newRouters := make([]router.Router, len(routers))
+	newRouters := make([]router.PriorityRouter, len(routers))
 	copy(newRouters, routers)
 
 	sortRouter(newRouters)
@@ -103,17 +110,20 @@ func NewRouterChain(url *common.URL) (*RouterChain, error) {
 		builtinRouters: routers,
 		routers:        newRouters,
 	}
+	if url != nil {
+		chain.url = *url
+	}
 
 	return chain, nil
 }
 
 // sortRouter Sort router instance by priority with stable algorithm
-func sortRouter(routers []router.Router) {
+func sortRouter(routers []router.PriorityRouter) {
 	sort.Stable(byPriority(routers))
 }
 
 // byPriority Sort by priority
-type byPriority []router.Router
+type byPriority []router.PriorityRouter
 
 func (a byPriority) Len() int           { return len(a) }
 func (a byPriority) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
diff --git a/cluster/router/chain/chain_test.go b/cluster/router/chain/chain_test.go
index 0cb47c4a185fe19b5f70ea4db2b80aab2f1aada5..c1f723525f5307e7732f0ea1ecc27eca7ba09c8d 100644
--- a/cluster/router/chain/chain_test.go
+++ b/cluster/router/chain/chain_test.go
@@ -20,7 +20,6 @@ package chain
 import (
 	"encoding/base64"
 	"fmt"
-	"strconv"
 	"testing"
 	"time"
 )
@@ -42,10 +41,29 @@ import (
 	"github.com/apache/dubbo-go/remoting/zookeeper"
 )
 
+const (
+	localIP    = "127.0.0.1"
+	test1234IP = "1.2.3.4"
+	test1111IP = "1.1.1.1"
+	test0000IP = "0.0.0.0"
+	port20000  = 20000
+
+	path             = "/dubbo/config/dubbo/test-condition.condition-router"
+	zkFormat         = "zookeeper://%s:%d"
+	consumerFormat   = "consumer://%s/com.foo.BarService"
+	dubboForamt      = "dubbo://%s:%d/com.foo.BarService"
+	anyUrlFormat     = "condition://%s/com.foo.BarService"
+	zk               = "zookeeper"
+	applicationKey   = "test-condition"
+	applicationField = "application"
+	forceField       = "force"
+	forceValue       = "true"
+)
+
 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,19 +73,19 @@ 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))
-	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
+	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, localIP, ts.Servers[0].Port))
+	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	assert.Nil(t, err)
 	assert.NotNil(t, configuration)
 
-	chain, err := NewRouterChain(getRouteUrl("test-condition"))
+	chain, err := NewRouterChain(getRouteUrl(applicationKey))
 	assert.Nil(t, err)
 	assert.Equal(t, 1, len(chain.routers))
 	appRouter := chain.routers[0].(*condition.AppRouter)
@@ -92,10 +110,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,63 +123,63 @@ 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))
-	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
+	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, localIP, ts.Servers[0].Port))
+	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
-	chain, err := NewRouterChain(getConditionRouteUrl("test-condition"))
+	chain, err := NewRouterChain(getConditionRouteUrl(applicationKey))
 	assert.Nil(t, err)
 	assert.Equal(t, 2, len(chain.routers))
 
-	url := getConditionRouteUrl("test-condition")
+	url := getConditionRouteUrl(applicationKey)
 	assert.NotNil(t, url)
 	factory := extension.GetRouterFactory(url.Protocol)
-	r, err := factory.NewRouter(url)
+	r, err := factory.NewPriorityRouter(url)
 	assert.Nil(t, err)
 	assert.NotNil(t, r)
 
-	routers := make([]router.Router, 0)
+	routers := make([]router.PriorityRouter, 0)
 	routers = append(routers, r)
 	chain.AddRouters(routers)
 	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))
-	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
+	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, localIP, ts.Servers[0].Port))
+	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
-	chain, err := NewRouterChain(getConditionRouteUrl("test-condition"))
+	chain, err := NewRouterChain(getConditionRouteUrl(applicationKey))
 	assert.Nil(t, err)
 	assert.Equal(t, 1, len(chain.routers))
 
-	url := getConditionRouteUrl("test-condition")
+	url := getConditionRouteUrl(applicationKey)
 	assert.NotNil(t, url)
 
 	invokers := []protocol.Invoker{}
-	dubboURL, _ := common.NewURL(fmt.Sprintf("dubbo://1.2.3.4:20000/com.foo.BarService"))
+	dubboURL, _ := common.NewURL(fmt.Sprintf(dubboForamt, test1234IP, port20000))
 	invokers = append(invokers, protocol.NewBaseInvoker(dubboURL))
 
-	targetURL, _ := common.NewURL(fmt.Sprintf("consumer://1.1.1.1/com.foo.BarService"))
+	targetURL, _ := common.NewURL(fmt.Sprintf(consumerFormat, test1111IP))
 	inv := &invocation.RPCInvocation{}
 	finalInvokers := chain.Route(invokers, &targetURL, inv)
 
 	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,51 +189,51 @@ 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))
-	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
+	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, localIP, ts.Servers[0].Port))
+	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
-	chain, err := NewRouterChain(getConditionRouteUrl("test-condition"))
+	chain, err := NewRouterChain(getConditionRouteUrl(applicationKey))
 	assert.Nil(t, err)
 	assert.Equal(t, 2, len(chain.routers))
 
 	invokers := []protocol.Invoker{}
-	dubboURL, _ := common.NewURL(fmt.Sprintf("dubbo://1.2.3.4:20000/com.foo.BarService"))
+	dubboURL, _ := common.NewURL(fmt.Sprintf(dubboForamt, test1234IP, port20000))
 	invokers = append(invokers, protocol.NewBaseInvoker(dubboURL))
 
-	targetURL, _ := common.NewURL(fmt.Sprintf("consumer://1.1.1.1/com.foo.BarService"))
+	targetURL, _ := common.NewURL(fmt.Sprintf(consumerFormat, test1111IP))
 	inv := &invocation.RPCInvocation{}
 	finalInvokers := chain.Route(invokers, &targetURL, inv)
 
 	assert.Equal(t, 0, len(finalInvokers))
 }
 
-func TestRouterChain_Route_NoRoute(t *testing.T) {
+func TestRouterChainRouteNoRoute(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))
-	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
+	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, localIP, ts.Servers[0].Port))
+	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
-	chain, err := NewRouterChain(getConditionNoRouteUrl("test-condition"))
+	chain, err := NewRouterChain(getConditionNoRouteUrl(applicationKey))
 	assert.Nil(t, err)
 	assert.Equal(t, 1, len(chain.routers))
 
-	url := getConditionRouteUrl("test-condition")
+	url := getConditionRouteUrl(applicationKey)
 	assert.NotNil(t, url)
 
 	invokers := []protocol.Invoker{}
-	dubboURL, _ := common.NewURL(fmt.Sprintf("dubbo://1.2.3.4:20000/com.foo.BarService"))
+	dubboURL, _ := common.NewURL(fmt.Sprintf(dubboForamt, test1234IP, port20000))
 	invokers = append(invokers, protocol.NewBaseInvoker(dubboURL))
 
-	targetURL, _ := common.NewURL(fmt.Sprintf("consumer://1.1.1.1/com.foo.BarService"))
+	targetURL, _ := common.NewURL(fmt.Sprintf(consumerFormat, test1111IP))
 	inv := &invocation.RPCInvocation{}
 	finalInvokers := chain.Route(invokers, &targetURL, inv)
 
@@ -223,26 +241,26 @@ 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.AddParam("application", applicationKey)
-	url.AddParam("force", "true")
+	url, _ := common.NewURL(fmt.Sprintf(anyUrlFormat, test0000IP))
+	url.AddParam(applicationField, applicationKey)
+	url.AddParam(forceField, forceValue)
 	rule := base64.URLEncoding.EncodeToString([]byte("host = 1.1.1.1 => host != 1.2.3.4"))
 	url.AddParam(constant.RULE_KEY, rule)
 	return &url
 }
 
 func getConditionRouteUrl(applicationKey string) *common.URL {
-	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
-	url.AddParam("application", applicationKey)
-	url.AddParam("force", "true")
+	url, _ := common.NewURL(fmt.Sprintf(anyUrlFormat, test0000IP))
+	url.AddParam(applicationField, applicationKey)
+	url.AddParam(forceField, forceValue)
 	rule := base64.URLEncoding.EncodeToString([]byte("host = 1.1.1.1 => host = 1.2.3.4"))
 	url.AddParam(constant.RULE_KEY, rule)
 	return &url
 }
 
 func getRouteUrl(applicationKey string) *common.URL {
-	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
-	url.AddParam("application", applicationKey)
-	url.AddParam("force", "true")
+	url, _ := common.NewURL(fmt.Sprintf(anyUrlFormat, test0000IP))
+	url.AddParam(applicationField, applicationKey)
+	url.AddParam(forceField, forceValue)
 	return &url
 }
diff --git a/cluster/router/chan.go b/cluster/router/chan.go
new file mode 100644
index 0000000000000000000000000000000000000000..6904e1734a7cbdaa00afa1b30797d19ca502453c
--- /dev/null
+++ b/cluster/router/chan.go
@@ -0,0 +1,25 @@
+/*
+ * 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 router
+
+// Chain
+type Chain interface {
+	router
+	// AddRouters Add routers
+	AddRouters([]PriorityRouter)
+}
diff --git a/cluster/router/condition/app_router_test.go b/cluster/router/condition/app_router_test.go
index e99307625baf34fa6b744f168ff4e6cb8e042502..8b38f2dd6136b4d31f46e7214c0ad1359537b198 100644
--- a/cluster/router/condition/app_router_test.go
+++ b/cluster/router/condition/app_router_test.go
@@ -18,7 +18,7 @@
 package condition
 
 import (
-	"strconv"
+	"fmt"
 	"testing"
 	"time"
 )
@@ -31,12 +31,25 @@ import (
 import (
 	"github.com/apache/dubbo-go/common"
 	"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/config_center"
 	"github.com/apache/dubbo-go/remoting"
 	"github.com/apache/dubbo-go/remoting/zookeeper"
 )
 
+const (
+	routerPath    = "/dubbo/config/dubbo/test-condition.condition-router"
+	routerLocalIP = "127.0.0.1"
+	routerZk      = "zookeeper"
+	routerKey     = "test-condition"
+)
+
+var (
+	zkFormat        = "zookeeper://%s:%d"
+	conditionFormat = "condition://%s/com.foo.BarService"
+)
+
 func TestNewAppRouter(t *testing.T) {
 
 	testYML := `enabled: true
@@ -47,22 +60,22 @@ 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(routerPath)
 	assert.NoError(t, err)
 
-	_, err = z.Conn.Set("/dubbo/config/dubbo/test-condition.condition-router", []byte(testYML), 0)
+	_, err = z.Conn.Set(routerPath, []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))
-	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
+	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, routerLocalIP, ts.Servers[0].Port))
+	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	assert.Nil(t, err)
 	assert.NotNil(t, configuration)
 
-	appRouteURL := getAppRouteURL("test-condition")
+	appRouteURL := getAppRouteURL(routerKey)
 	appRouter, err := NewAppRouter(appRouteURL)
 	assert.Nil(t, err)
 	assert.NotNil(t, appRouter)
@@ -93,22 +106,22 @@ 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(routerPath)
 	assert.NoError(t, err)
 
-	_, err = z.Conn.Set("/dubbo/config/dubbo/test-condition.condition-router", []byte(testYML), 0)
+	_, err = z.Conn.Set(routerPath, []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))
-	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
+	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, routerLocalIP, ts.Servers[0].Port))
+	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	assert.Nil(t, err)
 	assert.NotNil(t, configuration)
 
-	appRouteURL := getAppRouteURL("test-condition")
+	appRouteURL := getAppRouteURL(routerKey)
 	appRouter, err := NewAppRouter(appRouteURL)
 	assert.Nil(t, err)
 	assert.NotNil(t, appRouter)
@@ -130,22 +143,22 @@ 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(routerPath)
 	assert.NoError(t, err)
 
-	_, err = z.Conn.Set("/dubbo/config/dubbo/test-condition.condition-router", []byte(testYML), 0)
+	_, err = z.Conn.Set(routerPath, []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))
-	configuration, err := extension.GetConfigCenterFactory("zookeeper").GetDynamicConfiguration(&zkUrl)
+	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, routerLocalIP, ts.Servers[0].Port))
+	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(&zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	assert.Nil(t, err)
 	assert.NotNil(t, configuration)
 
-	appRouteURL := getAppRouteURL("test-condition")
+	appRouteURL := getAppRouteURL(routerKey)
 	appRouter, err := NewAppRouter(appRouteURL)
 	assert.Nil(t, err)
 	assert.NotNil(t, appRouter)
@@ -171,7 +184,7 @@ conditions:
 }
 
 func getAppRouteURL(applicationKey string) *common.URL {
-	url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService")
+	url, _ := common.NewURL(fmt.Sprintf(conditionFormat, constant.ANYHOST_VALUE))
 	url.AddParam("application", applicationKey)
 	url.AddParam("force", "true")
 	return &url
diff --git a/cluster/router/condition/factory.go b/cluster/router/condition/factory.go
index 66512a138706e9b9ab565f7537a15c37a75deefd..f8d3e130102d4311f8b1ddb1055aece8a0633296 100644
--- a/cluster/router/condition/factory.go
+++ b/cluster/router/condition/factory.go
@@ -32,28 +32,28 @@ func init() {
 // ConditionRouterFactory Condition router factory
 type ConditionRouterFactory struct{}
 
-func newConditionRouterFactory() router.RouterFactory {
+func newConditionRouterFactory() router.PriorityRouterFactory {
 	return &ConditionRouterFactory{}
 }
 
-// NewRouter Create ConditionRouterFactory by URL
-func (c *ConditionRouterFactory) NewRouter(url *common.URL) (router.Router, error) {
+// NewPriorityRouter creates ConditionRouterFactory by URL
+func (c *ConditionRouterFactory) NewPriorityRouter(url *common.URL) (router.PriorityRouter, error) {
 	return NewConditionRouter(url)
 }
 
 // NewRouter Create FileRouterFactory by Content
-func (c *ConditionRouterFactory) NewFileRouter(content []byte) (router.Router, error) {
+func (c *ConditionRouterFactory) NewFileRouter(content []byte) (router.PriorityRouter, error) {
 	return NewFileConditionRouter(content)
 }
 
 // AppRouterFactory Application router factory
 type AppRouterFactory struct{}
 
-func newAppRouterFactory() router.RouterFactory {
+func newAppRouterFactory() router.PriorityRouterFactory {
 	return &AppRouterFactory{}
 }
 
-// NewRouter Create AppRouterFactory by URL
-func (c *AppRouterFactory) NewRouter(url *common.URL) (router.Router, error) {
+// NewPriorityRouter creates AppRouterFactory by URL
+func (c *AppRouterFactory) NewPriorityRouter(url *common.URL) (router.PriorityRouter, error) {
 	return NewAppRouter(url)
 }
diff --git a/cluster/router/condition/factory_test.go b/cluster/router/condition/factory_test.go
index 99cec34096a55d3c2a967b63afdf5f6d0a77279a..0f61b39fc71af3aaeffc731974a0fa997503693e 100644
--- a/cluster/router/condition/factory_test.go
+++ b/cluster/router/condition/factory_test.go
@@ -33,11 +33,22 @@ import (
 
 import (
 	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/protocol"
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
+const (
+	factory1111Ip               = "1.1.1.1"
+	factoryUrlFormat            = "condition://%s/com.foo.BarService"
+	factoryDubboFormat          = "dubbo://%s:20880/com.foo.BarService"
+	factoryConsumerMethodFormat = "consumer://%s/com.foo.BarService?methods=getFoo"
+	factory333URL               = "dubbo://10.20.3.3:20880/com.foo.BarService"
+	factoryConsumerFormat       = "consumer://%s/com.foo.BarService"
+	factoryHostIp1234Format     = "host = %s =>  host = 1.2.3.4"
+)
+
 type MockInvoker struct {
 	url          common.URL
 	available    bool
@@ -59,21 +70,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(fmt.Sprintf(factoryUrlFormat, constant.ANYHOST_VALUE))
 	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(fmt.Sprintf(factoryUrlFormat, constant.ANYHOST_VALUE))
 	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(fmt.Sprintf(factoryUrlFormat, constant.ANYHOST_VALUE))
 	url.AddParam("rule", rule)
 	return &url
 }
@@ -119,32 +130,32 @@ func (bi *MockInvoker) Destroy() {
 func TestRoute_matchWhen(t *testing.T) {
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("=> host = 1.2.3.4"))
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule))
-	cUrl, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService")
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
+	cUrl, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, factory1111Ip))
 	matchWhen := router.(*ConditionRouter).MatchWhen(&cUrl, inv)
 	assert.Equal(t, true, matchWhen)
 	rule1 := base64.URLEncoding.EncodeToString([]byte("host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"))
-	router1, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule1))
+	router1, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule1))
 	matchWhen1 := router1.(*ConditionRouter).MatchWhen(&cUrl, inv)
 	assert.Equal(t, true, matchWhen1)
 	rule2 := base64.URLEncoding.EncodeToString([]byte("host = 2.2.2.2,1.1.1.1,3.3.3.3 & host !=1.1.1.1 => host = 1.2.3.4"))
-	router2, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule2))
+	router2, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule2))
 	matchWhen2 := router2.(*ConditionRouter).MatchWhen(&cUrl, inv)
 	assert.Equal(t, false, matchWhen2)
 	rule3 := base64.URLEncoding.EncodeToString([]byte("host !=4.4.4.4 & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"))
-	router3, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule3))
+	router3, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule3))
 	matchWhen3 := router3.(*ConditionRouter).MatchWhen(&cUrl, inv)
 	assert.Equal(t, true, matchWhen3)
 	rule4 := 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"))
-	router4, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule4))
+	router4, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule4))
 	matchWhen4 := router4.(*ConditionRouter).MatchWhen(&cUrl, inv)
 	assert.Equal(t, true, matchWhen4)
 	rule5 := base64.URLEncoding.EncodeToString([]byte("host = 2.2.2.2,1.1.1.*,3.3.3.3 & host != 1.1.1.1 => host = 1.2.3.4"))
-	router5, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule5))
+	router5, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule5))
 	matchWhen5 := router5.(*ConditionRouter).MatchWhen(&cUrl, inv)
 	assert.Equal(t, false, matchWhen5)
 	rule6 := base64.URLEncoding.EncodeToString([]byte("host = 2.2.2.2,1.1.1.*,3.3.3.3 & host != 1.1.1.2 => host = 1.2.3.4"))
-	router6, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule6))
+	router6, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule6))
 	matchWhen6 := router6.(*ConditionRouter).MatchWhen(&cUrl, inv)
 	assert.Equal(t, true, matchWhen6)
 }
@@ -153,8 +164,8 @@ func TestRoute_matchFilter(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")
-	url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
-	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
+	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	invokers := []protocol.Invoker{NewMockInvoker(url1, 1), NewMockInvoker(url2, 2), NewMockInvoker(url3, 3)}
 	rule1 := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 10.20.3.3"))
 	rule2 := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 10.20.3.* & host != 10.20.3.3"))
@@ -162,13 +173,13 @@ func TestRoute_matchFilter(t *testing.T) {
 	rule4 := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 10.20.3.2,10.20.3.3,10.20.3.4"))
 	rule5 := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host != 10.20.3.3"))
 	rule6 := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " serialization = fastjson"))
-	router1, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule1))
-	router2, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule2))
-	router3, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule3))
-	router4, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule4))
-	router5, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule5))
-	router6, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule6))
-	cUrl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
+	router1, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule1))
+	router2, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule2))
+	router3, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule3))
+	router4, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule4))
+	router5, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule5))
+	router6, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule6))
+	cUrl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
 	fileredInvokers1 := router1.Route(invokers, &cUrl, &invocation.RPCInvocation{})
 	fileredInvokers2 := router2.Route(invokers, &cUrl, &invocation.RPCInvocation{})
 	fileredInvokers3 := router3.Route(invokers, &cUrl, &invocation.RPCInvocation{})
@@ -187,21 +198,21 @@ func TestRoute_matchFilter(t *testing.T) {
 func TestRoute_methodRoute(t *testing.T) {
 	inv := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("getFoo"), invocation.WithParameterTypes([]reflect.Type{}), invocation.WithArguments([]interface{}{}))
 	rule := base64.URLEncoding.EncodeToString([]byte("host !=4.4.4.* & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"))
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule))
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
 	url, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo")
 	matchWhen := router.(*ConditionRouter).MatchWhen(&url, inv)
 	assert.Equal(t, true, matchWhen)
-	url1, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=getFoo")
+	url1, _ := common.NewURL(fmt.Sprintf(factoryConsumerMethodFormat, factory1111Ip))
 	matchWhen = router.(*ConditionRouter).MatchWhen(&url1, inv)
 	assert.Equal(t, true, matchWhen)
-	url2, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=getFoo")
+	url2, _ := common.NewURL(fmt.Sprintf(factoryConsumerMethodFormat, factory1111Ip))
 	rule2 := base64.URLEncoding.EncodeToString([]byte("methods=getFoo & host!=1.1.1.1 => host = 1.2.3.4"))
-	router2, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule2))
+	router2, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule2))
 	matchWhen = router2.(*ConditionRouter).MatchWhen(&url2, inv)
 	assert.Equal(t, false, matchWhen)
-	url3, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=getFoo")
+	url3, _ := common.NewURL(fmt.Sprintf(factoryConsumerMethodFormat, factory1111Ip))
 	rule3 := base64.URLEncoding.EncodeToString([]byte("methods=getFoo & host=1.1.1.1 => host = 1.2.3.4"))
-	router3, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule3))
+	router3, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule3))
 	matchWhen = router3.(*ConditionRouter).MatchWhen(&url3, inv)
 	assert.Equal(t, true, matchWhen)
 
@@ -213,8 +224,8 @@ func TestRoute_ReturnFalse(t *testing.T) {
 	invokers := []protocol.Invoker{NewMockInvoker(url, 1), NewMockInvoker(url, 2), NewMockInvoker(url, 3)}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => false"))
-	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule))
+	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
 	assert.Equal(t, 0, len(fileredInvokers))
 }
@@ -225,8 +236,8 @@ func TestRoute_ReturnEmpty(t *testing.T) {
 	invokers := []protocol.Invoker{NewMockInvoker(url, 1), NewMockInvoker(url, 2), NewMockInvoker(url, 3)}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => "))
-	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule))
+	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
 	assert.Equal(t, 0, len(fileredInvokers))
 }
@@ -241,25 +252,25 @@ func TestRoute_ReturnAll(t *testing.T) {
 	invokers := []protocol.Invoker{mockInvoker1, mockInvoker2, mockInvoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = " + localIP))
-	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule))
+	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
 	assert.Equal(t, invokers, fileredInvokers)
 }
 
 func TestRoute_HostFilter(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))
-	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL(factory333URL)
+	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
+	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = " + localIP))
-	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule))
+	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
 	assert.Equal(t, 2, len(fileredInvokers))
 	assert.Equal(t, invoker2, fileredInvokers[0])
@@ -268,17 +279,17 @@ func TestRoute_HostFilter(t *testing.T) {
 
 func TestRoute_Empty_HostFilter(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))
-	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL(factory333URL)
+	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
+	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte(" => " + " host = " + localIP))
-	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule))
+	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
 	assert.Equal(t, 2, len(fileredInvokers))
 	assert.Equal(t, invoker2, fileredInvokers[0])
@@ -287,17 +298,17 @@ func TestRoute_Empty_HostFilter(t *testing.T) {
 
 func TestRoute_False_HostFilter(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))
-	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL(factory333URL)
+	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
+	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("true => " + " host = " + localIP))
-	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule))
+	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
 	assert.Equal(t, 2, len(fileredInvokers))
 	assert.Equal(t, invoker2, fileredInvokers[0])
@@ -306,17 +317,17 @@ func TestRoute_False_HostFilter(t *testing.T) {
 
 func TestRoute_Placeholder(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))
-	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL(factory333URL)
+	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
+	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = $host"))
-	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrl(rule))
+	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
 	assert.Equal(t, 2, len(fileredInvokers))
 	assert.Equal(t, invoker2, fileredInvokers[0])
@@ -325,34 +336,34 @@ func TestRoute_Placeholder(t *testing.T) {
 
 func TestRoute_NoForce(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))
-	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL(factory333URL)
+	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
+	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
-	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 1.2.3.4"))
-	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrlWithNoForce(rule))
+	rule := base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf(factoryHostIp1234Format, localIP)))
+	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrlWithNoForce(rule))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
 	assert.Equal(t, invokers, fileredInvokers)
 }
 
 func TestRoute_Force(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))
-	url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP))
+	url1, _ := common.NewURL(factory333URL)
+	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
+	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	invoker1 := NewMockInvoker(url1, 1)
 	invoker2 := NewMockInvoker(url2, 2)
 	invoker3 := NewMockInvoker(url3, 3)
 	invokers := []protocol.Invoker{invoker1, invoker2, invoker3}
 	inv := &invocation.RPCInvocation{}
-	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 1.2.3.4"))
-	curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService")
-	router, _ := newConditionRouterFactory().NewRouter(getRouteUrlWithForce(rule, "true"))
+	rule := base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf(factoryHostIp1234Format, localIP)))
+	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
+	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrlWithForce(rule, "true"))
 	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
 	assert.Equal(t, 0, len(fileredInvokers))
 }
diff --git a/cluster/router/condition/file.go b/cluster/router/condition/file.go
index b2c876690043d18a1a9e746fee13f06c77a0de03..eabdf1c263446140b359b3e791238b020cecb50c 100644
--- a/cluster/router/condition/file.go
+++ b/cluster/router/condition/file.go
@@ -77,10 +77,7 @@ func (f *FileConditionRouter) URL() common.URL {
 }
 
 func parseCondition(conditions []string) string {
-	var (
-		when string
-		then string
-	)
+	var when, then string
 	for _, condition := range conditions {
 		condition = strings.Trim(condition, " ")
 		if strings.Contains(condition, "=>") {
@@ -101,10 +98,7 @@ func parseCondition(conditions []string) string {
 					then = provider
 				}
 			}
-
 		}
-
 	}
-
 	return strings.Join([]string{when, then}, " => ")
 }
diff --git a/cluster/router/condition/router.go b/cluster/router/condition/router.go
index 0267a3c7a462acb43f84ccb4701247147699804a..40a251573f5e73d40032972313565d98b288b1b1 100644
--- a/cluster/router/condition/router.go
+++ b/cluster/router/condition/router.go
@@ -181,9 +181,7 @@ func parseRule(rule string) (map[string]MatchPair, error) {
 		return condition, nil
 	}
 
-	var (
-		pair MatchPair
-	)
+	var pair MatchPair
 	values := gxset.NewSet()
 	matches := routerPatternReg.FindAllSubmatch([]byte(rule), -1)
 	for _, groups := range matches {
diff --git a/cluster/router/healthcheck/default_health_check_test.go b/cluster/router/healthcheck/default_health_check_test.go
index 74aa3940743a012f907cfe3d8811a618f07ff800..5d35ae8e486e3f7b29b2a68a3864ef806a1053c7 100644
--- a/cluster/router/healthcheck/default_health_check_test.go
+++ b/cluster/router/healthcheck/default_health_check_test.go
@@ -18,6 +18,7 @@
 package healthcheck
 
 import (
+	"fmt"
 	"math"
 	"testing"
 )
@@ -32,12 +33,18 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-func TestDefaultHealthChecker_IsHealthy(t *testing.T) {
+const (
+	healthCheckDubbo1010IP    = "192.168.10.10"
+	healthCheckDubbo1011IP    = "192.168.10.11"
+	healthCheckMethodTest     = "test"
+	healthCheckDubboUrlFormat = "dubbo://%s:20000/com.ikurento.user.UserProvider"
+)
 
+func TestDefaultHealthCheckerIsHealthy(t *testing.T) {
 	defer protocol.CleanAllStatus()
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
 	hc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
-	invoker := NewMockInvoker(url, 1)
+	invoker := NewMockInvoker(url)
 	healthy := hc.IsHealthy(invoker)
 	assert.True(t, healthy)
 
@@ -45,7 +52,7 @@ func TestDefaultHealthChecker_IsHealthy(t *testing.T) {
 	url.SetParam(constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, "100")
 	// fake the outgoing request
 	for i := 0; i < 11; i++ {
-		request(url, "test", 0, true, false)
+		request(url, healthCheckMethodTest, 0, true, false)
 	}
 	hc = NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
 	healthy = hc.IsHealthy(invoker)
@@ -54,7 +61,7 @@ func TestDefaultHealthChecker_IsHealthy(t *testing.T) {
 
 	// successive failed count is more than constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, go to unhealthy
 	for i := 0; i < 11; i++ {
-		request(url, "test", 0, false, false)
+		request(url, healthCheckMethodTest, 0, false, false)
 	}
 	url.SetParam(constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, "10")
 	url.SetParam(constant.OUTSTANDING_REQUEST_COUNT_LIMIT_KEY, "1000")
@@ -63,18 +70,18 @@ func TestDefaultHealthChecker_IsHealthy(t *testing.T) {
 	assert.False(t, hc.IsHealthy(invoker))
 
 	// reset successive failed count and go to healthy
-	request(url, "test", 0, false, true)
+	request(url, healthCheckMethodTest, 0, false, true)
 	healthy = hc.IsHealthy(invoker)
 	assert.True(t, hc.IsHealthy(invoker))
 }
 
-func TestDefaultHealthChecker_getCircuitBreakerSleepWindowTime(t *testing.T) {
+func TestDefaultHealthCheckerGetCircuitBreakerSleepWindowTime(t *testing.T) {
 	defer protocol.CleanAllStatus()
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
 	defaultHc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
 	// Increase the number of failed requests
 	for i := 0; i < 100; i++ {
-		request(url, "test", 1, false, false)
+		request(url, healthCheckMethodTest, 1, false, false)
 	}
 	sleepWindowTime := defaultHc.getCircuitBreakerSleepWindowTime(protocol.GetURLStatus(url))
 	assert.True(t, sleepWindowTime == constant.MAX_CIRCUIT_TRIPPED_TIMEOUT_IN_MS)
@@ -84,48 +91,48 @@ func TestDefaultHealthChecker_getCircuitBreakerSleepWindowTime(t *testing.T) {
 	sleepWindowTime = NewDefaultHealthChecker(&url).(*DefaultHealthChecker).getCircuitBreakerSleepWindowTime(protocol.GetURLStatus(url))
 	assert.True(t, sleepWindowTime == 0)
 
-	url1, _ := common.NewURL("dubbo://192.168.10.11:20000/com.ikurento.user.UserProvider")
+	url1, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1011IP))
 	sleepWindowTime = defaultHc.getCircuitBreakerSleepWindowTime(protocol.GetURLStatus(url1))
 	assert.True(t, sleepWindowTime == 0)
-	request(url1, "test", 1, false, false)
-	request(url1, "test", 1, false, false)
-	request(url1, "test", 1, false, false)
-	request(url1, "test", 1, false, false)
-	request(url1, "test", 1, false, false)
-	request(url1, "test", 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
 	sleepWindowTime = defaultHc.getCircuitBreakerSleepWindowTime(protocol.GetURLStatus(url1))
 	assert.True(t, sleepWindowTime > 0 && sleepWindowTime < constant.MAX_CIRCUIT_TRIPPED_TIMEOUT_IN_MS)
 }
 
-func TestDefaultHealthChecker_getCircuitBreakerTimeout(t *testing.T) {
+func TestDefaultHealthCheckerGetCircuitBreakerTimeout(t *testing.T) {
 	defer protocol.CleanAllStatus()
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
 	defaultHc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
 	timeout := defaultHc.getCircuitBreakerTimeout(protocol.GetURLStatus(url))
 	assert.True(t, timeout == 0)
-	url1, _ := common.NewURL("dubbo://192.168.10.11:20000/com.ikurento.user.UserProvider")
-	request(url1, "test", 1, false, false)
-	request(url1, "test", 1, false, false)
-	request(url1, "test", 1, false, false)
-	request(url1, "test", 1, false, false)
-	request(url1, "test", 1, false, false)
-	request(url1, "test", 1, false, false)
+	url1, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1011IP))
+	request(url1, healthCheckMethodTest, 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
+	request(url1, healthCheckMethodTest, 1, false, false)
 	timeout = defaultHc.getCircuitBreakerTimeout(protocol.GetURLStatus(url1))
 	// timeout must after the current time
 	assert.True(t, timeout > protocol.CurrentTimeMillis())
 
 }
 
-func TestDefaultHealthChecker_isCircuitBreakerTripped(t *testing.T) {
+func TestDefaultHealthCheckerIsCircuitBreakerTripped(t *testing.T) {
 	defer protocol.CleanAllStatus()
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
 	defaultHc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
 	status := protocol.GetURLStatus(url)
 	tripped := defaultHc.isCircuitBreakerTripped(status)
 	assert.False(t, tripped)
 	// Increase the number of failed requests
 	for i := 0; i < 100; i++ {
-		request(url, "test", 1, false, false)
+		request(url, healthCheckMethodTest, 1, false, false)
 	}
 	tripped = defaultHc.isCircuitBreakerTripped(protocol.GetURLStatus(url))
 	assert.True(t, tripped)
@@ -134,13 +141,13 @@ func TestDefaultHealthChecker_isCircuitBreakerTripped(t *testing.T) {
 
 func TestNewDefaultHealthChecker(t *testing.T) {
 	defer protocol.CleanAllStatus()
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
 	defaultHc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
 	assert.NotNil(t, defaultHc)
 	assert.Equal(t, defaultHc.outStandingRequestConutLimit, int32(math.MaxInt32))
 	assert.Equal(t, defaultHc.requestSuccessiveFailureThreshold, int32(constant.DEFAULT_SUCCESSIVE_FAILED_REQUEST_MAX_DIFF))
 
-	url1, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url1, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
 	url1.SetParam(constant.OUTSTANDING_REQUEST_COUNT_LIMIT_KEY, "10")
 	url1.SetParam(constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, "10")
 	nondefaultHc := NewDefaultHealthChecker(&url1).(*DefaultHealthChecker)
diff --git a/cluster/router/healthcheck/factory.go b/cluster/router/healthcheck/factory.go
index 32d84d145ceb2aa05f5a75de352e52d13dd9d6b3..40c9dd7ab9e431a16833507ee4093ff7fbff8c95 100644
--- a/cluster/router/healthcheck/factory.go
+++ b/cluster/router/healthcheck/factory.go
@@ -33,11 +33,11 @@ type HealthCheckRouteFactory struct {
 }
 
 // newHealthCheckRouteFactory construct a new HealthCheckRouteFactory
-func newHealthCheckRouteFactory() router.RouterFactory {
+func newHealthCheckRouteFactory() router.PriorityRouterFactory {
 	return &HealthCheckRouteFactory{}
 }
 
-// NewRouter construct a new NewHealthCheckRouter via url
-func (f *HealthCheckRouteFactory) NewRouter(url *common.URL) (router.Router, error) {
+// NewPriorityRouter construct a new NewHealthCheckRouter via url
+func (f *HealthCheckRouteFactory) NewPriorityRouter(url *common.URL) (router.PriorityRouter, error) {
 	return NewHealthCheckRouter(url)
 }
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.go b/cluster/router/healthcheck/health_check_route.go
index 1ddc9ccb173881a87bc5351711326f02ab2da3f6..ee42e47e3b26c9a1976b4599d3464d752b615e0a 100644
--- a/cluster/router/healthcheck/health_check_route.go
+++ b/cluster/router/healthcheck/health_check_route.go
@@ -38,7 +38,7 @@ type HealthCheckRouter struct {
 }
 
 // NewHealthCheckRouter construct an HealthCheckRouter via url
-func NewHealthCheckRouter(url *common.URL) (router.Router, error) {
+func NewHealthCheckRouter(url *common.URL) (router.PriorityRouter, error) {
 	r := &HealthCheckRouter{
 		url:     url,
 		enabled: url.GetParamBool(HEALTH_ROUTE_ENABLED_KEY, false),
diff --git a/cluster/router/healthcheck/health_check_route_test.go b/cluster/router/healthcheck/health_check_route_test.go
index 759ef93dbeb8d91a82eefd59060afbe8a10a4440..d5862fb884114bac0ea2ec9ee8926baac57d5ba6 100644
--- a/cluster/router/healthcheck/health_check_route_test.go
+++ b/cluster/router/healthcheck/health_check_route_test.go
@@ -18,6 +18,7 @@
 package healthcheck
 
 import (
+	"fmt"
 	"math"
 	"testing"
 	"time"
@@ -34,35 +35,44 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-func TestHealthCheckRouter_Route(t *testing.T) {
+const (
+	healthCheckRoute1010IP         = "192.168.10.10"
+	healthCheckRoute1011IP         = "192.168.10.11"
+	healthCheckRoute1012IP         = "192.168.10.12"
+	healthCheckRouteMethodNameTest = "test"
+	healthCheck1001URL             = "dubbo://192.168.10.1/com.ikurento.user.UserProvider"
+	healthCheckRouteUrlFormat      = "dubbo://%s:20000/com.ikurento.user.UserProvider"
+)
+
+func TestHealthCheckRouterRoute(t *testing.T) {
 	defer protocol.CleanAllStatus()
-	consumerURL, _ := common.NewURL("dubbo://192.168.10.1/com.ikurento.user.UserProvider")
+	consumerURL, _ := common.NewURL(healthCheck1001URL)
 	consumerURL.SetParam(HEALTH_ROUTE_ENABLED_KEY, "true")
-	url1, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
-	url2, _ := common.NewURL("dubbo://192.168.10.11:20000/com.ikurento.user.UserProvider")
-	url3, _ := common.NewURL("dubbo://192.168.10.12:20000/com.ikurento.user.UserProvider")
+	url1, _ := common.NewURL(fmt.Sprintf(healthCheckRouteUrlFormat, healthCheckRoute1010IP))
+	url2, _ := common.NewURL(fmt.Sprintf(healthCheckRouteUrlFormat, healthCheckRoute1011IP))
+	url3, _ := common.NewURL(fmt.Sprintf(healthCheckRouteUrlFormat, healthCheckRoute1012IP))
 	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)
+	inv := invocation.NewRPCInvocation(healthCheckRouteMethodNameTest, nil, nil)
 	res := hcr.Route(invokers, &consumerURL, inv)
 	// now all invokers are healthy
 	assert.True(t, len(res) == len(invokers))
 
 	for i := 0; i < 10; i++ {
-		request(url1, "test", 0, false, false)
+		request(url1, healthCheckRouteMethodNameTest, 0, false, false)
 	}
 	res = hcr.Route(invokers, &consumerURL, inv)
 	// invokers1  is unhealthy now
 	assert.True(t, len(res) == 2 && !contains(res, invoker1))
 
 	for i := 0; i < 10; i++ {
-		request(url1, "test", 0, false, false)
-		request(url2, "test", 0, false, false)
+		request(url1, healthCheckRouteMethodNameTest, 0, false, false)
+		request(url2, healthCheckRouteMethodNameTest, 0, false, false)
 	}
 
 	res = hcr.Route(invokers, &consumerURL, inv)
@@ -70,9 +80,9 @@ func TestHealthCheckRouter_Route(t *testing.T) {
 	assert.True(t, len(res) == 1 && !contains(res, invoker1) && !contains(res, invoker2))
 
 	for i := 0; i < 10; i++ {
-		request(url1, "test", 0, false, false)
-		request(url2, "test", 0, false, false)
-		request(url3, "test", 0, false, false)
+		request(url1, healthCheckRouteMethodNameTest, 0, false, false)
+		request(url2, healthCheckRouteMethodNameTest, 0, false, false)
+		request(url3, healthCheckRouteMethodNameTest, 0, false, false)
 	}
 
 	res = hcr.Route(invokers, &consumerURL, inv)
@@ -80,12 +90,12 @@ func TestHealthCheckRouter_Route(t *testing.T) {
 	assert.True(t, len(res) == 3)
 
 	// reset the invoker1 successive failed count, so invoker1 go to healthy
-	request(url1, "test", 0, false, true)
+	request(url1, healthCheckRouteMethodNameTest, 0, false, true)
 	res = hcr.Route(invokers, &consumerURL, inv)
 	assert.True(t, contains(res, invoker1))
 
 	for i := 0; i < 6; i++ {
-		request(url1, "test", 0, false, false)
+		request(url1, healthCheckRouteMethodNameTest, 0, false, false)
 	}
 	// now all invokers are unhealthy, so downgraded to all again
 	res = hcr.Route(invokers, &consumerURL, inv)
@@ -108,7 +118,7 @@ func contains(invokers []protocol.Invoker, invoker protocol.Invoker) bool {
 
 func TestNewHealthCheckRouter(t *testing.T) {
 	defer protocol.CleanAllStatus()
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
 	hcr, _ := NewHealthCheckRouter(&url)
 	h := hcr.(*HealthCheckRouter)
 	assert.Nil(t, h.checker)
diff --git a/cluster/router/router.go b/cluster/router/router.go
index 9ee1154437e6fd205f08098deabb1ca260c3c040..1d1f79d277860abf34bebb9deab8a0f0a67c7b5d 100644
--- a/cluster/router/router.go
+++ b/cluster/router/router.go
@@ -23,34 +23,30 @@ import (
 )
 
 // Extension - Router
-
-// RouterFactory Router create factory
-type RouterFactory interface {
-	// NewRouter Create router instance with URL
-	NewRouter(*common.URL) (Router, error)
+// PriorityRouterFactory creates creates priority router with url
+type PriorityRouterFactory interface {
+	// NewPriorityRouter creates router instance with URL
+	NewPriorityRouter(*common.URL) (PriorityRouter, error)
 }
 
-// RouterFactory Router create factory use for parse config file
-type FileRouterFactory interface {
+// FilePriorityRouterFactory creates priority router with parse config file
+type FilePriorityRouterFactory interface {
 	// NewFileRouters Create file router with config file
-	NewFileRouter([]byte) (Router, error)
+	NewFileRouter([]byte) (PriorityRouter, error)
 }
 
 // Router
-type Router interface {
+type router interface {
 	// Route Determine the target invokers list.
 	Route([]protocol.Invoker, *common.URL, protocol.Invocation) []protocol.Invoker
-	// Priority Return Priority in router
-	// 0 to ^int(0) is better
-	Priority() int64
 	// URL Return URL in router
 	URL() common.URL
 }
 
-// Chain
-type Chain interface {
-	// Route Determine the target invokers list with chain.
-	Route([]protocol.Invoker, *common.URL, protocol.Invocation) []protocol.Invoker
-	// AddRouters Add routers
-	AddRouters([]Router)
+// Router
+type PriorityRouter interface {
+	router
+	// Priority Return Priority in router
+	// 0 to ^int(0) is better
+	Priority() int64
 }
diff --git a/cluster/router/tag/factory.go b/cluster/router/tag/factory.go
index d74924c89862ae4f4cd85b59c7008880298c0c99..a5d989cd31453f6d02eee9c5902dc3666defe4fe 100644
--- a/cluster/router/tag/factory.go
+++ b/cluster/router/tag/factory.go
@@ -31,17 +31,17 @@ func init() {
 type tagRouterFactory struct{}
 
 // NewTagRouterFactory create a tagRouterFactory
-func NewTagRouterFactory() router.RouterFactory {
+func NewTagRouterFactory() router.PriorityRouterFactory {
 	return &tagRouterFactory{}
 }
 
-// NewRouter create a tagRouter by tagRouterFactory with a url
+// NewPriorityRouter create a tagRouter by tagRouterFactory with a url
 // The url contains router configuration information
-func (c *tagRouterFactory) NewRouter(url *common.URL) (router.Router, error) {
+func (c *tagRouterFactory) NewPriorityRouter(url *common.URL) (router.PriorityRouter, error) {
 	return NewTagRouter(url)
 }
 
 // NewFileRouter create a tagRouter by profile content
-func (c *tagRouterFactory) NewFileRouter(content []byte) (router.Router, error) {
+func (c *tagRouterFactory) NewFileRouter(content []byte) (router.PriorityRouter, error) {
 	return NewFileTagRouter(content)
 }
diff --git a/cluster/router/tag/factory_test.go b/cluster/router/tag/factory_test.go
index 58bff5b18113d69f97ec513e393aa6759a3cf050..ee195820c123e1fc67a2c27cd12aaa544650b615 100644
--- a/cluster/router/tag/factory_test.go
+++ b/cluster/router/tag/factory_test.go
@@ -18,6 +18,7 @@
 package tag
 
 import (
+	"fmt"
 	"testing"
 )
 
@@ -29,11 +30,16 @@ import (
 	"github.com/apache/dubbo-go/common"
 )
 
-func TestTagRouterFactory_NewRouter(t *testing.T) {
-	u1, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true")
+const (
+	factoryLocalIP = "127.0.0.1"
+	factoryFormat  = "dubbo://%s:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true"
+)
+
+func TestTagRouterFactoryNewRouter(t *testing.T) {
+	u1, err := common.NewURL(fmt.Sprintf(factoryFormat, factoryLocalIP))
 	assert.Nil(t, err)
 	factory := NewTagRouterFactory()
-	tagRouter, e := factory.NewRouter(&u1)
+	tagRouter, e := factory.NewPriorityRouter(&u1)
 	assert.Nil(t, e)
 	assert.NotNil(t, tagRouter)
 }
diff --git a/cluster/router/tag/file_test.go b/cluster/router/tag/file_test.go
index 94fcf9e0e0fabed2445417d14b711f91b65b9e5e..513ba0c0b6c622d6a52fad35a24824121eb71b76 100644
--- a/cluster/router/tag/file_test.go
+++ b/cluster/router/tag/file_test.go
@@ -29,18 +29,21 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
+const (
+	fileTestTag = `priority: 100
+force: true`
+)
+
 func TestNewFileTagRouter(t *testing.T) {
-	router, e := NewFileTagRouter([]byte(`priority: 100
-force: true`))
+	router, e := NewFileTagRouter([]byte(fileTestTag))
 	assert.Nil(t, e)
 	assert.NotNil(t, router)
 	assert.Equal(t, 100, router.routerRule.Priority)
 	assert.Equal(t, true, router.routerRule.Force)
 }
 
-func TestFileTagRouter_URL(t *testing.T) {
-	router, e := NewFileTagRouter([]byte(`priority: 100
-force: true`))
+func TestFileTagRouterURL(t *testing.T) {
+	router, e := NewFileTagRouter([]byte(fileTestTag))
 	assert.Nil(t, e)
 	assert.NotNil(t, router)
 	url := router.URL()
@@ -52,9 +55,8 @@ force: true`))
 
 }
 
-func TestFileTagRouter_Priority(t *testing.T) {
-	router, e := NewFileTagRouter([]byte(`priority: 100
-force: true`))
+func TestFileTagRouterPriority(t *testing.T) {
+	router, e := NewFileTagRouter([]byte(fileTestTag))
 	assert.Nil(t, e)
 	assert.NotNil(t, router)
 	priority := router.Priority()
diff --git a/cluster/router/tag/tag_router_test.go b/cluster/router/tag/tag_router_test.go
index 280b56c8ccb69eb5d32dae2369bdc862adb8e6fd..000b3ec6724d85590c86456a009d5194c4e71e03 100644
--- a/cluster/router/tag/tag_router_test.go
+++ b/cluster/router/tag/tag_router_test.go
@@ -32,6 +32,21 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
+const (
+	tagRouterTestHangZhouUrl     = "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=hangzhou"
+	tagRouterTestShangHaiUrl     = "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=shanghai"
+	tagRouterTestBeijingUrl      = "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=beijing"
+	tagRouterTestUserConsumer    = "dubbo://127.0.0.1:20000/com.ikurento.user.UserConsumer?interface=com.ikurento.user.UserConsumer&group=&version=2.6.0&enabled=true"
+	tagRouterTestUserConsumerTag = "dubbo://127.0.0.1:20000/com.ikurento.user.UserConsumer?interface=com.ikurento.user.UserConsumer&group=&version=2.6.0&enabled=true&dubbo.force.tag=true"
+
+	tagRouterTestDubboTag      = "dubbo.tag"
+	tagRouterTestDubboForceTag = "dubbo.force.tag"
+	tagRouterTestHangZhou      = "hangzhou"
+	tagRouterTestGuangZhou     = "guangzhou"
+	tagRouterTestFalse         = "false"
+	tagRouterTestTrue          = "true"
+)
+
 // MockInvoker is only mock the Invoker to support test tagRouter
 type MockInvoker struct {
 	url          common.URL
@@ -73,8 +88,8 @@ func (bi *MockInvoker) Destroy() {
 	bi.available = false
 }
 
-func TestTagRouter_Priority(t *testing.T) {
-	u1, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserConsumer?interface=com.ikurento.user.UserConsumer&group=&version=2.6.0&enabled=true&dubbo.force.tag=true")
+func TestTagRouterPriority(t *testing.T) {
+	u1, err := common.NewURL(tagRouterTestUserConsumerTag)
 	assert.Nil(t, err)
 	tagRouter, e := NewTagRouter(&u1)
 	assert.Nil(t, e)
@@ -82,15 +97,15 @@ func TestTagRouter_Priority(t *testing.T) {
 	assert.Equal(t, int64(0), p)
 }
 
-func TestTagRouter_Route_force(t *testing.T) {
-	u1, e1 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserConsumer?interface=com.ikurento.user.UserConsumer&group=&version=2.6.0&enabled=true&dubbo.force.tag=true")
+func TestTagRouterRouteForce(t *testing.T) {
+	u1, e1 := common.NewURL(tagRouterTestUserConsumerTag)
 	assert.Nil(t, e1)
 	tagRouter, e := NewTagRouter(&u1)
 	assert.Nil(t, e)
 
-	u2, e2 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=hangzhou")
-	u3, e3 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=shanghai")
-	u4, e4 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=beijing")
+	u2, e2 := common.NewURL(tagRouterTestHangZhouUrl)
+	u3, e3 := common.NewURL(tagRouterTestShangHaiUrl)
+	u4, e4 := common.NewURL(tagRouterTestBeijingUrl)
 	assert.Nil(t, e2)
 	assert.Nil(t, e3)
 	assert.Nil(t, e4)
@@ -100,29 +115,29 @@ func TestTagRouter_Route_force(t *testing.T) {
 	var invokers []protocol.Invoker
 	invokers = append(invokers, inv2, inv3, inv4)
 	inv := &invocation.RPCInvocation{}
-	inv.SetAttachments("dubbo.tag", "hangzhou")
+	inv.SetAttachments(tagRouterTestDubboTag, tagRouterTestHangZhou)
 	invRst1 := tagRouter.Route(invokers, &u1, inv)
 	assert.Equal(t, 1, len(invRst1))
-	assert.Equal(t, "hangzhou", invRst1[0].GetUrl().GetParam("dubbo.tag", ""))
+	assert.Equal(t, tagRouterTestHangZhou, invRst1[0].GetUrl().GetParam(tagRouterTestDubboTag, ""))
 
-	inv.SetAttachments("dubbo.tag", "guangzhou")
+	inv.SetAttachments(tagRouterTestDubboTag, tagRouterTestGuangZhou)
 	invRst2 := tagRouter.Route(invokers, &u1, inv)
 	assert.Equal(t, 0, len(invRst2))
-	inv.SetAttachments("dubbo.force.tag", "false")
-	inv.SetAttachments("dubbo.tag", "guangzhou")
+	inv.SetAttachments(tagRouterTestDubboForceTag, tagRouterTestFalse)
+	inv.SetAttachments(tagRouterTestDubboTag, tagRouterTestGuangZhou)
 	invRst3 := tagRouter.Route(invokers, &u1, inv)
 	assert.Equal(t, 3, len(invRst3))
 }
 
-func TestTagRouter_Route_noForce(t *testing.T) {
-	u1, e1 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserConsumer?interface=com.ikurento.user.UserConsumer&group=&version=2.6.0&enabled=true")
+func TestTagRouterRouteNoForce(t *testing.T) {
+	u1, e1 := common.NewURL(tagRouterTestUserConsumer)
 	assert.Nil(t, e1)
 	tagRouter, e := NewTagRouter(&u1)
 	assert.Nil(t, e)
 
-	u2, e2 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=hangzhou")
-	u3, e3 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=shanghai")
-	u4, e4 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=beijing")
+	u2, e2 := common.NewURL(tagRouterTestHangZhouUrl)
+	u3, e3 := common.NewURL(tagRouterTestShangHaiUrl)
+	u4, e4 := common.NewURL(tagRouterTestShangHaiUrl)
 	assert.Nil(t, e2)
 	assert.Nil(t, e3)
 	assert.Nil(t, e4)
@@ -132,16 +147,16 @@ func TestTagRouter_Route_noForce(t *testing.T) {
 	var invokers []protocol.Invoker
 	invokers = append(invokers, inv2, inv3, inv4)
 	inv := &invocation.RPCInvocation{}
-	inv.SetAttachments("dubbo.tag", "hangzhou")
+	inv.SetAttachments(tagRouterTestDubboTag, tagRouterTestHangZhou)
 	invRst := tagRouter.Route(invokers, &u1, inv)
 	assert.Equal(t, 1, len(invRst))
-	assert.Equal(t, "hangzhou", invRst[0].GetUrl().GetParam("dubbo.tag", ""))
+	assert.Equal(t, tagRouterTestHangZhou, invRst[0].GetUrl().GetParam(tagRouterTestDubboTag, ""))
 
-	inv.SetAttachments("dubbo.tag", "guangzhou")
-	inv.SetAttachments("dubbo.force.tag", "true")
+	inv.SetAttachments(tagRouterTestDubboTag, tagRouterTestGuangZhou)
+	inv.SetAttachments(tagRouterTestDubboForceTag, tagRouterTestTrue)
 	invRst1 := tagRouter.Route(invokers, &u1, inv)
 	assert.Equal(t, 0, len(invRst1))
-	inv.SetAttachments("dubbo.force.tag", "false")
+	inv.SetAttachments(tagRouterTestDubboForceTag, tagRouterTestFalse)
 	invRst2 := tagRouter.Route(invokers, &u1, inv)
 	assert.Equal(t, 3, len(invRst2))
 }
diff --git a/common/config/environment.go b/common/config/environment.go
index 071af31152ba4ce3c579f70aa23df59d718ce506..44cdd1fca18bfed306b135fe38ef536779e148aa 100644
--- a/common/config/environment.go
+++ b/common/config/environment.go
@@ -46,7 +46,7 @@ var (
 	once     sync.Once
 )
 
-// GetEnvInstance ...
+// GetEnvInstance gets env instance by singleton
 func GetEnvInstance() *Environment {
 	once.Do(func() {
 		instance = &Environment{configCenterFirst: true}
@@ -54,7 +54,7 @@ func GetEnvInstance() *Environment {
 	return instance
 }
 
-// NewEnvInstance ...
+// NewEnvInstance creates Environment instance
 func NewEnvInstance() {
 	instance = &Environment{configCenterFirst: true}
 }
@@ -67,21 +67,22 @@ func NewEnvInstance() {
 //	return env.configCenterFirst
 //}
 
-// UpdateExternalConfigMap ...
+// UpdateExternalConfigMap updates env externalConfigMap field
 func (env *Environment) UpdateExternalConfigMap(externalMap map[string]string) {
 	for k, v := range externalMap {
 		env.externalConfigMap.Store(k, v)
 	}
 }
 
-// UpdateAppExternalConfigMap ...
+// UpdateAppExternalConfigMap updates env appExternalConfigMap field
 func (env *Environment) UpdateAppExternalConfigMap(externalMap map[string]string) {
 	for k, v := range externalMap {
 		env.appExternalConfigMap.Store(k, v)
 	}
 }
 
-// Configuration ...
+// Configuration puts externalConfigMap and appExternalConfigMap into list
+// List represents a doubly linked list.
 func (env *Environment) Configuration() *list.List {
 	cfgList := list.New()
 	// The sequence would be: SystemConfiguration -> ExternalConfiguration -> AppExternalConfiguration -> AbstractConfig -> PropertiesConfiguration
@@ -90,17 +91,17 @@ func (env *Environment) Configuration() *list.List {
 	return cfgList
 }
 
-// SetDynamicConfiguration ...
+// SetDynamicConfiguration sets value for dynamicConfiguration
 func (env *Environment) SetDynamicConfiguration(dc config_center.DynamicConfiguration) {
 	env.dynamicConfiguration = dc
 }
 
-// GetDynamicConfiguration ...
+// GetDynamicConfiguration gets dynamicConfiguration
 func (env *Environment) GetDynamicConfiguration() config_center.DynamicConfiguration {
 	return env.dynamicConfiguration
 }
 
-// InmemoryConfiguration ...
+// InmemoryConfiguration stores config in memory
 type InmemoryConfiguration struct {
 	store *sync.Map
 }
@@ -109,7 +110,7 @@ func newInmemoryConfiguration(p *sync.Map) *InmemoryConfiguration {
 	return &InmemoryConfiguration{store: p}
 }
 
-// GetProperty ...
+// GetProperty gets value from InmemoryConfiguration instance by @key
 func (conf *InmemoryConfiguration) GetProperty(key string) (bool, string) {
 	if conf.store == nil {
 		return false, ""
@@ -123,14 +124,14 @@ func (conf *InmemoryConfiguration) GetProperty(key string) (bool, string) {
 	return false, ""
 }
 
-// GetSubProperty ...
+// GetSubProperty gets sub property from InmemoryConfiguration instance by @subkey
 func (conf *InmemoryConfiguration) GetSubProperty(subKey string) map[string]struct{} {
 	if conf.store == nil {
 		return nil
 	}
 
 	properties := make(map[string]struct{})
-	conf.store.Range(func(key, value interface{}) bool {
+	conf.store.Range(func(key, _ interface{}) bool {
 		if idx := strings.Index(key.(string), subKey); idx >= 0 {
 			after := key.(string)[idx+len(subKey):]
 			if i := strings.Index(after, "."); i >= 0 {
diff --git a/common/config/environment_test.go b/common/config/environment_test.go
index 2d84dc4ae31ef74fdcf2a37d7acb4a3e4cf36a09..183071b0ef0d10e9ce010965668b46d30b008a15 100644
--- a/common/config/environment_test.go
+++ b/common/config/environment_test.go
@@ -29,14 +29,14 @@ func TestGetEnvInstance(t *testing.T) {
 	assert.NotNil(t, instance)
 }
 
-func TestEnvironment_UpdateExternalConfigMap(t *testing.T) {
+func TestEnvironmentUpdateExternalConfigMap(t *testing.T) {
 	GetEnvInstance().UpdateExternalConfigMap(map[string]string{"1": "2"})
 	v, ok := GetEnvInstance().externalConfigMap.Load("1")
 	assert.True(t, ok)
 	assert.Equal(t, "2", v)
 }
 
-func TestEnvironment_ConfigurationAndGetProperty(t *testing.T) {
+func TestEnvironmentConfigurationAndGetProperty(t *testing.T) {
 	GetEnvInstance().UpdateExternalConfigMap(map[string]string{"1": "2"})
 	list := GetEnvInstance().Configuration()
 	ok, v := list.Back().Value.(*InmemoryConfiguration).GetProperty("1")
@@ -44,7 +44,7 @@ func TestEnvironment_ConfigurationAndGetProperty(t *testing.T) {
 	assert.Equal(t, "2", v)
 }
 
-func TestInmemoryConfiguration_GetSubProperty(t *testing.T) {
+func TestInmemoryConfigurationGetSubProperty(t *testing.T) {
 	GetEnvInstance().UpdateExternalConfigMap(map[string]string{"123": "2"})
 	list := GetEnvInstance().Configuration()
 	m := list.Front().Value.(*InmemoryConfiguration).GetSubProperty("1")
diff --git a/common/constant/default.go b/common/constant/default.go
index 3c889158e460031f06b9401008c80f55200a46e4..c69989b4fbc3e95cb42c7f5e403989b9cff9215b 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 d9413fcc9e24a857cdb398cc6fb96074ffef31b4..8da0e89caf7b5a184bdd98293f04557afe173ecf 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -119,6 +119,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"
 )
@@ -149,6 +150,7 @@ const (
 	NACOS_CATEGORY_KEY           = "category"
 	NACOS_PROTOCOL_KEY           = "protocol"
 	NACOS_PATH_KEY               = "path"
+	NACOS_NAMESPACE_ID           = "namespaceId"
 )
 
 const (
@@ -180,6 +182,9 @@ const (
 	// ForceUseTag is the tag in attachment
 	ForceUseTag = "dubbo.force.tag"
 	Tagkey      = "dubbo.tag"
+
+	// Attachment key in context in invoker
+	AttachmentKey = "attachment"
 )
 
 const (
@@ -210,9 +215,9 @@ const (
 	// consumer
 	CONSUMER = "consumer"
 	// key of access key id
-	ACCESS_KEY_ID_KEY = "accessKeyId"
+	ACCESS_KEY_ID_KEY = ".accessKeyId"
 	// key of secret access key
-	SECRET_ACCESS_KEY_KEY = "secretAccessKey"
+	SECRET_ACCESS_KEY_KEY = ".secretAccessKey"
 )
 
 // metadata report
diff --git a/common/extension/auth.go b/common/extension/auth.go
index d7900045d3f7db9e2587e4e92e377325c74971b3..4fca0a8e8c255456720df9e4fd9852295715b160 100644
--- a/common/extension/auth.go
+++ b/common/extension/auth.go
@@ -26,13 +26,13 @@ var (
 	accesskeyStorages = make(map[string]func() filter.AccessKeyStorage)
 )
 
-// SetAuthenticator put the fcn into map with name
+// SetAuthenticator puts the @fcn into map with name
 func SetAuthenticator(name string, fcn func() filter.Authenticator) {
 	authenticators[name] = fcn
 }
 
-// GetAuthenticator find the Authenticator with name
-// if not found, it will panic
+// GetAuthenticator finds the Authenticator with @name
+// 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.")
@@ -40,13 +40,13 @@ func GetAuthenticator(name string) filter.Authenticator {
 	return authenticators[name]()
 }
 
-// SetAccesskeyStorages will set the fcn into map with this name
+// SetAccesskeyStorages will set the @fcn into map with this name
 func SetAccesskeyStorages(name string, fcn func() filter.AccessKeyStorage) {
 	accesskeyStorages[name] = fcn
 }
 
-// GetAccesskeyStorages find the storage with the name.
-// If not found, it will panic.
+// GetAccesskeyStorages finds the storage with the @name.
+// 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/cluster.go b/common/extension/cluster.go
index b2d81f6b1e56bb487b1d408b878308f6dfe042e4..8be27a1ca3aaf93dd54201c4ff7081478c746f0f 100644
--- a/common/extension/cluster.go
+++ b/common/extension/cluster.go
@@ -25,12 +25,13 @@ var (
 	clusters = make(map[string]func() cluster.Cluster)
 )
 
-// SetCluster ...
+// SetCluster sets the cluster fault-tolerant mode with @name
+// For example: available/failfast/broadcast/failfast/failsafe/...
 func SetCluster(name string, fcn func() cluster.Cluster) {
 	clusters[name] = fcn
 }
 
-// GetCluster ...
+// GetCluster finds the cluster fault-tolerant mode with @name
 func GetCluster(name string) cluster.Cluster {
 	if clusters[name] == nil {
 		panic("cluster for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/config_center.go b/common/extension/config_center.go
index 03d27db46c94b0ea0e212646077d97f948a8e328..5a2c52f32d070f5ec03bdae0b3cd47f869c28171 100644
--- a/common/extension/config_center.go
+++ b/common/extension/config_center.go
@@ -26,12 +26,12 @@ var (
 	configCenters = make(map[string]func(config *common.URL) (config_center.DynamicConfiguration, error))
 )
 
-// SetConfigCenter ...
-func SetConfigCenter(name string, v func(config *common.URL) (config_center.DynamicConfiguration, error)) {
+// SetConfigCenter sets the DynamicConfiguration with @name
+func SetConfigCenter(name string, v func(*common.URL) (config_center.DynamicConfiguration, error)) {
 	configCenters[name] = v
 }
 
-// GetConfigCenter ...
+// GetConfigCenter finds the DynamicConfiguration with @name
 func GetConfigCenter(name string, config *common.URL) (config_center.DynamicConfiguration, error) {
 	if configCenters[name] == nil {
 		panic("config center for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/config_center_factory.go b/common/extension/config_center_factory.go
index 85913fdce1ed3472c2bd9eb4aadbb0f631481dbd..dff89752296c6d2441d043ec628aa13ad219e698 100644
--- a/common/extension/config_center_factory.go
+++ b/common/extension/config_center_factory.go
@@ -25,12 +25,12 @@ var (
 	configCenterFactories = make(map[string]func() config_center.DynamicConfigurationFactory)
 )
 
-// SetConfigCenterFactory ...
+// SetConfigCenterFactory sets the DynamicConfigurationFactory with @name
 func SetConfigCenterFactory(name string, v func() config_center.DynamicConfigurationFactory) {
 	configCenterFactories[name] = v
 }
 
-// GetConfigCenterFactory ...
+// GetConfigCenterFactory finds the DynamicConfigurationFactory with @name
 func GetConfigCenterFactory(name string) config_center.DynamicConfigurationFactory {
 	if configCenterFactories[name] == nil {
 		panic("config center for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/config_reader.go b/common/extension/config_reader.go
index aced5b0281ff9313461425e5ec6d70d562c6c947..5e13d8629fd145dac680619a427c68b29226b051 100644
--- a/common/extension/config_reader.go
+++ b/common/extension/config_reader.go
@@ -26,12 +26,12 @@ var (
 	defaults      = make(map[string]string)
 )
 
-// SetConfigReaders set a creator of config reader.
+// SetConfigReaders sets a creator of config reader with @name
 func SetConfigReaders(name string, v func() interfaces.ConfigReader) {
 	configReaders[name] = v
 }
 
-// GetConfigReaders get a config reader by name.
+// GetConfigReaders gets a config reader with @name
 func GetConfigReaders(name string) interfaces.ConfigReader {
 	if configReaders[name] == nil {
 		panic("config reader for " + name + " is not existing, make sure you have imported the package.")
@@ -39,12 +39,12 @@ func GetConfigReaders(name string) interfaces.ConfigReader {
 	return configReaders[name]()
 }
 
-// SetDefaultConfigReader set {name} to default config reader for {module}
+// SetDefaultConfigReader sets @name for @module in default config reader
 func SetDefaultConfigReader(module, name string) {
 	defaults[module] = name
 }
 
-// GetDefaultConfigReader
+// GetDefaultConfigReader gets default config reader
 func GetDefaultConfigReader() map[string]string {
 	return defaults
 }
diff --git a/common/extension/configurator.go b/common/extension/configurator.go
index de98f8a260ea1f3a2e2a1f32c82dc869585e2789..dc2bea73afb79aaab36e2ce7cc9675169a446eb7 100644
--- a/common/extension/configurator.go
+++ b/common/extension/configurator.go
@@ -23,7 +23,7 @@ import (
 )
 
 const (
-	// DefaultKey ...
+	// DefaultKey for default Configurator
 	DefaultKey = "default"
 )
 
@@ -33,12 +33,12 @@ var (
 	configurator = make(map[string]getConfiguratorFunc)
 )
 
-// SetConfigurator ...
+// SetConfigurator sets the getConfiguratorFunc with @name
 func SetConfigurator(name string, v getConfiguratorFunc) {
 	configurator[name] = v
 }
 
-// GetConfigurator ...
+// GetConfigurator finds the Configurator with @name
 func GetConfigurator(name string, url *common.URL) config_center.Configurator {
 	if configurator[name] == nil {
 		panic("configurator for " + name + " is not existing, make sure you have import the package.")
@@ -47,12 +47,12 @@ func GetConfigurator(name string, url *common.URL) config_center.Configurator {
 
 }
 
-// SetDefaultConfigurator ...
+// SetDefaultConfigurator sets the default Configurator
 func SetDefaultConfigurator(v getConfiguratorFunc) {
 	configurator[DefaultKey] = v
 }
 
-// GetDefaultConfigurator ...
+// GetDefaultConfigurator gets default configurator
 func GetDefaultConfigurator(url *common.URL) config_center.Configurator {
 	if configurator[DefaultKey] == nil {
 		panic("configurator for default is not existing, make sure you have import the package.")
@@ -61,7 +61,7 @@ func GetDefaultConfigurator(url *common.URL) config_center.Configurator {
 
 }
 
-// GetDefaultConfiguratorFunc ...
+// GetDefaultConfiguratorFunc gets default configurator function
 func GetDefaultConfiguratorFunc() getConfiguratorFunc {
 	if configurator[DefaultKey] == nil {
 		panic("configurator for default is not existing, make sure you have import the package.")
diff --git a/common/extension/filter.go b/common/extension/filter.go
index deea2d908bc2741e0f15ecc36e9d4fc5975e531e..96059c4363060c41f14ececb466ca62bdaefb1a9 100644
--- a/common/extension/filter.go
+++ b/common/extension/filter.go
@@ -26,12 +26,13 @@ var (
 	rejectedExecutionHandler = make(map[string]func() filter.RejectedExecutionHandler)
 )
 
-// SetFilter ...
+// SetFilter sets the filter extension with @name
+// For example: hystrix/metrics/token/tracing/limit/...
 func SetFilter(name string, v func() filter.Filter) {
 	filters[name] = v
 }
 
-// GetFilter ...
+// GetFilter finds the filter extension with @name
 func GetFilter(name string) filter.Filter {
 	if filters[name] == nil {
 		panic("filter for " + name + " is not existing, make sure you have imported the package.")
@@ -39,12 +40,12 @@ func GetFilter(name string) filter.Filter {
 	return filters[name]()
 }
 
-// SetRejectedExecutionHandler ...
+// SetRejectedExecutionHandler sets the RejectedExecutionHandler with @name
 func SetRejectedExecutionHandler(name string, creator func() filter.RejectedExecutionHandler) {
 	rejectedExecutionHandler[name] = creator
 }
 
-// GetRejectedExecutionHandler ...
+// GetRejectedExecutionHandler finds the RejectedExecutionHandler with @name
 func GetRejectedExecutionHandler(name string) filter.RejectedExecutionHandler {
 	creator, ok := rejectedExecutionHandler[name]
 	if !ok {
diff --git a/common/extension/graceful_shutdown.go b/common/extension/graceful_shutdown.go
index 3abd75c0aa328f3553c3d83340ae440b8dfe3356..cb55419aabbce26b41e5b10f49268f6b3ace516d 100644
--- a/common/extension/graceful_shutdown.go
+++ b/common/extension/graceful_shutdown.go
@@ -49,7 +49,7 @@ func AddCustomShutdownCallback(callback func()) {
 	customShutdownCallbacks.PushBack(callback)
 }
 
-// GetAllCustomShutdownCallbacks ...
+// GetAllCustomShutdownCallbacks gets all custom shutdown callbacks
 func GetAllCustomShutdownCallbacks() *list.List {
 	return customShutdownCallbacks
 }
diff --git a/common/extension/health_checker.go b/common/extension/health_checker.go
index 365c5d0910812efb00eb94408bb226115b037c02..8def727614dad8393eeef9ced5e30a056fa65461 100644
--- a/common/extension/health_checker.go
+++ b/common/extension/health_checker.go
@@ -26,12 +26,12 @@ var (
 	healthCheckers = make(map[string]func(url *common.URL) router.HealthChecker)
 )
 
-// SethealthChecker set the HealthChecker with name
-func SethealthChecker(name string, fcn func(url *common.URL) router.HealthChecker) {
+// SethealthChecker sets the HealthChecker with @name
+func SethealthChecker(name string, fcn func(_ *common.URL) router.HealthChecker) {
 	healthCheckers[name] = fcn
 }
 
-// GetHealthChecker get the HealthChecker with name
+// GetHealthChecker gets the HealthChecker with @name
 func GetHealthChecker(name string, url *common.URL) router.HealthChecker {
 	if healthCheckers[name] == nil {
 		panic("healthCheckers for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/health_checker_test.go b/common/extension/health_checker_test.go
index ec934e6e9cedc5acbef350f17b87b0b2e37bc844..4e83a6f6e1ed8a57b6e6374377d08eabfb56c604 100644
--- a/common/extension/health_checker_test.go
+++ b/common/extension/health_checker_test.go
@@ -44,6 +44,6 @@ func (m mockHealthChecker) IsHealthy(invoker protocol.Invoker) bool {
 	return true
 }
 
-func newMockhealthCheck(url *common.URL) router.HealthChecker {
+func newMockhealthCheck(_ *common.URL) router.HealthChecker {
 	return &mockHealthChecker{}
 }
diff --git a/common/extension/loadbalance.go b/common/extension/loadbalance.go
index 0d557a4640ed892a18ad59a3247763ab5807a593..aa19141014a6c42df0c17dad05301997f67fbd79 100644
--- a/common/extension/loadbalance.go
+++ b/common/extension/loadbalance.go
@@ -25,12 +25,13 @@ var (
 	loadbalances = make(map[string]func() cluster.LoadBalance)
 )
 
-// SetLoadbalance ...
+// SetLoadbalance sets the loadbalance extension with @name
+// For example: random/round_robin/consistent_hash/least_active/...
 func SetLoadbalance(name string, fcn func() cluster.LoadBalance) {
 	loadbalances[name] = fcn
 }
 
-// GetLoadbalance ...
+// GetLoadbalance finds the loadbalance extension with @name
 func GetLoadbalance(name string) cluster.LoadBalance {
 	if loadbalances[name] == nil {
 		panic("loadbalance for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/metadata_report_factory.go b/common/extension/metadata_report_factory.go
index 0ae0793bb4459767cb42fb1860fc484388aae1a3..c55f8617fadd9d09d68547b05341d127716ce73c 100644
--- a/common/extension/metadata_report_factory.go
+++ b/common/extension/metadata_report_factory.go
@@ -25,12 +25,12 @@ var (
 	metaDataReportFactories = make(map[string]func() metadata.MetadataReportFactory, 8)
 )
 
-// SetMetadataReportFactory ...
+// SetMetadataReportFactory sets the MetadataReportFactory with @name
 func SetMetadataReportFactory(name string, v func() metadata.MetadataReportFactory) {
 	metaDataReportFactories[name] = v
 }
 
-// GetMetadataReportFactory ...
+// GetMetadataReportFactory finds the MetadataReportFactory with @name
 func GetMetadataReportFactory(name string) metadata.MetadataReportFactory {
 	if metaDataReportFactories[name] == nil {
 		panic("metadata report for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/metrics.go b/common/extension/metrics.go
index 42fca7a2db36614fcef31dd5ba7324a156164d4f..60cf6bac2384c7367094adad83e01f7dcf64a33d 100644
--- a/common/extension/metrics.go
+++ b/common/extension/metrics.go
@@ -27,12 +27,12 @@ var (
 	metricReporterMap = make(map[string]func() metrics.Reporter, 4)
 )
 
-// SetMetricReporter set a reporter with the name
+// SetMetricReporter sets a reporter with the @name
 func SetMetricReporter(name string, reporterFunc func() metrics.Reporter) {
 	metricReporterMap[name] = reporterFunc
 }
 
-// GetMetricReporter find the reporter with name.
+// GetMetricReporter finds the reporter with @name.
 // if not found, it will panic.
 // we should know that this method usually is called when system starts, so we should panic
 func GetMetricReporter(name string) metrics.Reporter {
diff --git a/common/extension/metrics_test.go b/common/extension/metrics_test.go
index 6a8a3fe538a9cd68c57c91592a88ec257ae4a267..2aaae75f0ccf7929754582aa42aa1bff4ece7c22 100644
--- a/common/extension/metrics_test.go
+++ b/common/extension/metrics_test.go
@@ -45,5 +45,6 @@ func TestGetMetricReporter(t *testing.T) {
 type mockReporter struct {
 }
 
+// Report method for feature expansion
 func (m mockReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) {
 }
diff --git a/common/extension/protocol.go b/common/extension/protocol.go
index 009687a17ace8cea567248af655e04604d09d9b8..c89dd08fae5d12b384d6ca4e797343fe79897bbd 100644
--- a/common/extension/protocol.go
+++ b/common/extension/protocol.go
@@ -25,12 +25,12 @@ var (
 	protocols = make(map[string]func() protocol.Protocol)
 )
 
-// SetProtocol ...
+// SetProtocol sets the protocol extension with @name
 func SetProtocol(name string, v func() protocol.Protocol) {
 	protocols[name] = v
 }
 
-// GetProtocol ...
+// GetProtocol finds the protocol extension with @name
 func GetProtocol(name string) protocol.Protocol {
 	if protocols[name] == nil {
 		panic("protocol for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/proxy_factory.go b/common/extension/proxy_factory.go
index 19826bb0560ea0d3fa471c04873b20a6878f57d8..1e326d884b5dd37925c38ffdf0a87e69bf6a865c 100644
--- a/common/extension/proxy_factory.go
+++ b/common/extension/proxy_factory.go
@@ -25,12 +25,12 @@ var (
 	proxyFactories = make(map[string]func(...proxy.Option) proxy.ProxyFactory)
 )
 
-// SetProxyFactory ...
+// SetProxyFactory sets the ProxyFactory extension with @name
 func SetProxyFactory(name string, f func(...proxy.Option) proxy.ProxyFactory) {
 	proxyFactories[name] = f
 }
 
-// GetProxyFactory ...
+// GetProxyFactory finds the ProxyFactory extension with @name
 func GetProxyFactory(name string) proxy.ProxyFactory {
 	if name == "" {
 		name = "default"
diff --git a/common/extension/registry.go b/common/extension/registry.go
index 6ba746dc47382927d12ce39b7936212c5d75153d..187c8fecf4e27c87d6feff8749730c77a83b2f32 100644
--- a/common/extension/registry.go
+++ b/common/extension/registry.go
@@ -26,15 +26,15 @@ var (
 	registrys = make(map[string]func(config *common.URL) (registry.Registry, error))
 )
 
-// SetRegistry ...
-func SetRegistry(name string, v func(config *common.URL) (registry.Registry, error)) {
+// SetRegistry sets the registry extension with @name
+func SetRegistry(name string, v func(_ *common.URL) (registry.Registry, error)) {
 	registrys[name] = v
 }
 
-// GetRegistry ...
+// 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/registry_directory.go b/common/extension/registry_directory.go
index 6b92189c4e98b391a90e6e71a68d51a252eede2a..330fc46400daf81047e5c24c1634249e355d74b7 100644
--- a/common/extension/registry_directory.go
+++ b/common/extension/registry_directory.go
@@ -27,12 +27,12 @@ type registryDirectory func(url *common.URL, registry registry.Registry) (cluste
 
 var defaultRegistry registryDirectory
 
-// SetDefaultRegistryDirectory ...
+// SetDefaultRegistryDirectory sets the default registryDirectory
 func SetDefaultRegistryDirectory(v registryDirectory) {
 	defaultRegistry = v
 }
 
-// GetDefaultRegistryDirectory ...
+// GetDefaultRegistryDirectory finds the registryDirectory with url and registry
 func GetDefaultRegistryDirectory(config *common.URL, registry registry.Registry) (cluster.Directory, error) {
 	if defaultRegistry == nil {
 		panic("registry directory is not existing, make sure you have import the package.")
diff --git a/common/extension/rest_client.go b/common/extension/rest_client.go
index 514d1fdfd2efb5c291fdb47df4dd69da26fa90b1..0c2f4ddf95d2226cfadc3ab6492c629ba15c4063 100644
--- a/common/extension/rest_client.go
+++ b/common/extension/rest_client.go
@@ -25,10 +25,12 @@ var (
 	restClients = make(map[string]func(restOptions *client.RestOptions) client.RestClient, 8)
 )
 
-func SetRestClient(name string, fun func(restOptions *client.RestOptions) client.RestClient) {
+// SetRestClient sets the RestClient with @name
+func SetRestClient(name string, fun func(_ *client.RestOptions) client.RestClient) {
 	restClients[name] = fun
 }
 
+// GetNewRestClient finds the RestClient with @name
 func GetNewRestClient(name string, restOptions *client.RestOptions) client.RestClient {
 	if restClients[name] == nil {
 		panic("restClient for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/rest_server.go b/common/extension/rest_server.go
index fa8d435a5c976a4c95b036810fa2916a327a73b9..37a231a57c861ae49aab244eb9fa8b611ae63f6d 100644
--- a/common/extension/rest_server.go
+++ b/common/extension/rest_server.go
@@ -25,10 +25,12 @@ var (
 	restServers = make(map[string]func() server.RestServer, 8)
 )
 
+// SetRestServer sets the RestServer with @name
 func SetRestServer(name string, fun func() server.RestServer) {
 	restServers[name] = fun
 }
 
+// GetNewRestServer finds the RestServer with @name
 func GetNewRestServer(name string) server.RestServer {
 	if restServers[name] == nil {
 		panic("restServer for " + name + " is not existing, make sure you have import the package.")
diff --git a/common/extension/router_factory.go b/common/extension/router_factory.go
index 1339228618def41ccebc8d54cdebb5a623e605fa..b61a05668a0cd24e28f6de46754c00ffbcb766d8 100644
--- a/common/extension/router_factory.go
+++ b/common/extension/router_factory.go
@@ -26,31 +26,31 @@ import (
 )
 
 var (
-	routers               = make(map[string]func() router.RouterFactory)
+	routers               = make(map[string]func() router.PriorityRouterFactory)
 	fileRouterFactoryOnce sync.Once
-	fileRouterFactories   = make(map[string]router.FileRouterFactory)
+	fileRouterFactories   = make(map[string]router.FilePriorityRouterFactory)
 )
 
-// SetRouterFactory Set create router factory function by name
-func SetRouterFactory(name string, fun func() router.RouterFactory) {
+// SetRouterFactory sets create router factory function with @name
+func SetRouterFactory(name string, fun func() router.PriorityRouterFactory) {
 	routers[name] = fun
 }
 
-// GetRouterFactory Get create router factory function by name
-func GetRouterFactory(name string) router.RouterFactory {
+// GetRouterFactory gets create router factory function by @name
+func GetRouterFactory(name string) router.PriorityRouterFactory {
 	if routers[name] == nil {
 		panic("router_factory for " + name + " is not existing, make sure you have import the package.")
 	}
 	return routers[name]()
 }
 
-// GetRouterFactories Get all create router factory function
-func GetRouterFactories() map[string]func() router.RouterFactory {
+// GetRouterFactories gets all create router factory function
+func GetRouterFactories() map[string]func() router.PriorityRouterFactory {
 	return routers
 }
 
-// GetFileRouterFactories Get all create file router factory instance
-func GetFileRouterFactories() map[string]router.FileRouterFactory {
+// GetFileRouterFactories gets all create file router factory instance
+func GetFileRouterFactories() map[string]router.FilePriorityRouterFactory {
 	l := len(routers)
 	if l == 0 {
 		return nil
@@ -58,7 +58,7 @@ func GetFileRouterFactories() map[string]router.FileRouterFactory {
 	fileRouterFactoryOnce.Do(func() {
 		for k := range routers {
 			factory := GetRouterFactory(k)
-			if fr, ok := factory.(router.FileRouterFactory); ok {
+			if fr, ok := factory.(router.FilePriorityRouterFactory); ok {
 				fileRouterFactories[k] = fr
 			}
 		}
diff --git a/common/extension/service_discovery.go b/common/extension/service_discovery.go
index 25b80cf3353505c058bea40cc4c80712ad923d2d..1d891c2189e55fbd6fa03e4c6e5ea6ec5b654e46 100644
--- a/common/extension/service_discovery.go
+++ b/common/extension/service_discovery.go
@@ -29,8 +29,8 @@ var (
 	discoveryCreatorMap = make(map[string]func(url *common.URL) (registry.ServiceDiscovery, error), 4)
 )
 
-// SetServiceDiscovery will store the creator and name
-func SetServiceDiscovery(name string, creator func(url *common.URL) (registry.ServiceDiscovery, error)) {
+// SetServiceDiscovery will store the @creator and @name
+func SetServiceDiscovery(name string, creator func(_ *common.URL) (registry.ServiceDiscovery, error)) {
 	discoveryCreatorMap[name] = creator
 }
 
diff --git a/common/extension/tps_limit.go b/common/extension/tps_limit.go
index c72c2b030fc0f391362189bfe18a65582543693a..d25821deee626cb75c94af2257f877c9983023de 100644
--- a/common/extension/tps_limit.go
+++ b/common/extension/tps_limit.go
@@ -26,12 +26,12 @@ var (
 	tpsLimiter       = make(map[string]func() filter.TpsLimiter)
 )
 
-// SetTpsLimiter ...
+// SetTpsLimiter sets the TpsLimiter with @name
 func SetTpsLimiter(name string, creator func() filter.TpsLimiter) {
 	tpsLimiter[name] = creator
 }
 
-// GetTpsLimiter ...
+// GetTpsLimiter finds the TpsLimiter with @name
 func GetTpsLimiter(name string) filter.TpsLimiter {
 	creator, ok := tpsLimiter[name]
 	if !ok {
@@ -41,12 +41,12 @@ func GetTpsLimiter(name string) filter.TpsLimiter {
 	return creator()
 }
 
-// SetTpsLimitStrategy ...
+// SetTpsLimitStrategy sets the TpsLimitStrategyCreator with @name
 func SetTpsLimitStrategy(name string, creator filter.TpsLimitStrategyCreator) {
 	tpsLimitStrategy[name] = creator
 }
 
-// GetTpsLimitStrategyCreator ...
+// GetTpsLimitStrategyCreator finds the TpsLimitStrategyCreator with @name
 func GetTpsLimitStrategyCreator(name string) filter.TpsLimitStrategyCreator {
 	creator, ok := tpsLimitStrategy[name]
 	if !ok {
diff --git a/common/logger/logger.go b/common/logger/logger.go
index 016afe69808f2007541c617f406db64beb511f1c..9bc6a461003d086e8951ebac3d6997774ac69b90 100644
--- a/common/logger/logger.go
+++ b/common/logger/logger.go
@@ -40,13 +40,13 @@ var (
 	logger Logger
 )
 
-// DubboLogger ...
+// nolint
 type DubboLogger struct {
 	Logger
 	dynamicLevel zap.AtomicLevel
 }
 
-// Logger ...
+// Logger is the interface for Logger types
 type Logger interface {
 	Info(args ...interface{})
 	Warn(args ...interface{})
@@ -67,7 +67,7 @@ func init() {
 	}
 }
 
-// InitLog ...
+// InitLog use for init logger by call InitLogger
 func InitLog(logConfFile string) error {
 	if logConfFile == "" {
 		InitLogger(nil)
@@ -96,7 +96,7 @@ func InitLog(logConfFile string) error {
 	return nil
 }
 
-// InitLogger ...
+// InitLogger use for init logger by @conf
 func InitLogger(conf *zap.Config) {
 	var zapLoggerConfig zap.Config
 	if conf == nil {
@@ -125,18 +125,18 @@ func InitLogger(conf *zap.Config) {
 	getty.SetLogger(logger)
 }
 
-// SetLogger ...
+// SetLogger sets logger for dubbo and getty
 func SetLogger(log Logger) {
 	logger = log
 	getty.SetLogger(logger)
 }
 
-// GetLogger ...
+// GetLogger gets the logger
 func GetLogger() Logger {
 	return logger
 }
 
-// SetLoggerLevel ...
+// SetLoggerLevel use for set logger level
 func SetLoggerLevel(level string) bool {
 	if l, ok := logger.(OpsLogger); ok {
 		l.SetLoggerLevel(level)
@@ -145,13 +145,13 @@ func SetLoggerLevel(level string) bool {
 	return false
 }
 
-// OpsLogger ...
+// OpsLogger use for the SetLoggerLevel
 type OpsLogger interface {
 	Logger
 	SetLoggerLevel(level string)
 }
 
-// SetLoggerLevel ...
+// SetLoggerLevel use for set logger level
 func (dl *DubboLogger) SetLoggerLevel(level string) {
 	l := new(zapcore.Level)
 	l.Set(level)
diff --git a/common/logger/logging.go b/common/logger/logging.go
index 36d48ee61e8a4a986abfbaa79f3d361cd81494f4..7a31ece203815287384ade282b2a4f12e11abc2a 100644
--- a/common/logger/logging.go
+++ b/common/logger/logging.go
@@ -17,42 +17,42 @@
 
 package logger
 
-// Info ...
+// Info is info level
 func Info(args ...interface{}) {
 	logger.Info(args...)
 }
 
-// Warn ...
+// Warn is warning level
 func Warn(args ...interface{}) {
 	logger.Warn(args...)
 }
 
-// Error ...
+// Error is error level
 func Error(args ...interface{}) {
 	logger.Error(args...)
 }
 
-// Debug ...
+// Debug is debug level
 func Debug(args ...interface{}) {
 	logger.Debug(args...)
 }
 
-// Infof ...
+// Infof is format info level
 func Infof(fmt string, args ...interface{}) {
 	logger.Infof(fmt, args...)
 }
 
-// Warnf ...
+// Warnf is format warning level
 func Warnf(fmt string, args ...interface{}) {
 	logger.Warnf(fmt, args...)
 }
 
-// Errorf ...
+// Errorf is format error level
 func Errorf(fmt string, args ...interface{}) {
 	logger.Errorf(fmt, args...)
 }
 
-// Debugf ...
+// Debugf is format debug level
 func Debugf(fmt string, args ...interface{}) {
 	logger.Debugf(fmt, args...)
 }
diff --git a/common/node.go b/common/node.go
index 979eee31ef3a63eb21af6c9045aee7f6d784f2ba..4febd78536126c67bdc65fc09d4be47fb869ef5e 100644
--- a/common/node.go
+++ b/common/node.go
@@ -17,7 +17,7 @@
 
 package common
 
-// Node ...
+// Node use for process dubbo node
 type Node interface {
 	GetUrl() URL
 	IsAvailable() bool
diff --git a/common/proxy/proxy.go b/common/proxy/proxy.go
index 68ba3ff7882837a9419c5e47228461af11fd79ba..abcf87cd9d297769bf8aff6fa07d6a4659091eb6 100644
--- a/common/proxy/proxy.go
+++ b/common/proxy/proxy.go
@@ -25,12 +25,13 @@ import (
 
 import (
 	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/protocol"
 	invocation_impl "github.com/apache/dubbo-go/protocol/invocation"
 )
 
-// Proxy struct
+// nolint
 type Proxy struct {
 	rpc         common.RPCService
 	invoke      protocol.Invoker
@@ -44,7 +45,7 @@ var (
 	typError = reflect.Zero(reflect.TypeOf((*error)(nil)).Elem()).Type()
 )
 
-// NewProxy ...
+// NewProxy create service proxy.
 func NewProxy(invoke protocol.Invoker, callBack interface{}, attachments map[string]string) *Proxy {
 	return &Proxy{
 		invoke:      invoke,
@@ -59,7 +60,6 @@ func NewProxy(invoke protocol.Invoker, callBack interface{}, attachments map[str
 // 		type XxxProvider struct {
 //  		Yyy func(ctx context.Context, args []interface{}, rsp *Zzz) error
 // 		}
-
 func (p *Proxy) Implement(v common.RPCService) {
 
 	// check parameters, incoming interface must be a elem's pointer.
@@ -141,7 +141,7 @@ func (p *Proxy) Implement(v common.RPCService) {
 			}
 
 			// add user setAttachment
-			atm := invCtx.Value("attachment")
+			atm := invCtx.Value(constant.AttachmentKey)
 			if m, ok := atm.(map[string]string); ok {
 				for k, value := range m {
 					inv.SetAttachments(k, value)
@@ -149,6 +149,9 @@ func (p *Proxy) Implement(v common.RPCService) {
 			}
 
 			result := p.invoke.Invoke(invCtx, inv)
+			if len(result.Attachments()) > 0 {
+				invCtx = context.WithValue(invCtx, constant.AttachmentKey, result.Attachments())
+			}
 
 			err = result.Error()
 			logger.Debugf("[makeDubboCallProxy] result: %v, err: %v", result.Result(), err)
@@ -202,12 +205,12 @@ func (p *Proxy) Implement(v common.RPCService) {
 
 }
 
-// Get ...
+// Get gets rpc service instance.
 func (p *Proxy) Get() common.RPCService {
 	return p.rpc
 }
 
-// GetCallback ...
+// GetCallback gets callback.
 func (p *Proxy) GetCallback() interface{} {
 	return p.callBack
 }
diff --git a/common/proxy/proxy_factory.go b/common/proxy/proxy_factory.go
index 7b249a3e9754b097130a80bf3819d282dad6b6e8..117428cb253e1ad4a4ceee59aa620d7097b41a75 100644
--- a/common/proxy/proxy_factory.go
+++ b/common/proxy/proxy_factory.go
@@ -22,12 +22,12 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// ProxyFactory ...
+// ProxyFactory interface.
 type ProxyFactory interface {
 	GetProxy(invoker protocol.Invoker, url *common.URL) *Proxy
 	GetAsyncProxy(invoker protocol.Invoker, callBack interface{}, url *common.URL) *Proxy
 	GetInvoker(url common.URL) protocol.Invoker
 }
 
-// Option ...
+// Option will define a function of handling ProxyFactory
 type Option func(ProxyFactory)
diff --git a/common/proxy/proxy_factory/default.go b/common/proxy/proxy_factory/default.go
index 114cfee2363022da5f7957a825a16fc42b8c928f..1b8ca222011292040c57c3e86df0438943a5b464 100644
--- a/common/proxy/proxy_factory/default.go
+++ b/common/proxy/proxy_factory/default.go
@@ -40,7 +40,7 @@ func init() {
 	extension.SetProxyFactory("default", NewDefaultProxyFactory)
 }
 
-// DefaultProxyFactory ...
+// DefaultProxyFactory is the default proxy factory
 type DefaultProxyFactory struct {
 	//delegate ProxyFactory
 }
@@ -53,17 +53,17 @@ type DefaultProxyFactory struct {
 //	}
 //}
 
-// NewDefaultProxyFactory ...
-func NewDefaultProxyFactory(options ...proxy.Option) proxy.ProxyFactory {
+// NewDefaultProxyFactory returns a proxy factory instance
+func NewDefaultProxyFactory(_ ...proxy.Option) proxy.ProxyFactory {
 	return &DefaultProxyFactory{}
 }
 
-// GetProxy ...
+// GetProxy gets a proxy
 func (factory *DefaultProxyFactory) GetProxy(invoker protocol.Invoker, url *common.URL) *proxy.Proxy {
 	return factory.GetAsyncProxy(invoker, nil, url)
 }
 
-// GetAsyncProxy ...
+// GetAsyncProxy gets a async proxy
 func (factory *DefaultProxyFactory) GetAsyncProxy(invoker protocol.Invoker, callBack interface{}, url *common.URL) *proxy.Proxy {
 	//create proxy
 	attachments := map[string]string{}
@@ -71,19 +71,19 @@ func (factory *DefaultProxyFactory) GetAsyncProxy(invoker protocol.Invoker, call
 	return proxy.NewProxy(invoker, callBack, attachments)
 }
 
-// GetInvoker ...
+// GetInvoker gets a invoker
 func (factory *DefaultProxyFactory) GetInvoker(url common.URL) protocol.Invoker {
 	return &ProxyInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
 	}
 }
 
-// ProxyInvoker ...
+// ProxyInvoker is a invoker struct
 type ProxyInvoker struct {
 	protocol.BaseInvoker
 }
 
-// Invoke ...
+// Invoke is used to call service method by invocation
 func (pi *ProxyInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	result := &protocol.RPCResult{}
 	result.SetAttachments(invocation.Attachments())
@@ -113,6 +113,7 @@ func (pi *ProxyInvoker) Invoke(ctx context.Context, invocation protocol.Invocati
 
 	in := []reflect.Value{svc.Rcvr()}
 	if method.CtxType() != nil {
+		ctx = context.WithValue(ctx, constant.AttachmentKey, invocation.Attachments())
 		in = append(in, method.SuiteContext(ctx))
 	}
 
diff --git a/common/proxy/proxy_factory/default_test.go b/common/proxy/proxy_factory/default_test.go
index 7159b4b00eb2fcddb0f20f701f56b3179e57c4a0..99d5c020f4bfd0254ddddc65e78bcae2e252b6be 100644
--- a/common/proxy/proxy_factory/default_test.go
+++ b/common/proxy/proxy_factory/default_test.go
@@ -31,7 +31,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-func Test_GetProxy(t *testing.T) {
+func TestGetProxy(t *testing.T) {
 	proxyFactory := NewDefaultProxyFactory()
 	url := common.NewURLWithOptions()
 	proxy := proxyFactory.GetProxy(protocol.NewBaseInvoker(*url), url)
@@ -45,7 +45,7 @@ func (u *TestAsync) CallBack(res common.CallbackResponse) {
 	fmt.Println("CallBack res:", res)
 }
 
-func Test_GetAsyncProxy(t *testing.T) {
+func TestGetAsyncProxy(t *testing.T) {
 	proxyFactory := NewDefaultProxyFactory()
 	url := common.NewURLWithOptions()
 	async := &TestAsync{}
@@ -53,7 +53,7 @@ func Test_GetAsyncProxy(t *testing.T) {
 	assert.NotNil(t, proxy)
 }
 
-func Test_GetInvoker(t *testing.T) {
+func TestGetInvoker(t *testing.T) {
 	proxyFactory := NewDefaultProxyFactory()
 	url := common.NewURLWithOptions()
 	invoker := proxyFactory.GetInvoker(*url)
diff --git a/common/proxy/proxy_test.go b/common/proxy/proxy_test.go
index 8c1c0295d05135095b5be35b5b2b16428691d7f2..14b2befbc47242d9cc9a2f88e9070b84828062c0 100644
--- a/common/proxy/proxy_test.go
+++ b/common/proxy/proxy_test.go
@@ -53,7 +53,7 @@ func (s *TestServiceInt) Reference() string {
 	return "com.test.TestServiceInt"
 }
 
-func TestProxy_Implement(t *testing.T) {
+func TestProxyImplement(t *testing.T) {
 
 	invoker := protocol.NewBaseInvoker(common.URL{})
 	p := NewProxy(invoker, nil, map[string]string{constant.ASYNC_KEY: "false"})
@@ -84,7 +84,7 @@ func TestProxy_Implement(t *testing.T) {
 		TestService
 		methodOne func(context.Context, interface{}, *struct{}) error
 	}
-	s1 := &S1{TestService: *s, methodOne: func(i context.Context, i2 interface{}, i3 *struct{}) error {
+	s1 := &S1{TestService: *s, methodOne: func(_ context.Context, _ interface{}, _ *struct{}) error {
 		return perrors.New("errors")
 	}}
 	p.Implement(s1)
diff --git a/common/rpc_service.go b/common/rpc_service.go
index ebd1d02f843bc339c3a37d977e2138798307475d..05ca3721d98124ccbdebedb47b5ae4edd8b84add 100644
--- a/common/rpc_service.go
+++ b/common/rpc_service.go
@@ -35,23 +35,23 @@ import (
 )
 
 // RPCService
-//rpc service interface
+// rpc service interface
 type RPCService interface {
 	// Reference:
 	// rpc service id or reference id
 	Reference() string
 }
 
-//AsyncCallbackService callback interface for async
+// AsyncCallbackService callback interface for async
 type AsyncCallbackService interface {
 	// Callback: callback
 	CallBack(response CallbackResponse)
 }
 
-//CallbackResponse for different protocol
+// CallbackResponse for different protocol
 type CallbackResponse interface{}
 
-//AsyncCallback async callback method
+// AsyncCallback async callback method
 type AsyncCallback func(response CallbackResponse)
 
 // for lowercase func
@@ -59,7 +59,6 @@ type AsyncCallback func(response CallbackResponse)
 //     return map[string][string]{}
 // }
 const (
-	// METHOD_MAPPER ...
 	METHOD_MAPPER = "MethodMapper"
 )
 
@@ -68,8 +67,7 @@ var (
 	// because Typeof takes an empty interface value. This is annoying.
 	typeOfError = reflect.TypeOf((*error)(nil)).Elem()
 
-	// ServiceMap ...
-	// todo: lowerecas?
+	// ServiceMap store description of service.
 	ServiceMap = &serviceMap{
 		serviceMap:   make(map[string]map[string]*Service),
 		interfaceMap: make(map[string][]*Service),
@@ -80,7 +78,7 @@ var (
 // info of method
 //////////////////////////
 
-// MethodType ...
+// MethodType is description of service method.
 type MethodType struct {
 	method    reflect.Method
 	ctxType   reflect.Type   // request context
@@ -88,27 +86,27 @@ type MethodType struct {
 	replyType reflect.Type   // return value, otherwise it is nil
 }
 
-// Method ...
+// Method gets @m.method.
 func (m *MethodType) Method() reflect.Method {
 	return m.method
 }
 
-// CtxType ...
+// CtxType gets @m.ctxType.
 func (m *MethodType) CtxType() reflect.Type {
 	return m.ctxType
 }
 
-// ArgsType ...
+// ArgsType gets @m.argsType.
 func (m *MethodType) ArgsType() []reflect.Type {
 	return m.argsType
 }
 
-// ReplyType ...
+// ReplyType gets @m.replyType.
 func (m *MethodType) ReplyType() reflect.Type {
 	return m.replyType
 }
 
-// SuiteContext ...
+// SuiteContext tranfers @ctx to reflect.Value type or get it from @m.ctxType.
 func (m *MethodType) SuiteContext(ctx context.Context) reflect.Value {
 	if contextv := reflect.ValueOf(ctx); contextv.IsValid() {
 		return contextv
@@ -120,7 +118,7 @@ func (m *MethodType) SuiteContext(ctx context.Context) reflect.Value {
 // info of service interface
 //////////////////////////
 
-// Service ...
+// Service is description of service
 type Service struct {
 	name     string
 	rcvr     reflect.Value
@@ -128,17 +126,17 @@ type Service struct {
 	methods  map[string]*MethodType
 }
 
-// Method ...
+// Method gets @s.methods.
 func (s *Service) Method() map[string]*MethodType {
 	return s.methods
 }
 
-// RcvrType ...
+// RcvrType gets @s.rcvrType.
 func (s *Service) RcvrType() reflect.Type {
 	return s.rcvrType
 }
 
-// Rcvr ...
+// Rcvr gets @s.rcvr.
 func (s *Service) Rcvr() reflect.Value {
 	return s.rcvr
 }
@@ -153,7 +151,7 @@ type serviceMap struct {
 	interfaceMap map[string][]*Service          // interface -> service
 }
 
-// GetService get a service defination by protocol and name
+// GetService gets a service defination by protocol and name
 func (sm *serviceMap) GetService(protocol, name string) *Service {
 	sm.mutex.RLock()
 	defer sm.mutex.RUnlock()
@@ -166,7 +164,7 @@ func (sm *serviceMap) GetService(protocol, name string) *Service {
 	return nil
 }
 
-// GetInterface get an interface defination by interface name
+// GetInterface gets an interface defination by interface name
 func (sm *serviceMap) GetInterface(interfaceName string) []*Service {
 	sm.mutex.RLock()
 	defer sm.mutex.RUnlock()
@@ -176,7 +174,7 @@ func (sm *serviceMap) GetInterface(interfaceName string) []*Service {
 	return nil
 }
 
-// Register register a service by @interfaceName and @protocol
+// Register registers a service by @interfaceName and @protocol
 func (sm *serviceMap) Register(interfaceName, protocol string, rcvr RPCService) (string, error) {
 	if sm.serviceMap[protocol] == nil {
 		sm.serviceMap[protocol] = make(map[string]*Service)
@@ -224,7 +222,7 @@ func (sm *serviceMap) Register(interfaceName, protocol string, rcvr RPCService)
 	return strings.TrimSuffix(methods, ","), nil
 }
 
-// UnRegister cancel a service by @interfaceName, @protocol and @serviceId
+// UnRegister cancels a service by @interfaceName, @protocol and @serviceId
 func (sm *serviceMap) UnRegister(interfaceName, protocol, serviceId string) error {
 	if protocol == "" || serviceId == "" {
 		return perrors.New("protocol or serviceName is nil")
diff --git a/common/rpc_service_test.go b/common/rpc_service_test.go
index 2311205d0ec0c2fd4642a4d8639c0bf871fe1d17..7c4eb421d7ed0e5e0306eb1a1a2ff5ac31c29b6d 100644
--- a/common/rpc_service_test.go
+++ b/common/rpc_service_test.go
@@ -27,6 +27,14 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+const (
+	referenceTestPath             = "com.test.Path"
+	referenceTestPathDistinct     = "com.test.Path1"
+	testInterfaceName             = "testService"
+	testProtocol                  = "testprotocol"
+	testSuiteMethodExpectedString = "interface {}"
+)
+
 type TestService struct {
 }
 
@@ -40,7 +48,7 @@ func (s *TestService) MethodThree() error {
 	return nil
 }
 func (s *TestService) Reference() string {
-	return "com.test.Path"
+	return referenceTestPath
 }
 func (s *TestService) MethodMapper() map[string]string {
 	return map[string]string{
@@ -63,36 +71,36 @@ func (s *testService) Method4(ctx context.Context, args []interface{}, rsp *stru
 	return nil
 }
 func (s *testService) Reference() string {
-	return "com.test.Path"
+	return referenceTestPath
 }
 
 type TestService1 struct {
 }
 
 func (s *TestService1) Reference() string {
-	return "com.test.Path1"
+	return referenceTestPathDistinct
 }
 
-func TestServiceMap_Register(t *testing.T) {
+func TestServiceMapRegister(t *testing.T) {
 	// lowercase
 	s0 := &testService{}
 	// methods, err := ServiceMap.Register("testporotocol", s0)
-	_, err := ServiceMap.Register("testService", "testporotocol", s0)
+	_, err := ServiceMap.Register(testInterfaceName, "testporotocol", s0)
 	assert.EqualError(t, err, "type testService is not exported")
 
 	// succ
 	s := &TestService{}
-	methods, err := ServiceMap.Register("testService", "testporotocol", s)
+	methods, err := ServiceMap.Register(testInterfaceName, "testporotocol", s)
 	assert.NoError(t, err)
 	assert.Equal(t, "MethodOne,MethodThree,methodTwo", methods)
 
 	// repeat
-	_, err = ServiceMap.Register("testService", "testporotocol", s)
+	_, err = ServiceMap.Register(testInterfaceName, "testporotocol", s)
 	assert.EqualError(t, err, "service already defined: com.test.Path")
 
 	// no method
 	s1 := &TestService1{}
-	_, err = ServiceMap.Register("testService", "testporotocol", s1)
+	_, err = ServiceMap.Register(testInterfaceName, "testporotocol", s1)
 	assert.EqualError(t, err, "type com.test.Path1 has no exported methods of suitable type")
 
 	ServiceMap = &serviceMap{
@@ -101,28 +109,28 @@ func TestServiceMap_Register(t *testing.T) {
 	}
 }
 
-func TestServiceMap_UnRegister(t *testing.T) {
+func TestServiceMapUnRegister(t *testing.T) {
 	s := &TestService{}
-	_, err := ServiceMap.Register("TestService", "testprotocol", s)
+	_, err := ServiceMap.Register("TestService", testProtocol, s)
 	assert.NoError(t, err)
-	assert.NotNil(t, ServiceMap.GetService("testprotocol", "com.test.Path"))
+	assert.NotNil(t, ServiceMap.GetService(testProtocol, referenceTestPath))
 	assert.Equal(t, 1, len(ServiceMap.GetInterface("TestService")))
 
-	err = ServiceMap.UnRegister("", "", "com.test.Path")
+	err = ServiceMap.UnRegister("", "", referenceTestPath)
 	assert.EqualError(t, err, "protocol or serviceName is nil")
 
-	err = ServiceMap.UnRegister("", "protocol", "com.test.Path")
+	err = ServiceMap.UnRegister("", "protocol", referenceTestPath)
 	assert.EqualError(t, err, "no services for protocol")
 
-	err = ServiceMap.UnRegister("", "testprotocol", "com.test.Path1")
+	err = ServiceMap.UnRegister("", testProtocol, referenceTestPathDistinct)
 	assert.EqualError(t, err, "no service for com.test.Path1")
 
 	// succ
-	err = ServiceMap.UnRegister("TestService", "testprotocol", "com.test.Path")
+	err = ServiceMap.UnRegister("TestService", testProtocol, referenceTestPath)
 	assert.NoError(t, err)
 }
 
-func TestMethodType_SuiteContext(t *testing.T) {
+func TestMethodTypeSuiteContext(t *testing.T) {
 	mt := &MethodType{ctxType: reflect.TypeOf(context.TODO())}
 	ctx := context.WithValue(context.Background(), "key", "value")
 	assert.Equal(t, reflect.ValueOf(ctx), mt.SuiteContext(ctx))
@@ -139,9 +147,9 @@ func TestSuiteMethod(t *testing.T) {
 	method = methodType.Method()
 	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())
-	assert.Equal(t, "interface {}", at[2].String())
+	assert.Equal(t, testSuiteMethodExpectedString, at[0].String())
+	assert.Equal(t, testSuiteMethodExpectedString, at[1].String())
+	assert.Equal(t, testSuiteMethodExpectedString, at[2].String())
 	ct := methodType.CtxType()
 	assert.Equal(t, "context.Context", ct.String())
 	rt := methodType.ReplyType()
@@ -153,12 +161,12 @@ func TestSuiteMethod(t *testing.T) {
 	method = methodType.Method()
 	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())
-	assert.Equal(t, "interface {}", at[2].String())
+	assert.Equal(t, testSuiteMethodExpectedString, at[0].String())
+	assert.Equal(t, testSuiteMethodExpectedString, at[1].String())
+	assert.Equal(t, testSuiteMethodExpectedString, at[2].String())
 	assert.Nil(t, methodType.CtxType())
 	rt = methodType.ReplyType()
-	assert.Equal(t, "interface {}", rt.String())
+	assert.Equal(t, testSuiteMethodExpectedString, rt.String())
 
 	method, ok = reflect.TypeOf(s).MethodByName("MethodThree")
 	assert.True(t, ok)
diff --git a/common/url.go b/common/url.go
index ebb648db27c3efff534f0d0a545f2211f335aa89..983d1d798d048e33b18f68aee16b9b38febcf16b 100644
--- a/common/url.go
+++ b/common/url.go
@@ -18,7 +18,6 @@
 package common
 
 import (
-	"bytes"
 	"encoding/base64"
 	"fmt"
 	"math"
@@ -26,7 +25,6 @@ import (
 	"net/url"
 	"strconv"
 	"strings"
-	"sync"
 )
 
 import (
@@ -40,136 +38,141 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
-/////////////////////////////////
+// ///////////////////////////////
 // dubbo role type
-/////////////////////////////////
+// ///////////////////////////////
 
 // role constant
 const (
-	// CONSUMER ...
+	// CONSUMER is consumer role
 	CONSUMER = iota
-	// CONFIGURATOR ...
+	// CONFIGURATOR is configurator role
 	CONFIGURATOR
-	// ROUTER ...
+	// ROUTER is router role
 	ROUTER
-	// PROVIDER ...
+	// PROVIDER is provider role
 	PROVIDER
+	PROTOCOL = "protocol"
 )
 
 var (
-	// DubboNodes ...
+	// DubboNodes Dubbo service node
 	DubboNodes = [...]string{"consumers", "configurators", "routers", "providers"}
 	// DubboRole Dubbo service role
 	DubboRole = [...]string{"consumer", "", "routers", "provider"}
 )
 
-// RoleType ...
+// nolint
 type RoleType int
 
 func (t RoleType) String() string {
 	return DubboNodes[t]
 }
 
-// Role ...
+// Role returns role by @RoleType
 func (t RoleType) Role() string {
 	return DubboRole[t]
 }
 
 type baseUrl struct {
-	Protocol string
-	Location string // ip+port
-	Ip       string
-	Port     string
-	//url.Values is not safe map, add to avoid concurrent map read and map write error
-	paramsLock   sync.RWMutex
+	Protocol     string
+	Location     string // ip+port
+	Ip           string
+	Port         string
 	params       url.Values
 	PrimitiveURL string
 }
 
-// URL ...
+// URL is not thread-safe.
+// we fail to define this struct to be immutable object.
+// but, those method which will update the URL, including SetParam, SetParams
+// are only allowed to be invoked in creating URL instance
+// Please keep in mind that this struct is immutable after it has been created and initialized.
 type URL struct {
 	baseUrl
 	Path     string // like  /com.ikurento.dubbo.UserProvider3
 	Username string
 	Password string
 	Methods  []string
-	//special for registry
+	// special for registry
 	SubURL *URL
 }
 
+// Option accepts url
+// Option will define a function of handling URL
 type option func(*URL)
 
-// WithUsername ...
+// WithUsername sets username for url
 func WithUsername(username string) option {
 	return func(url *URL) {
 		url.Username = username
 	}
 }
 
-// WithPassword ...
+// WithPassword sets password for url
 func WithPassword(pwd string) option {
 	return func(url *URL) {
 		url.Password = pwd
 	}
 }
 
-// WithMethods ...
+// WithMethods sets methods for url
 func WithMethods(methods []string) option {
 	return func(url *URL) {
 		url.Methods = methods
 	}
 }
 
-// WithParams ...
+// WithParams sets params for url
 func WithParams(params url.Values) option {
 	return func(url *URL) {
 		url.params = params
 	}
 }
 
-// WithParamsValue ...
+// WithParamsValue sets params field for url
 func WithParamsValue(key, val string) option {
 	return func(url *URL) {
 		url.SetParam(key, val)
 	}
 }
 
-// WithProtocol ...
+// WithProtocol sets protocol for url
 func WithProtocol(proto string) option {
 	return func(url *URL) {
 		url.Protocol = proto
 	}
 }
 
-// WithIp ...
+// WithIp sets ip for url
 func WithIp(ip string) option {
 	return func(url *URL) {
 		url.Ip = ip
 	}
 }
 
-// WithPort ...
+// WithPort sets port for url
 func WithPort(port string) option {
 	return func(url *URL) {
 		url.Port = port
 	}
 }
 
-// WithPath ...
+// WithPath sets path for url
 func WithPath(path string) option {
 	return func(url *URL) {
 		url.Path = "/" + strings.TrimPrefix(path, "/")
 	}
 }
 
-// WithLocation ...
+// WithLocation sets location for url
 func WithLocation(location string) option {
 	return func(url *URL) {
 		url.Location = location
 	}
 }
 
-// WithToken ...
+// WithToken sets token for url
 func WithToken(token string) option {
 	return func(url *URL) {
 		if len(token) > 0 {
@@ -182,7 +185,7 @@ func WithToken(token string) option {
 	}
 }
 
-// NewURLWithOptions ...
+// NewURLWithOptions will create a new url with options
 func NewURLWithOptions(opts ...option) *URL {
 	url := &URL{}
 	for _, opt := range opts {
@@ -195,7 +198,6 @@ func NewURLWithOptions(opts ...option) *URL {
 // NewURL will create a new url
 // the urlString should not be empty
 func NewURL(urlString string, opts ...option) (URL, error) {
-
 	var (
 		err          error
 		rawUrlString string
@@ -213,7 +215,7 @@ func NewURL(urlString string, opts ...option) (URL, error) {
 		return s, perrors.Errorf("url.QueryUnescape(%s),  error{%v}", urlString, err)
 	}
 
-	//rawUrlString = "//" + rawUrlString
+	// rawUrlString = "//" + rawUrlString
 	if strings.Index(rawUrlString, "//") < 0 {
 		t := URL{baseUrl: baseUrl{}}
 		for _, opt := range opts {
@@ -249,7 +251,7 @@ func NewURL(urlString string, opts ...option) (URL, error) {
 	return s, nil
 }
 
-// URLEqual ...
+// URLEqual judge @url and @c is equal or not.
 func (c URL) URLEqual(url URL) bool {
 	c.Ip = ""
 	c.Port = ""
@@ -265,17 +267,19 @@ func (c URL) URLEqual(url URL) bool {
 	} else if urlGroup == constant.ANY_VALUE {
 		urlKey = strings.Replace(urlKey, "group=*", "group="+cGroup, 1)
 	}
+
+	// 1. protocol, username, password, ip, port, service name, group, version should be equal
 	if cKey != urlKey {
 		return false
 	}
+
+	// 2. if url contains enabled key, should be true, or *
 	if url.GetParam(constant.ENABLED_KEY, "true") != "true" && url.GetParam(constant.ENABLED_KEY, "") != constant.ANY_VALUE {
 		return false
 	}
-	//TODO :may need add interface key any value condition
-	if !isMatchCategory(url.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY), c.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY)) {
-		return false
-	}
-	return true
+
+	// TODO :may need add interface key any value condition
+	return isMatchCategory(url.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY), c.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY))
 }
 
 func isMatchCategory(category1 string, category2 string) bool {
@@ -291,38 +295,35 @@ func isMatchCategory(category1 string, category2 string) bool {
 }
 
 func (c URL) String() string {
-	var buildString string
+	var buf strings.Builder
 	if len(c.Username) == 0 && len(c.Password) == 0 {
-		buildString = fmt.Sprintf(
+		buf.WriteString(fmt.Sprintf(
 			"%s://%s:%s%s?",
-			c.Protocol, c.Ip, c.Port, c.Path)
+			c.Protocol, c.Ip, c.Port, c.Path))
 	} else {
-		buildString = fmt.Sprintf(
+		buf.WriteString(fmt.Sprintf(
 			"%s://%s:%s@%s:%s%s?",
-			c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Path)
+			c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Path))
 	}
-	c.paramsLock.RLock()
-	buildString += c.params.Encode()
-	c.paramsLock.RUnlock()
-	return buildString
+	buf.WriteString(c.params.Encode())
+	return buf.String()
 }
 
-// Key ...
+// Key gets key
 func (c URL) Key() string {
 	buildString := fmt.Sprintf(
 		"%s://%s:%s@%s:%s/?interface=%s&group=%s&version=%s",
 		c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Service(), c.GetParam(constant.GROUP_KEY, ""), c.GetParam(constant.VERSION_KEY, ""))
 	return buildString
-	//return c.ServiceKey()
 }
 
-// ServiceKey ...
+// ServiceKey gets a unique key of a service.
 func (c URL) ServiceKey() string {
 	intf := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
 	if intf == "" {
 		return ""
 	}
-	buf := &bytes.Buffer{}
+	var buf strings.Builder
 	group := c.GetParam(constant.GROUP_KEY, "")
 	if group != "" {
 		buf.WriteString(group)
@@ -347,7 +348,7 @@ func (c *URL) ColonSeparatedKey() string {
 	if intf == "" {
 		return ""
 	}
-	buf := &bytes.Buffer{}
+	var buf strings.Builder
 	buf.WriteString(intf)
 	buf.WriteString(":")
 	version := c.GetParam(constant.VERSION_KEY, "")
@@ -362,44 +363,44 @@ func (c *URL) ColonSeparatedKey() string {
 	return buf.String()
 }
 
-// EncodedServiceKey ...
+// EncodedServiceKey encode the service key
 func (c *URL) EncodedServiceKey() string {
 	serviceKey := c.ServiceKey()
 	return strings.Replace(serviceKey, "/", "*", 1)
 }
 
-// Service ...
+// Service gets service
 func (c URL) Service() string {
 	service := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
 	if service != "" {
 		return service
 	} else if c.SubURL != nil {
 		service = c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
-		if service != "" { //if url.path is "" then return suburl's path, special for registry url
+		if service != "" { // if url.path is "" then return suburl's path, special for registry url
 			return service
 		}
 	}
 	return ""
 }
 
-// AddParam ...
+// AddParam will add the key-value pair
+// Not thread-safe
+// think twice before using it.
 func (c *URL) AddParam(key string, value string) {
-	c.paramsLock.Lock()
 	c.params.Add(key, value)
-	c.paramsLock.Unlock()
 }
 
-// SetParam ...
+// SetParam will put the key-value pair into url
+// it's not thread safe.
+// think twice before you want to use this method
+// usually it should only be invoked when you want to initialized an url
 func (c *URL) SetParam(key string, value string) {
-	c.paramsLock.Lock()
 	c.params.Set(key, value)
-	c.paramsLock.Unlock()
 }
 
-// RangeParams ...
+// RangeParams will iterate the params
+// it's not thread-safe
 func (c *URL) RangeParams(f func(key, value string) bool) {
-	c.paramsLock.RLock()
-	defer c.paramsLock.RUnlock()
 	for k, v := range c.params {
 		if !f(k, v[0]) {
 			break
@@ -407,35 +408,31 @@ func (c *URL) RangeParams(f func(key, value string) bool) {
 	}
 }
 
-// GetParam ...
+// GetParam gets value by key
 func (c URL) GetParam(s string, d string) string {
-	var r string
-	c.paramsLock.RLock()
-	if r = c.params.Get(s); len(r) == 0 {
+	r := c.params.Get(s)
+	if len(r) == 0 {
 		r = d
 	}
-	c.paramsLock.RUnlock()
 	return r
 }
 
-// GetParams ...
+// GetParams gets values
 func (c URL) GetParams() url.Values {
 	return c.params
 }
 
-// GetParamAndDecoded ...
+// GetParamAndDecoded gets values and decode
 func (c URL) GetParamAndDecoded(key string) (string, error) {
-	c.paramsLock.RLock()
-	defer c.paramsLock.RUnlock()
 	ruleDec, err := base64.URLEncoding.DecodeString(c.GetParam(key, ""))
 	value := string(ruleDec)
 	return value, err
 }
 
-// GetRawParam ...
+// GetRawParam gets raw param
 func (c URL) GetRawParam(key string) string {
 	switch key {
-	case "protocol":
+	case PROTOCOL:
 		return c.Protocol
 	case "username":
 		return c.Username
@@ -452,76 +449,61 @@ func (c URL) GetRawParam(key string) string {
 	}
 }
 
-// GetParamBool ...
-func (c URL) GetParamBool(s string, d bool) bool {
-
-	var r bool
-	var err error
-	if r, err = strconv.ParseBool(c.GetParam(s, "")); err != nil {
+// GetParamBool judge whether @key exists or not
+func (c URL) GetParamBool(key string, d bool) bool {
+	r, err := strconv.ParseBool(c.GetParam(key, ""))
+	if err != nil {
 		return d
 	}
 	return r
 }
 
-// GetParamInt ...
-func (c URL) GetParamInt(s string, d int64) int64 {
-	var r int
-	var err error
-
-	if r, err = strconv.Atoi(c.GetParam(s, "")); r == 0 || err != nil {
+// GetParamInt gets int value by @key
+func (c URL) GetParamInt(key string, d int64) int64 {
+	r, err := strconv.Atoi(c.GetParam(key, ""))
+	if r == 0 || err != nil {
 		return d
 	}
 	return int64(r)
 }
 
-// GetMethodParamInt ...
+// GetMethodParamInt gets int method param
 func (c URL) GetMethodParamInt(method string, key string, d int64) int64 {
-	var r int
-	var err error
-	c.paramsLock.RLock()
-	defer c.paramsLock.RUnlock()
-	if r, err = strconv.Atoi(c.GetParam("methods."+method+"."+key, "")); r == 0 || err != nil {
+	r, err := strconv.Atoi(c.GetParam("methods."+method+"."+key, ""))
+	if r == 0 || err != nil {
 		return d
 	}
 	return int64(r)
 }
 
-// GetMethodParamInt64 ...
+// GetMethodParamInt64 gets int64 method param
 func (c URL) GetMethodParamInt64(method string, key string, d int64) int64 {
 	r := c.GetMethodParamInt(method, key, math.MinInt64)
 	if r == math.MinInt64 {
 		return c.GetParamInt(key, d)
 	}
-
 	return r
 }
 
-// GetMethodParam ...
+// GetMethodParam gets method param
 func (c URL) GetMethodParam(method string, key string, d string) string {
-	var r string
-	if r = c.GetParam("methods."+method+"."+key, ""); r == "" {
+	r := c.GetParam("methods."+method+"."+key, "")
+	if r == "" {
 		r = d
 	}
 	return r
 }
 
-// GetMethodParamBool ...
+// GetMethodParamBool judge whether @method param exists or not
 func (c URL) GetMethodParamBool(method string, key string, d bool) bool {
 	r := c.GetParamBool("methods."+method+"."+key, d)
 	return r
 }
 
-// RemoveParams ...
-func (c *URL) RemoveParams(set *gxset.HashSet) {
-	c.paramsLock.Lock()
-	defer c.paramsLock.Unlock()
-	for k := range set.Items {
-		s := k.(string)
-		delete(c.params, s)
-	}
-}
-
-// SetParams ...
+// SetParams will put all key-value pair into url.
+// 1. if there already has same key, the value will be override
+// 2. it's not thread safe
+// 3. think twice when you want to invoke this method
 func (c *URL) SetParams(m url.Values) {
 	for k := range m {
 		c.SetParam(k, m.Get(k))
@@ -530,7 +512,6 @@ func (c *URL) SetParams(m url.Values) {
 
 // ToMap transfer URL to Map
 func (c URL) ToMap() map[string]string {
-
 	paramsMap := make(map[string]string)
 
 	c.RangeParams(func(key, value string) bool {
@@ -539,7 +520,7 @@ func (c URL) ToMap() map[string]string {
 	})
 
 	if c.Protocol != "" {
-		paramsMap["protocol"] = c.Protocol
+		paramsMap[PROTOCOL] = c.Protocol
 	}
 	if c.Username != "" {
 		paramsMap["username"] = c.Username
@@ -558,7 +539,7 @@ func (c URL) ToMap() map[string]string {
 		paramsMap["port"] = port
 	}
 	if c.Protocol != "" {
-		paramsMap["protocol"] = c.Protocol
+		paramsMap[PROTOCOL] = c.Protocol
 	}
 	if c.Path != "" {
 		paramsMap["path"] = c.Path
@@ -571,29 +552,35 @@ func (c URL) ToMap() map[string]string {
 
 // configuration  > reference config >service config
 //  in this function we should merge the reference local url config into the service url from registry.
-//TODO configuration merge, in the future , the configuration center's config should merge too.
-
-// MergeUrl ...
+// TODO configuration merge, in the future , the configuration center's config should merge too.
+
+// MergeUrl will merge those two url
+// the result is based on serviceUrl, and the key which si only contained in referenceUrl
+// will be added into result.
+// for example, if serviceUrl contains params (a1->v1, b1->v2) and referenceUrl contains params(a2->v3, b1 -> v4)
+// the params of result will be (a1->v1, b1->v2, a2->v3).
+// You should notice that the value of b1 is v2, not v4.
+// due to URL is not thread-safe, so this method is not thread-safe
 func MergeUrl(serviceUrl *URL, referenceUrl *URL) *URL {
 	mergedUrl := serviceUrl.Clone()
 
-	//iterator the referenceUrl if serviceUrl not have the key ,merge in
+	// iterator the referenceUrl if serviceUrl not have the key ,merge in
 	referenceUrl.RangeParams(func(key, value string) bool {
 		if v := mergedUrl.GetParam(key, ""); len(v) == 0 {
 			mergedUrl.SetParam(key, value)
 		}
 		return true
 	})
-	//loadBalance,cluster,retries strategy config
+	// loadBalance,cluster,retries strategy config
 	methodConfigMergeFcn := mergeNormalParam(mergedUrl, referenceUrl, []string{constant.LOADBALANCE_KEY, constant.CLUSTER_KEY, constant.RETRIES_KEY, constant.TIMEOUT_KEY})
 
-	//remote timestamp
+	// remote timestamp
 	if v := serviceUrl.GetParam(constant.TIMESTAMP_KEY, ""); len(v) > 0 {
 		mergedUrl.SetParam(constant.REMOTE_TIMESTAMP_KEY, v)
 		mergedUrl.SetParam(constant.TIMESTAMP_KEY, referenceUrl.GetParam(constant.TIMESTAMP_KEY, ""))
 	}
 
-	//finally execute methodConfigMergeFcn
+	// finally execute methodConfigMergeFcn
 	for _, method := range referenceUrl.Methods {
 		for _, fcn := range methodConfigMergeFcn {
 			fcn("methods." + method)
@@ -603,7 +590,7 @@ func MergeUrl(serviceUrl *URL, referenceUrl *URL) *URL {
 	return mergedUrl
 }
 
-// Clone ...
+// Clone will copy the url
 func (c *URL) Clone() *URL {
 	newUrl := &URL{}
 	copier.Copy(newUrl, c)
@@ -615,8 +602,43 @@ func (c *URL) Clone() *URL {
 	return newUrl
 }
 
+func (c *URL) CloneExceptParams(excludeParams *gxset.HashSet) *URL {
+	newUrl := &URL{}
+	copier.Copy(newUrl, c)
+	newUrl.params = url.Values{}
+	c.RangeParams(func(key, value string) bool {
+		if !excludeParams.Contains(key) {
+			newUrl.SetParam(key, value)
+		}
+		return true
+	})
+	return newUrl
+}
+
+// Copy url based on the reserved parameter's keys.
+func (c *URL) CloneWithParams(reserveParams []string) *URL {
+	params := url.Values{}
+	for _, reserveParam := range reserveParams {
+		v := c.GetParam(reserveParam, "")
+		if len(v) != 0 {
+			params.Set(reserveParam, v)
+		}
+	}
+
+	return NewURLWithOptions(
+		WithProtocol(c.Protocol),
+		WithUsername(c.Username),
+		WithPassword(c.Password),
+		WithIp(c.Ip),
+		WithPort(c.Port),
+		WithPath(c.Path),
+		WithMethods(c.Methods),
+		WithParams(params),
+	)
+}
+
 func mergeNormalParam(mergedUrl *URL, referenceUrl *URL, paramKeys []string) []func(method string) {
-	var methodConfigMergeFcn = []func(method string){}
+	methodConfigMergeFcn := make([]func(method string), 0, len(paramKeys))
 	for _, paramKey := range paramKeys {
 		if v := referenceUrl.GetParam(paramKey, ""); len(v) > 0 {
 			mergedUrl.SetParam(paramKey, v)
diff --git a/common/url_test.go b/common/url_test.go
index 2372de520e88b0949023e88cec64871736dd6aa0..6845190a7362571ebbd4738bd146c94f6d644253 100644
--- a/common/url_test.go
+++ b/common/url_test.go
@@ -31,24 +31,30 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
+const (
+	userName        = "username"
+	password        = "password"
+	loopbackAddress = "127.0.0.1"
+)
+
 func TestNewURLWithOptions(t *testing.T) {
 	methods := []string{"Methodone,methodtwo"}
 	params := url.Values{}
 	params.Set("key", "value")
 	u := NewURLWithOptions(WithPath("com.test.Service"),
-		WithUsername("username"),
-		WithPassword("password"),
+		WithUsername(userName),
+		WithPassword(password),
 		WithProtocol("testprotocol"),
-		WithIp("127.0.0.1"),
+		WithIp(loopbackAddress),
 		WithPort("8080"),
 		WithMethods(methods),
 		WithParams(params),
 		WithParamsValue("key2", "value2"))
 	assert.Equal(t, "/com.test.Service", u.Path)
-	assert.Equal(t, "username", u.Username)
-	assert.Equal(t, "password", u.Password)
+	assert.Equal(t, userName, u.Username)
+	assert.Equal(t, password, u.Password)
 	assert.Equal(t, "testprotocol", u.Protocol)
-	assert.Equal(t, "127.0.0.1", u.Ip)
+	assert.Equal(t, loopbackAddress, u.Ip)
 	assert.Equal(t, "8080", u.Port)
 	assert.Equal(t, methods, u.Methods)
 	assert.Equal(t, params, u.params)
@@ -65,7 +71,7 @@ func TestURL(t *testing.T) {
 	assert.Equal(t, "/com.ikurento.user.UserProvider", u.Path)
 	assert.Equal(t, "127.0.0.1:20000", u.Location)
 	assert.Equal(t, "dubbo", u.Protocol)
-	assert.Equal(t, "127.0.0.1", u.Ip)
+	assert.Equal(t, loopbackAddress, u.Ip)
 	assert.Equal(t, "20000", u.Port)
 	assert.Equal(t, URL{}.Methods, u.Methods)
 	assert.Equal(t, "", u.Username)
@@ -92,7 +98,7 @@ func TestURLWithoutSchema(t *testing.T) {
 	assert.Equal(t, "/com.ikurento.user.UserProvider", u.Path)
 	assert.Equal(t, "127.0.0.1:20000", u.Location)
 	assert.Equal(t, "dubbo", u.Protocol)
-	assert.Equal(t, "127.0.0.1", u.Ip)
+	assert.Equal(t, loopbackAddress, u.Ip)
 	assert.Equal(t, "20000", u.Port)
 	assert.Equal(t, URL{}.Methods, u.Methods)
 	assert.Equal(t, "", u.Username)
@@ -108,7 +114,7 @@ func TestURLWithoutSchema(t *testing.T) {
 		"ZX&pid=1447&revision=0.0.1&side=provider&timeout=3000&timestamp=1556509797245", u.String())
 }
 
-func TestURL_URLEqual(t *testing.T) {
+func TestURLEqual(t *testing.T) {
 	u1, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
 	assert.NoError(t, err)
 	u2, err := NewURL("dubbo://127.0.0.2:20001/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
@@ -118,9 +124,36 @@ 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) {
+func TestURLGetParam(t *testing.T) {
 	params := url.Values{}
 	params.Set("key", "value")
 	u := URL{baseUrl: baseUrl{params: params}}
@@ -132,7 +165,7 @@ func TestURL_GetParam(t *testing.T) {
 	assert.Equal(t, "default", v)
 }
 
-func TestURL_GetParamInt(t *testing.T) {
+func TestURLGetParamInt(t *testing.T) {
 	params := url.Values{}
 	params.Set("key", "3")
 	u := URL{baseUrl: baseUrl{params: params}}
@@ -144,7 +177,7 @@ func TestURL_GetParamInt(t *testing.T) {
 	assert.Equal(t, int64(1), v)
 }
 
-func TestURL_GetParamBool(t *testing.T) {
+func TestURLGetParamBool(t *testing.T) {
 	params := url.Values{}
 	params.Set("force", "true")
 	u := URL{baseUrl: baseUrl{params: params}}
@@ -156,7 +189,7 @@ func TestURL_GetParamBool(t *testing.T) {
 	assert.Equal(t, false, v)
 }
 
-func TestURL_GetParamAndDecoded(t *testing.T) {
+func TestURLGetParamAndDecoded(t *testing.T) {
 	rule := "host = 2.2.2.2,1.1.1.1,3.3.3.3 & host !=1.1.1.1 => host = 1.2.3.4"
 	params := url.Values{}
 	params.Set("rule", base64.URLEncoding.EncodeToString([]byte(rule)))
@@ -165,20 +198,20 @@ func TestURL_GetParamAndDecoded(t *testing.T) {
 	assert.Equal(t, rule, v)
 }
 
-func TestURL_GetRawParam(t *testing.T) {
+func TestURLGetRawParam(t *testing.T) {
 	u, _ := NewURL("condition://0.0.0.0:8080/com.foo.BarService?serialization=fastjson")
 	u.Username = "test"
 	u.Password = "test"
 	assert.Equal(t, "condition", u.GetRawParam("protocol"))
 	assert.Equal(t, "0.0.0.0", u.GetRawParam("host"))
 	assert.Equal(t, "8080", u.GetRawParam("port"))
-	assert.Equal(t, "test", u.GetRawParam("username"))
-	assert.Equal(t, "test", u.GetRawParam("password"))
+	assert.Equal(t, "test", u.GetRawParam(userName))
+	assert.Equal(t, "test", u.GetRawParam(password))
 	assert.Equal(t, "/com.foo.BarService", u.GetRawParam("path"))
 	assert.Equal(t, "fastjson", u.GetRawParam("serialization"))
 }
 
-func TestURL_ToMap(t *testing.T) {
+func TestURLToMap(t *testing.T) {
 	u, _ := NewURL("condition://0.0.0.0:8080/com.foo.BarService?serialization=fastjson")
 	u.Username = "test"
 	u.Password = "test"
@@ -188,13 +221,13 @@ func TestURL_ToMap(t *testing.T) {
 	assert.Equal(t, "condition", m["protocol"])
 	assert.Equal(t, "0.0.0.0", m["host"])
 	assert.Equal(t, "8080", m["port"])
-	assert.Equal(t, "test", m["username"])
-	assert.Equal(t, "test", m["password"])
+	assert.Equal(t, "test", m[userName])
+	assert.Equal(t, "test", m[password])
 	assert.Equal(t, "/com.foo.BarService", m["path"])
 	assert.Equal(t, "fastjson", m["serialization"])
 }
 
-func TestURL_GetMethodParamInt(t *testing.T) {
+func TestURLGetMethodParamInt(t *testing.T) {
 	params := url.Values{}
 	params.Set("methods.GetValue.timeout", "3")
 	u := URL{baseUrl: baseUrl{params: params}}
@@ -206,7 +239,7 @@ func TestURL_GetMethodParamInt(t *testing.T) {
 	assert.Equal(t, int64(1), v)
 }
 
-func TestURL_GetMethodParam(t *testing.T) {
+func TestURLGetMethodParam(t *testing.T) {
 	params := url.Values{}
 	params.Set("methods.GetValue.timeout", "3s")
 	u := URL{baseUrl: baseUrl{params: params}}
@@ -218,7 +251,7 @@ func TestURL_GetMethodParam(t *testing.T) {
 	assert.Equal(t, "1s", v)
 }
 
-func TestURL_GetMethodParamBool(t *testing.T) {
+func TestURLGetMethodParamBool(t *testing.T) {
 	params := url.Values{}
 	params.Set("methods.GetValue.async", "true")
 	u := URL{baseUrl: baseUrl{params: params}}
@@ -252,7 +285,7 @@ func TestMergeUrl(t *testing.T) {
 	assert.Equal(t, "2", mergedUrl.GetParam(constant.METHOD_KEYS+".testMethod."+constant.RETRIES_KEY, ""))
 }
 
-func TestURL_SetParams(t *testing.T) {
+func TestURLSetParams(t *testing.T) {
 	u1, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&configVersion=1.0")
 	assert.NoError(t, err)
 	params := url.Values{}
diff --git a/common/yaml/yaml.go b/common/yaml/yaml.go
index 93ebb166144510236aff27a67422a6377ccb5c9f..5edda1b3c7751e8171528d121148b6c3c60fe128 100644
--- a/common/yaml/yaml.go
+++ b/common/yaml/yaml.go
@@ -40,7 +40,7 @@ func LoadYMLConfig(confProFile string) ([]byte, error) {
 	return ioutil.ReadFile(confProFile)
 }
 
-// unmarshalYMLConfig Load yml config byte from file , then unmarshal to object
+// unmarshalYMLConfig Load yml config byte from file, then unmarshal to object
 func UnmarshalYMLConfig(confProFile string, out interface{}) ([]byte, error) {
 	confFileStream, err := LoadYMLConfig(confProFile)
 	if err != nil {
diff --git a/common/yaml/yaml_test.go b/common/yaml/yaml_test.go
index c8b8258a68951a1437ac2e617c13ee5af4b3a5ee..5a271a25823f576cb9cdb10c657520bbf5666017 100644
--- a/common/yaml/yaml_test.go
+++ b/common/yaml/yaml_test.go
@@ -38,7 +38,7 @@ func TestUnmarshalYMLConfig(t *testing.T) {
 	assert.Equal(t, "childStrTest", c.ChildConfig.StrTest)
 }
 
-func TestUnmarshalYMLConfig_Error(t *testing.T) {
+func TestUnmarshalYMLConfigError(t *testing.T) {
 	c := &Config{}
 	_, err := UnmarshalYMLConfig("./testdata/config", c)
 	assert.Error(t, err)
diff --git a/config/application_config.go b/config/application_config.go
index 33b47c81dd0da9959984cd1f53648167863cb713..16e841792c7bffaa6f847d73c336c6a43431bc49 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"`
@@ -36,22 +36,12 @@ type ApplicationConfig struct {
 	MetadataType string `default:"local" yaml:"metadataType" json:"metadataType,omitempty" property:"metadataType"` //field for metadata report
 }
 
-// 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 93c0ce6a6692193e7ea7b1b9f2f74e9eaed0c858..fd749a934b8344a5ed00343f1b18f10bc41fd820 100644
--- a/config/base_config.go
+++ b/config/base_config.go
@@ -69,7 +69,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)
@@ -125,20 +124,20 @@ func getKeyPrefix(val reflect.Value) []string {
 	var (
 		prefix string
 	)
-
+	configPrefixMethod := "Prefix"
 	if val.CanAddr() {
-		prefix = val.Addr().MethodByName("Prefix").Call(nil)[0].String()
+		prefix = val.Addr().MethodByName(configPrefixMethod).Call(nil)[0].String()
 	} else {
-		prefix = val.MethodByName("Prefix").Call(nil)[0].String()
+		prefix = val.MethodByName(configPrefixMethod).Call(nil)[0].String()
 	}
-	var retPrefixs []string
+	var retPrefixes []string
 
 	for _, pfx := range strings.Split(prefix, "|") {
 
-		retPrefixs = append(retPrefixs, pfx)
+		retPrefixes = append(retPrefixes, pfx)
 
 	}
-	return retPrefixs
+	return retPrefixes
 
 }
 
@@ -165,13 +164,13 @@ func setFieldValue(val reflect.Value, id reflect.Value, config *config.InmemoryC
 						idStr string
 					)
 
-					prefixs := getKeyPrefix(val)
+					prefixes := getKeyPrefix(val)
 
 					if id.Kind() == reflect.String {
 						idStr = id.Interface().(string)
 					}
 
-					for _, pfx := range prefixs {
+					for _, pfx := range prefixes {
 
 						if len(pfx) > 0 {
 							if len(idStr) > 0 {
@@ -191,18 +190,20 @@ func setFieldValue(val reflect.Value, id reflect.Value, config *config.InmemoryC
 
 					}
 					if ok {
+						errMsg := func(structName string, fieldName string, errorDetails error) {
+							logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
+								structName, fieldName, errorDetails)
+						}
 						switch f.Kind() {
 						case reflect.Int64:
 							x, err := strconv.Atoi(value)
 							if err != nil {
-								logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
-									val.Type().Name(), val.Type().Field(i).Name, err)
+								errMsg(val.Type().Name(), val.Type().Field(i).Name, err)
 							} else {
 								if !f.OverflowInt(int64(x)) {
 									f.SetInt(int64(x))
 								} else {
-									logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
-										val.Type().Name(), val.Type().Field(i).Name, perrors.Errorf("the int64 value {%v} from config center is  overflow", int64(x)))
+									errMsg(val.Type().Name(), val.Type().Field(i).Name, perrors.Errorf("the int64 value {%v} from config center is  overflow", int64(x)))
 								}
 							}
 						case reflect.String:
@@ -210,21 +211,18 @@ func setFieldValue(val reflect.Value, id reflect.Value, config *config.InmemoryC
 						case reflect.Bool:
 							x, err := strconv.ParseBool(value)
 							if err != nil {
-								logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
-									val.Type().Name(), val.Type().Field(i).Name, err)
+								errMsg(val.Type().Name(), val.Type().Field(i).Name, err)
 							}
 							f.SetBool(x)
 						case reflect.Float64:
 							x, err := strconv.ParseFloat(value, 64)
 							if err != nil {
-								logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
-									val.Type().Name(), val.Type().Field(i).Name, err)
+								errMsg(val.Type().Name(), val.Type().Field(i).Name, err)
 							} else {
 								if !f.OverflowFloat(x) {
 									f.SetFloat(x)
 								} else {
-									logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
-										val.Type().Name(), val.Type().Field(i).Name, perrors.Errorf("the float64 value {%v} from config center is  overflow", x))
+									errMsg(val.Type().Name(), val.Type().Field(i).Name, perrors.Errorf("the float64 value {%v} from config center is  overflow", x))
 								}
 							}
 						default:
@@ -323,45 +321,46 @@ 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
 }
 
 func initializeStruct(t reflect.Type, v reflect.Value) {
-	if v.Kind() == reflect.Struct {
-		for i := 0; i < v.NumField(); i++ {
-			f := v.Field(i)
-			ft := t.Field(i)
-
-			if ft.Tag.Get("property") != "" {
-				switch ft.Type.Kind() {
-				case reflect.Map:
-					if f.IsNil() {
-						f.Set(reflect.MakeMap(ft.Type))
-					}
-				case reflect.Slice:
-					if f.IsNil() {
-						f.Set(reflect.MakeSlice(ft.Type, 0, 0))
-					}
-				case reflect.Chan:
-					if f.IsNil() {
-						f.Set(reflect.MakeChan(ft.Type, 0))
-					}
-				case reflect.Struct:
-					if f.IsNil() {
-						initializeStruct(ft.Type, f)
-					}
-				case reflect.Ptr:
-					if f.IsNil() {
-						fv := reflect.New(ft.Type.Elem())
-						initializeStruct(ft.Type.Elem(), fv.Elem())
-						f.Set(fv)
-					}
-				default:
-				}
-			}
+	if v.Kind() != reflect.Struct {
+		return
+	}
+	for i := 0; i < v.NumField(); i++ {
+		f := v.Field(i)
+		ft := t.Field(i)
 
+		if ft.Tag.Get("property") == "" {
+			continue
+		}
+		switch ft.Type.Kind() {
+		case reflect.Map:
+			if f.IsNil() {
+				f.Set(reflect.MakeMap(ft.Type))
+			}
+		case reflect.Slice:
+			if f.IsNil() {
+				f.Set(reflect.MakeSlice(ft.Type, 0, 0))
+			}
+		case reflect.Chan:
+			if f.IsNil() {
+				f.Set(reflect.MakeChan(ft.Type, 0))
+			}
+		case reflect.Struct:
+			if f.IsNil() {
+				initializeStruct(ft.Type, f)
+			}
+		case reflect.Ptr:
+			if f.IsNil() {
+				fv := reflect.New(ft.Type.Elem())
+				initializeStruct(ft.Type.Elem(), fv.Elem())
+				f.Set(fv)
+			}
+		default:
 		}
 	}
 }
diff --git a/config/base_config_test.go b/config/base_config_test.go
index d16b2420922ece60ef2135729cd47d5aa73a3760..ca2875fb95e9bdabcc430edc15bd4a56c440bc45 100644
--- a/config/base_config_test.go
+++ b/config/base_config_test.go
@@ -21,9 +21,11 @@ import (
 	"reflect"
 	"testing"
 )
+
 import (
 	"github.com/stretchr/testify/assert"
 )
+
 import (
 	"github.com/apache/dubbo-go/common/config"
 	"github.com/apache/dubbo-go/common/extension"
@@ -31,89 +33,93 @@ import (
 	_ "github.com/apache/dubbo-go/config_center/apollo"
 )
 
-func Test_refresh(t *testing.T) {
-	c := &BaseConfig{}
-	mockMap := map[string]string{}
-	mockMap["dubbo.registries.shanghai_reg1.protocol"] = "mock100"
-	mockMap["dubbo.reference.com.MockService.MockService.retries"] = "10"
-	mockMap["dubbo.com.MockService.MockService.GetUser.retries"] = "10"
-	mockMap["dubbo.consumer.check"] = "false"
-	mockMap["dubbo.application.name"] = "dubbo"
-	mockMap["dubbo.shutdown.timeout"] = "12s"
+func getMockMap() map[string]string {
+	baseMockMap := map[string]string{
+		"dubbo.registries.shanghai_reg1.protocol":             "mock100",
+		"dubbo.reference.com.MockService.MockService.retries": "10",
+		"dubbo.com.MockService.MockService.GetUser.retries":   "10",
+		"dubbo.consumer.check":                                "false",
+		"dubbo.application.name":                              "dubbo",
+	}
+	return baseMockMap
+}
 
-	config.GetEnvInstance().UpdateExternalConfigMap(mockMap)
+var baseAppConfig = &ApplicationConfig{
+	Organization: "dubbo_org",
+	Name:         "dubbo",
+	Module:       "module",
+	Version:      "2.6.0",
+	Owner:        "dubbo",
+	Environment:  "test",
+}
 
-	father := &ConsumerConfig{
-		Check: &[]bool{true}[0],
-		ApplicationConfig: &ApplicationConfig{
-			Organization: "dubbo_org",
-			Name:         "dubbo",
-			Module:       "module",
-			Version:      "2.6.0",
-			Owner:        "dubbo",
-			Environment:  "test"},
-		Registries: map[string]*RegistryConfig{
-			//"shanghai_reg1": {
-			//	id:         "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",
+var baseRegistries = map[string]*RegistryConfig{
+	"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",
+	},
+}
+
+var baseMockRef = map[string]*ReferenceConfig{
+	"MockService": {
+		InterfaceName: "com.MockService",
+		Protocol:      "mock",
+		Cluster:       "failover",
+		Loadbalance:   "random",
+		Retries:       "3",
+		Group:         "huadong_idc",
+		Version:       "1.0.0",
+		Methods: []*MethodConfig{
+			{
+				InterfaceId:   "MockService",
+				InterfaceName: "com.MockService",
+				Name:          "GetUser",
+				Retries:       "2",
+				Loadbalance:   "random",
 			},
-		},
-		References: map[string]*ReferenceConfig{
-			"MockService": {
+			{
+				InterfaceId:   "MockService",
 				InterfaceName: "com.MockService",
-				Protocol:      "mock",
-				Cluster:       "failover",
+				Name:          "GetUser1",
+				Retries:       "2",
 				Loadbalance:   "random",
-				Retries:       "3",
-				Group:         "huadong_idc",
-				Version:       "1.0.0",
-				Methods: []*MethodConfig{
-					{
-						InterfaceId:   "MockService",
-						InterfaceName: "com.MockService",
-						Name:          "GetUser",
-						Retries:       "2",
-						Loadbalance:   "random",
-					},
-					{
-						InterfaceId:   "MockService",
-						InterfaceName: "com.MockService",
-						Name:          "GetUser1",
-						Retries:       "2",
-						Loadbalance:   "random",
-					},
-				},
 			},
 		},
+	},
+}
+
+func TestRefresh(t *testing.T) {
+	c := &BaseConfig{}
+	mockMap := getMockMap()
+	mockMap["dubbo.shutdown.timeout"] = "12s"
+
+	config.GetEnvInstance().UpdateExternalConfigMap(mockMap)
+
+	father := &ConsumerConfig{
+		Check:             &[]bool{true}[0],
+		ApplicationConfig: baseAppConfig,
+		Registries:        baseRegistries,
+		References:        baseMockRef,
 		ShutdownConfig: &ShutdownConfig{
 			Timeout:              "12s",
 			StepTimeout:          "2s",
@@ -133,90 +139,19 @@ func Test_refresh(t *testing.T) {
 	assert.Equal(t, "dubbo", father.ApplicationConfig.Name)
 }
 
-func Test_appExternal_refresh(t *testing.T) {
+func TestAppExternalRefresh(t *testing.T) {
 	c := &BaseConfig{}
-	mockMap := map[string]string{}
-	mockMap["dubbo.registries.shanghai_reg1.protocol"] = "mock100"
-	mockMap["dubbo.reference.com.MockService.MockService.retries"] = "10"
+	mockMap := getMockMap()
 	mockMap["dubbo.reference.com.MockService.retries"] = "5"
-	mockMap["dubbo.com.MockService.MockService.GetUser.retries"] = "10"
-	mockMap["dubbo.consumer.check"] = "false"
-	mockMap["dubbo.application.name"] = "dubbo"
 
 	config.GetEnvInstance().UpdateAppExternalConfigMap(mockMap)
 	mockMap["dubbo.consumer.check"] = "true"
 	config.GetEnvInstance().UpdateExternalConfigMap(mockMap)
 	father := &ConsumerConfig{
-		Check: &[]bool{true}[0],
-		ApplicationConfig: &ApplicationConfig{
-			Organization: "dubbo_org",
-			Name:         "dubbo",
-			Module:       "module",
-			Version:      "2.6.0",
-			Owner:        "dubbo",
-			Environment:  "test"},
-		Registries: map[string]*RegistryConfig{
-			//"shanghai_reg1": {
-			//	id:         "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",
-			},
-		},
-		References: map[string]*ReferenceConfig{
-			"MockService": {
-				InterfaceName: "com.MockService",
-				Protocol:      "mock",
-				Cluster:       "failover",
-				Loadbalance:   "random",
-				Retries:       "3",
-				Group:         "huadong_idc",
-				Version:       "1.0.0",
-				Methods: []*MethodConfig{
-					{
-						InterfaceId:   "MockService",
-						InterfaceName: "com.MockService",
-						Name:          "GetUser",
-						Retries:       "2",
-						Loadbalance:   "random",
-					},
-					{
-						InterfaceId:   "MockService",
-						InterfaceName: "com.MockService",
-						Name:          "GetUser1",
-						Retries:       "2",
-						Loadbalance:   "random",
-					},
-				},
-			},
-		},
+		Check:             &[]bool{true}[0],
+		ApplicationConfig: baseAppConfig,
+		Registries:        baseRegistries,
+		References:        baseMockRef,
 	}
 
 	c.SetFatherConfig(father)
@@ -229,89 +164,20 @@ func Test_appExternal_refresh(t *testing.T) {
 	assert.Equal(t, "dubbo", father.ApplicationConfig.Name)
 }
 
-func Test_appExternalWithoutId_refresh(t *testing.T) {
+func TestAppExternalWithoutIDRefresh(t *testing.T) {
 	c := &BaseConfig{}
-	mockMap := map[string]string{}
-	mockMap["dubbo.registries.shanghai_reg1.protocol"] = "mock100"
+	mockMap := getMockMap()
+	delete(mockMap, "dubbo.reference.com.MockService.MockService.retries")
 	mockMap["dubbo.reference.com.MockService.retries"] = "10"
-	mockMap["dubbo.com.MockService.MockService.GetUser.retries"] = "10"
-	mockMap["dubbo.consumer.check"] = "false"
-	mockMap["dubbo.application.name"] = "dubbo"
 
 	config.GetEnvInstance().UpdateAppExternalConfigMap(mockMap)
 	mockMap["dubbo.consumer.check"] = "true"
 	config.GetEnvInstance().UpdateExternalConfigMap(mockMap)
 	father := &ConsumerConfig{
-		Check: &[]bool{true}[0],
-		ApplicationConfig: &ApplicationConfig{
-			Organization: "dubbo_org",
-			Name:         "dubbo",
-			Module:       "module",
-			Version:      "2.6.0",
-			Owner:        "dubbo",
-			Environment:  "test"},
-		Registries: map[string]*RegistryConfig{
-			//"shanghai_reg1": {
-			//	id:         "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",
-			},
-		},
-		References: map[string]*ReferenceConfig{
-			"MockService": {
-				InterfaceName: "com.MockService",
-				Protocol:      "mock",
-				Cluster:       "failover",
-				Loadbalance:   "random",
-				Retries:       "3",
-				Group:         "huadong_idc",
-				Version:       "1.0.0",
-				Methods: []*MethodConfig{
-					{
-						InterfaceId:   "MockService",
-						InterfaceName: "com.MockService",
-						Name:          "GetUser",
-						Retries:       "3",
-						Loadbalance:   "random",
-					},
-					{
-						InterfaceId:   "MockService",
-						InterfaceName: "com.MockService",
-						Name:          "GetUser1",
-						Retries:       "2",
-						Loadbalance:   "random",
-					},
-				},
-			},
-		},
+		Check:             &[]bool{true}[0],
+		ApplicationConfig: baseAppConfig,
+		Registries:        baseRegistries,
+		References:        baseMockRef,
 	}
 
 	c.SetFatherConfig(father)
@@ -324,7 +190,7 @@ func Test_appExternalWithoutId_refresh(t *testing.T) {
 	assert.Equal(t, "dubbo", father.ApplicationConfig.Name)
 }
 
-func Test_refresh_singleRegistry(t *testing.T) {
+func TestRefreshSingleRegistry(t *testing.T) {
 	c := &BaseConfig{}
 	mockMap := map[string]string{}
 	mockMap["dubbo.registry.address"] = "mock100://127.0.0.1:2181"
@@ -336,43 +202,11 @@ func Test_refresh_singleRegistry(t *testing.T) {
 	config.GetEnvInstance().UpdateExternalConfigMap(mockMap)
 
 	father := &ConsumerConfig{
-		Check: &[]bool{true}[0],
-		ApplicationConfig: &ApplicationConfig{
-			Organization: "dubbo_org",
-			Name:         "dubbo",
-			Module:       "module",
-			Version:      "2.6.0",
-			Owner:        "dubbo",
-			Environment:  "test"},
-		Registries: map[string]*RegistryConfig{},
-		Registry:   &RegistryConfig{},
-		References: map[string]*ReferenceConfig{
-			"MockService": {
-				InterfaceName: "com.MockService",
-				Protocol:      "mock",
-				Cluster:       "failover",
-				Loadbalance:   "random",
-				Retries:       "3",
-				Group:         "huadong_idc",
-				Version:       "1.0.0",
-				Methods: []*MethodConfig{
-					{
-						InterfaceId:   "MockService",
-						InterfaceName: "com.MockService",
-						Name:          "GetUser",
-						Retries:       "2",
-						Loadbalance:   "random",
-					},
-					{
-						InterfaceId:   "MockService",
-						InterfaceName: "com.MockService",
-						Name:          "GetUser1",
-						Retries:       "2",
-						Loadbalance:   "random",
-					},
-				},
-			},
-		},
+		Check:             &[]bool{true}[0],
+		ApplicationConfig: baseAppConfig,
+		Registries:        map[string]*RegistryConfig{},
+		Registry:          &RegistryConfig{},
+		References:        baseMockRef,
 	}
 
 	c.SetFatherConfig(father)
@@ -385,14 +219,11 @@ func Test_refresh_singleRegistry(t *testing.T) {
 	assert.Equal(t, "dubbo", father.ApplicationConfig.Name)
 }
 
-func Test_refreshProvider(t *testing.T) {
+func TestRefreshProvider(t *testing.T) {
 	c := &BaseConfig{}
-	mockMap := map[string]string{}
-	mockMap["dubbo.registries.shanghai_reg1.protocol"] = "mock100"
+	mockMap := getMockMap()
+	delete(mockMap, "dubbo.reference.com.MockService.MockService.retries")
 	mockMap["dubbo.service.com.MockService.MockService.retries"] = "10"
-	mockMap["dubbo.com.MockService.MockService.GetUser.retries"] = "10"
-	mockMap["dubbo.consumer.check"] = "false"
-	mockMap["dubbo.application.name"] = "dubbo"
 	mockMap["dubbo.protocols.jsonrpc1.name"] = "jsonrpc"
 	mockMap["dubbo.protocols.jsonrpc1.ip"] = "127.0.0.1"
 	mockMap["dubbo.protocols.jsonrpc1.port"] = "20001"
@@ -400,48 +231,8 @@ func Test_refreshProvider(t *testing.T) {
 	config.GetEnvInstance().UpdateExternalConfigMap(mockMap)
 
 	father := &ProviderConfig{
-		ApplicationConfig: &ApplicationConfig{
-			Organization: "dubbo_org",
-			Name:         "dubbo",
-			Module:       "module",
-			Version:      "2.6.0",
-			Owner:        "dubbo",
-			Environment:  "test"},
-		Registries: map[string]*RegistryConfig{
-			//"shanghai_reg1": {
-			//	id:         "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",
-			},
-		},
+		ApplicationConfig: baseAppConfig,
+		Registries:        baseRegistries,
 		Services: map[string]*ServiceConfig{
 			"MockService": {
 				InterfaceName: "com.MockService",
@@ -459,7 +250,8 @@ func Test_refreshProvider(t *testing.T) {
 						Retries:       "2",
 						Loadbalance:   "random",
 					},
-					{InterfaceId: "MockService",
+					{
+						InterfaceId:   "MockService",
 						InterfaceName: "com.MockService",
 						Name:          "GetUser1",
 						Retries:       "2",
@@ -480,8 +272,7 @@ func Test_refreshProvider(t *testing.T) {
 	assert.Equal(t, "20001", father.Protocols["jsonrpc1"].Port)
 }
 
-func Test_startConfigCenter(t *testing.T) {
-
+func TestStartConfigCenter(t *testing.T) {
 	extension.SetConfigCenterFactory("mock", func() config_center.DynamicConfigurationFactory {
 		return &config_center.MockDynamicConfigurationFactory{}
 	})
@@ -498,22 +289,22 @@ func Test_startConfigCenter(t *testing.T) {
 	assert.Equal(t, "ikurento.com", v)
 }
 
-func Test_initializeStruct(t *testing.T) {
-	consumerConfig := &ConsumerConfig{}
+func TestInitializeStruct(t *testing.T) {
+	testConsumerConfig := &ConsumerConfig{}
 	tp := reflect.TypeOf(ConsumerConfig{})
 	v := reflect.New(tp)
 	initializeStruct(tp, v.Elem())
-	fmt.Println(reflect.ValueOf(consumerConfig).Elem().Type().String())
+	fmt.Println(reflect.ValueOf(testConsumerConfig).Elem().Type().String())
 	fmt.Println(v.Elem().Type().String())
-	reflect.ValueOf(consumerConfig).Elem().Set(v.Elem())
+	reflect.ValueOf(testConsumerConfig).Elem().Set(v.Elem())
 
 	assert.Condition(t, func() (success bool) {
-		return consumerConfig.ApplicationConfig != nil
+		return testConsumerConfig.ApplicationConfig != nil
 	})
 	assert.Condition(t, func() (success bool) {
-		return consumerConfig.Registries != nil
+		return testConsumerConfig.Registries != nil
 	})
 	assert.Condition(t, func() (success bool) {
-		return consumerConfig.References != nil
+		return testConsumerConfig.References != nil
 	})
 }
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 61cb49457b7a2435cb22f02a9df0a02a71ae68cb..f8f83533d4796cc6df3e2d4c2d77f42be56e5933 100644
--- a/config/config_loader.go
+++ b/config/config_loader.go
@@ -81,128 +81,142 @@ func checkApplicationName(config *ApplicationConfig) {
 	}
 }
 
-// Load Dubbo Init
-func Load() {
-
-	// init router
-	if confRouterFile != "" {
-		if errPro := RouterInit(confRouterFile); errPro != nil {
-			log.Printf("[routerConfig init] %#v", errPro)
-		}
-	}
-
-	// reference config
+func loadConsumerConfig() {
 	if consumerConfig == nil {
 		logger.Warnf("consumerConfig is nil!")
-	} else {
-		// init other consumer config
-		conConfigType := consumerConfig.ConfigType
-		for key, value := range extension.GetDefaultConfigReader() {
-			if conConfigType == nil {
-				if v, ok := conConfigType[key]; ok {
-					value = v
-				}
-			}
-			if err := extension.GetConfigReaders(value).ReadConsumerConfig(consumerConfig.fileStream); err != nil {
-				logger.Errorf("ReadConsumerConfig error: %#v for %s", perrors.WithStack(err), value)
+		return
+	}
+	// init other consumer config
+	conConfigType := consumerConfig.ConfigType
+	for key, value := range extension.GetDefaultConfigReader() {
+		if conConfigType != nil {
+			if v, ok := conConfigType[key]; ok {
+				value = v
 			}
 		}
+		if err := extension.GetConfigReaders(value).ReadConsumerConfig(consumerConfig.fileStream); err != nil {
+			logger.Errorf("ReadConsumerConfig error: %#v for %s", perrors.WithStack(err), value)
+		}
+	}
 
-		metricConfig = consumerConfig.MetricConfig
-		applicationConfig = consumerConfig.ApplicationConfig
+	metricConfig = consumerConfig.MetricConfig
+	applicationConfig = consumerConfig.ApplicationConfig
 
-		checkApplicationName(consumerConfig.ApplicationConfig)
-		if err := configCenterRefreshConsumer(); err != nil {
-			logger.Errorf("[consumer config center refresh] %#v", err)
+	checkApplicationName(consumerConfig.ApplicationConfig)
+	if err := configCenterRefreshConsumer(); err != nil {
+		logger.Errorf("[consumer config center refresh] %#v", err)
+	}
+	checkRegistries(consumerConfig.Registries, consumerConfig.Registry)
+	for key, ref := range consumerConfig.References {
+		if ref.Generic {
+			genericService := NewGenericService(key)
+			SetConsumerService(genericService)
 		}
-		checkRegistries(consumerConfig.Registries, consumerConfig.Registry)
-		for key, ref := range consumerConfig.References {
-			if ref.Generic {
-				genericService := NewGenericService(key)
-				SetConsumerService(genericService)
-			}
-			rpcService := GetConsumerService(key)
-			if rpcService == nil {
-				logger.Warnf("%s does not exist!", key)
-				continue
-			}
-			ref.id = key
-			ref.Refer(rpcService)
-			ref.Implement(rpcService)
+		rpcService := GetConsumerService(key)
+		if rpcService == nil {
+			logger.Warnf("%s does not exist!", key)
+			continue
 		}
+		ref.id = key
+		ref.Refer(rpcService)
+		ref.Implement(rpcService)
+	}
 
-		//wait for invoker is available, if wait over default 3s, then panic
-		var count int
-		checkok := true
-		for {
-			for _, refconfig := range consumerConfig.References {
-				if (refconfig.Check != nil && *refconfig.Check) ||
-					(refconfig.Check == nil && consumerConfig.Check != nil && *consumerConfig.Check) ||
-					(refconfig.Check == nil && consumerConfig.Check == nil) { //default to true
-
-					if refconfig.invoker != nil &&
-						!refconfig.invoker.IsAvailable() {
-						checkok = false
-						count++
-						if count > maxWait {
-							errMsg := fmt.Sprintf("Failed to check the status of the service %v . No provider available for the service to the consumer use dubbo version %v", refconfig.InterfaceName, constant.Version)
-							logger.Error(errMsg)
-							panic(errMsg)
-						}
-						time.Sleep(time.Second * 1)
-						break
-					}
-					if refconfig.invoker == nil {
-						logger.Warnf("The interface %s invoker not exist , may you should check your interface config.", refconfig.InterfaceName)
+	//wait for invoker is available, if wait over default 3s, then panic
+	var count int
+	checkok := true
+	for {
+		for _, refconfig := range consumerConfig.References {
+			if (refconfig.Check != nil && *refconfig.Check) ||
+				(refconfig.Check == nil && consumerConfig.Check != nil && *consumerConfig.Check) ||
+				(refconfig.Check == nil && consumerConfig.Check == nil) { //default to true
+
+				if refconfig.invoker != nil &&
+					!refconfig.invoker.IsAvailable() {
+					checkok = false
+					count++
+					if count > maxWait {
+						errMsg := fmt.Sprintf("Failed to check the status of the service %v . No provider available for the service to the consumer use dubbo version %v", refconfig.InterfaceName, constant.Version)
+						logger.Error(errMsg)
+						panic(errMsg)
 					}
+					time.Sleep(time.Second * 1)
+					break
+				}
+				if refconfig.invoker == nil {
+					logger.Warnf("The interface %s invoker not exist , may you should check your interface config.", refconfig.InterfaceName)
 				}
 			}
-			if checkok {
-				break
-			}
-			checkok = true
 		}
+		if checkok {
+			break
+		}
+		checkok = true
 	}
+}
 
-	// service config
+func loadProviderConfig() {
 	if providerConfig == nil {
 		logger.Warnf("providerConfig is nil!")
-	} else {
-		// init other provider config
-		proConfigType := providerConfig.ConfigType
-		for key, value := range extension.GetDefaultConfigReader() {
-			if proConfigType != nil {
-				if v, ok := proConfigType[key]; ok {
-					value = v
-				}
-			}
-			if err := extension.GetConfigReaders(value).ReadProviderConfig(providerConfig.fileStream); err != nil {
-				logger.Errorf("ReadProviderConfig error: %#v for %s", perrors.WithStack(err), value)
+		return
+	}
+
+	// init other provider config
+	proConfigType := providerConfig.ConfigType
+	for key, value := range extension.GetDefaultConfigReader() {
+		if proConfigType != nil {
+			if v, ok := proConfigType[key]; ok {
+				value = v
 			}
 		}
+		if err := extension.GetConfigReaders(value).ReadProviderConfig(providerConfig.fileStream); err != nil {
+			logger.Errorf("ReadProviderConfig error: %#v for %s", perrors.WithStack(err), value)
+		}
+	}
 
-		// so, you should know that the consumer's config will be override
-		metricConfig = providerConfig.MetricConfig
-		applicationConfig = providerConfig.ApplicationConfig
+	// so, you should know that the consumer's config will be override
+	metricConfig = providerConfig.MetricConfig
+	applicationConfig = providerConfig.ApplicationConfig
 
-		checkApplicationName(providerConfig.ApplicationConfig)
-		if err := configCenterRefreshProvider(); err != nil {
-			logger.Errorf("[provider config center refresh] %#v", err)
+	checkApplicationName(providerConfig.ApplicationConfig)
+	if err := configCenterRefreshProvider(); err != nil {
+		logger.Errorf("[provider config center refresh] %#v", err)
+	}
+	checkRegistries(providerConfig.Registries, providerConfig.Registry)
+	for key, svs := range providerConfig.Services {
+		rpcService := GetProviderService(key)
+		if rpcService == nil {
+			logger.Warnf("%s does not exist!", key)
+			continue
 		}
-		checkRegistries(providerConfig.Registries, providerConfig.Registry)
-		for key, svs := range providerConfig.Services {
-			rpcService := GetProviderService(key)
-			if rpcService == nil {
-				logger.Warnf("%s does not exist!", key)
-				continue
-			}
-			svs.id = key
-			svs.Implement(rpcService)
-			if err := svs.Export(); err != nil {
-				panic(fmt.Sprintf("service %s export failed! err: %#v", key, err))
-			}
+		svs.id = key
+		svs.Implement(rpcService)
+		if err := svs.Export(); err != nil {
+			panic(fmt.Sprintf("service %s export failed! err: %#v", key, err))
 		}
 	}
+}
+
+func initRouter() {
+	if confRouterFile != "" {
+		if err := RouterInit(confRouterFile); err != nil {
+			log.Printf("[routerConfig init] %#v", err)
+		}
+	}
+}
+
+// Load Dubbo Init
+func Load() {
+
+	// init router
+	initRouter()
+
+	// reference config
+	loadConsumerConfig()
+
+	// service config
+	loadProviderConfig()
+
 	// init the shutdown callback
 	GracefulShutdownInit()
 }
diff --git a/config/config_loader_test.go b/config/config_loader_test.go
index 6368fcbd2c7bc675231e7b7835750f26743708af..a21a4998aae9eb6e0bd0632c7248cc39e7bbd9fa 100644
--- a/config/config_loader_test.go
+++ b/config/config_loader_test.go
@@ -36,10 +36,13 @@ import (
 	"github.com/apache/dubbo-go/config_center"
 )
 
+const mockConsumerConfigPath = "./testdata/consumer_config.yml"
+const mockProviderConfigPath = "./testdata/provider_config.yml"
+
 func TestConfigLoader(t *testing.T) {
-	conPath, err := filepath.Abs("./testdata/consumer_config.yml")
+	conPath, err := filepath.Abs(mockConsumerConfigPath)
 	assert.NoError(t, err)
-	proPath, err := filepath.Abs("./testdata/provider_config.yml")
+	proPath, err := filepath.Abs(mockProviderConfigPath)
 	assert.NoError(t, err)
 
 	assert.Nil(t, consumerConfig)
@@ -152,7 +155,7 @@ func TestConfigLoaderWithConfigCenter(t *testing.T) {
 
 	conPath, err := filepath.Abs("./testdata/consumer_config_with_configcenter.yml")
 	assert.NoError(t, err)
-	proPath, err := filepath.Abs("./testdata/provider_config.yml")
+	proPath, err := filepath.Abs(mockProviderConfigPath)
 	assert.NoError(t, err)
 
 	assert.Nil(t, consumerConfig)
@@ -205,7 +208,7 @@ func TestConfigLoaderWithConfigCenterSingleRegistry(t *testing.T) {
 
 	conPath, err := filepath.Abs("./testdata/consumer_config_with_configcenter.yml")
 	assert.NoError(t, err)
-	proPath, err := filepath.Abs("./testdata/provider_config.yml")
+	proPath, err := filepath.Abs(mockProviderConfigPath)
 	assert.NoError(t, err)
 
 	assert.Nil(t, consumerConfig)
diff --git a/config/config_utils.go b/config/config_utils.go
index 6bc574a546ebad548aaa15ce7dc9bcf68b95c3a1..5759ff34f6e5673c4a6de8af3b4e1a34a2e7af4c 100644
--- a/config/config_utils.go
+++ b/config/config_utils.go
@@ -18,6 +18,7 @@
 package config
 
 import (
+	"fmt"
 	"regexp"
 	"strings"
 )
@@ -30,50 +31,35 @@ func mergeValue(str1, str2, def string) string {
 	if str1 == "" && str2 == "" {
 		return def
 	}
-	str := "," + strings.Trim(str1, ",")
-	if str1 == "" {
-		str = "," + strings.Trim(str2, ",")
-	} else if str2 != "" {
-		str = str + "," + strings.Trim(str2, ",")
-	}
+	s1 := strings.Split(str1, ",")
+	s2 := strings.Split(str2, ",")
+	str := "," + strings.Join(append(s1, s2...), ",")
 	defKey := strings.Contains(str, ","+constant.DEFAULT_KEY)
 	if !defKey {
 		str = "," + constant.DEFAULT_KEY + str
 	}
 	str = strings.TrimPrefix(strings.Replace(str, ","+constant.DEFAULT_KEY, ","+def, -1), ",")
+	return removeMinus(strings.Split(str, ","))
+}
 
-	strArr := strings.Split(str, ",")
-	strMap := make(map[string][]int)
-	for k, v := range strArr {
-		add := true
+func removeMinus(strArr []string) string {
+	if len(strArr) == 0 {
+		return ""
+	}
+	var normalStr string
+	var minusStrArr []string
+	for _, v := range strArr {
 		if strings.HasPrefix(v, "-") {
-			v = v[1:]
-			add = false
-		}
-		if _, ok := strMap[v]; !ok {
-			if add {
-				strMap[v] = []int{1, k}
-			}
+			minusStrArr = append(minusStrArr, v[1:])
 		} else {
-			if add {
-				strMap[v][0] += 1
-				strMap[v] = append(strMap[v], k)
-			} else {
-				strMap[v][0] -= 1
-				strMap[v] = strMap[v][:len(strMap[v])-1]
-			}
+			normalStr += fmt.Sprintf(",%s", v)
 		}
 	}
-	strArr = make([]string, len(strArr))
-	for key, value := range strMap {
-		if value[0] == 0 {
-			continue
-		}
-		for i := 1; i < len(value); i++ {
-			strArr[value[i]] = key
-		}
+	normalStr = strings.Trim(normalStr, ",")
+	for _, v := range minusStrArr {
+		normalStr = strings.Replace(normalStr, v, "", 1)
 	}
 	reg := regexp.MustCompile("[,]+")
-	str = reg.ReplaceAllString(strings.Join(strArr, ","), ",")
-	return strings.Trim(str, ",")
+	normalStr = reg.ReplaceAllString(strings.Trim(normalStr, ","), ",")
+	return normalStr
 }
diff --git a/config/config_utils_test.go b/config/config_utils_test.go
index 5170b90c83a0f31bbbe1b5de5bca9b8dc5869ac6..81fc3a3721d5915ec3652e03f80ec203e170d1fa 100644
--- a/config/config_utils_test.go
+++ b/config/config_utils_test.go
@@ -41,3 +41,23 @@ func TestMergeValue(t *testing.T) {
 	str = mergeValue("", "default,-b,e,f", "a,b")
 	assert.Equal(t, "a,e,f", str)
 }
+
+func TestRemoveMinus(t *testing.T) {
+	strList := removeMinus([]string{})
+	assert.Equal(t, strList, "")
+
+	strList = removeMinus([]string{"a", "b", "c", "d", "-a"})
+	assert.Equal(t, strList, "b,c,d")
+
+	strList = removeMinus([]string{"a", "b", "c", "d", "-a", "-b"})
+	assert.Equal(t, strList, "c,d")
+
+	strList = removeMinus([]string{"a", "b", "c", "-c", "-a", "-b"})
+	assert.Equal(t, strList, "")
+
+	strList = removeMinus([]string{"b", "a", "-c", "c"})
+	assert.Equal(t, strList, "b,a")
+
+	strList = removeMinus([]string{"c", "b", "a", "d", "c", "-c", "-a", "e", "f"})
+	assert.Equal(t, strList, "b,d,c,e,f")
+}
diff --git a/config/consumer_config.go b/config/consumer_config.go
index debcd79fa281c40e5526f60f5c5cdb66688688f4..1453628ab5e24a3607183c349d44e9440868ab60 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"`
@@ -63,7 +63,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
@@ -75,17 +75,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")
@@ -129,7 +129,7 @@ func configCenterRefreshConsumer() error {
 	var err error
 	if consumerConfig.ConfigCenterConfig != nil {
 		consumerConfig.SetFatherConfig(consumerConfig)
-		if err := consumerConfig.startConfigCenter(); err != nil {
+		if err = consumerConfig.startConfigCenter(); err != nil {
 			return perrors.Errorf("start config center error , error message is {%v}", perrors.WithStack(err))
 		}
 		consumerConfig.fresh()
@@ -144,6 +144,5 @@ func configCenterRefreshConsumer() error {
 			return perrors.WithMessagef(err, "time.ParseDuration(Connect_Timeout{%#v})", consumerConfig.Connect_Timeout)
 		}
 	}
-
 	return 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_config_test.go b/config/graceful_shutdown_config_test.go
index 583ed70b838a8271a47e180ee3c6eb32cbb46984..80eb5317386f4e9d966f7a9f07635a810727d77c 100644
--- a/config/graceful_shutdown_config_test.go
+++ b/config/graceful_shutdown_config_test.go
@@ -26,7 +26,7 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func TestShutdownConfig_GetTimeout(t *testing.T) {
+func TestShutdownConfigGetTimeout(t *testing.T) {
 	config := ShutdownConfig{}
 	assert.False(t, config.RejectRequest)
 	assert.False(t, config.RequestsFinished)
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 94%
rename from config/instance/metedata_report.go
rename to config/instance/metadata_report.go
index cd54b0a7940df166c88f02234ab1a4e3bf384163..4c935d733283e6a79523dd0f35be60f092351dbb 100644
--- a/config/instance/metedata_report.go
+++ b/config/instance/metadata_report.go
@@ -32,7 +32,7 @@ var (
 	once     sync.Once
 )
 
-// GetMetadataReportInstance ...
+// GetMetadataReportInstance gets metadata report instance by @url
 func GetMetadataReportInstance(url *common.URL) metadata.MetadataReport {
 	once.Do(func() {
 		instance = extension.GetMetadataReportFactory(url.Protocol).CreateMetadataReport(url)
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 41fb6b4769e59784d8d18c3f82b956fd029d4ff7..11fb0cd65cf5500c09c51268115e5f7c60916657 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"`
 	Address    string            `yaml:"address" json:"address,omitempty" property:"address"`
@@ -43,12 +43,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)
@@ -60,7 +60,7 @@ func (c *MetadataReportConfig) UnmarshalYAML(unmarshal func(interface{}) error)
 	return nil
 }
 
-// ToUrl ...
+// nolint
 func (c *MetadataReportConfig) ToUrl() (*common.URL, error) {
 	urlMap := make(url.Values)
 
@@ -103,7 +103,7 @@ func startMetadataReport(metadataType string, metadataReportConfig *MetadataRepo
 	if url, err := metadataReportConfig.ToUrl(); err == nil {
 		instance.GetMetadataReportInstance(url)
 	} else {
-		return perrors.New("MetadataConfig is invalid!")
+		return perrors.Wrap(err, "Start MetadataReport failed.")
 	}
 
 	return nil
diff --git a/config/metadata_report_config_test.go b/config/metadata_report_config_test.go
index 635feecc2d433366534566d184e058eb54a881ed..b80a77657568d0821fddca2fc16a0ccc90d7f96e 100644
--- a/config/metadata_report_config_test.go
+++ b/config/metadata_report_config_test.go
@@ -23,7 +23,7 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func TestMetadataReportConfig_ToUrl(t *testing.T) {
+func TestMetadataReportConfigToUrl(t *testing.T) {
 	metadataReportConfig := MetadataReportConfig{
 		Protocol:   "mock",
 		Address:    "127.0.0.1:2181",
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 79569917455773653750d1d5921a722daf079b0a..97d037ede008b5fc8cab2febb2177a4e8c3dbd1b 100644
--- a/config/provider_config.go
+++ b/config/provider_config.go
@@ -36,7 +36,7 @@ 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"`
@@ -55,7 +55,7 @@ type ProviderConfig struct {
 	ConfigType        map[string]string          `yaml:"config_type" json:"config_type,omitempty" property:"config_type"`
 }
 
-// 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
@@ -67,17 +67,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 3710cbc4bc62a01a014e91bcb978742c4a93c5cb..5b7a8e9eac676e10276775cab327ae4de1eddf86 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
@@ -66,7 +66,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 + "."
 }
@@ -76,7 +76,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
@@ -168,7 +168,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 7a65e55f09c997cb49b83f1f185faf9338cf0f5a..e43f5aa40af84b9f15a5595ce23696b6a1bae9a4 100644
--- a/config/reference_config_test.go
+++ b/config/reference_config_test.go
@@ -123,6 +123,7 @@ func (m *MockProvider) Reference() string {
 }
 
 func (m *MockProvider) CallBack(res common.CallbackResponse) {
+	// CallBack is a mock function. to implement the interface
 }
 
 func doInitConsumerAsync() {
@@ -178,7 +179,7 @@ func doInitConsumerWithSingleRegistry() {
 	}
 }
 
-func Test_ReferMultireg(t *testing.T) {
+func TestReferMultireg(t *testing.T) {
 	doInitConsumer()
 	extension.SetProtocol("registry", GetProtocol)
 	extension.SetCluster("registryAware", cluster_impl.NewRegistryAwareCluster)
@@ -191,7 +192,7 @@ func Test_ReferMultireg(t *testing.T) {
 	consumerConfig = nil
 }
 
-func Test_Refer(t *testing.T) {
+func TestRefer(t *testing.T) {
 	doInitConsumer()
 	extension.SetProtocol("registry", GetProtocol)
 	extension.SetCluster("registryAware", cluster_impl.NewRegistryAwareCluster)
@@ -205,7 +206,7 @@ func Test_Refer(t *testing.T) {
 	consumerConfig = nil
 }
 
-func Test_ReferAsync(t *testing.T) {
+func TestReferAsync(t *testing.T) {
 	doInitConsumerAsync()
 	extension.SetProtocol("registry", GetProtocol)
 	extension.SetCluster("registryAware", cluster_impl.NewRegistryAwareCluster)
@@ -220,7 +221,7 @@ func Test_ReferAsync(t *testing.T) {
 	consumerConfig = nil
 }
 
-func Test_ReferP2P(t *testing.T) {
+func TestReferP2P(t *testing.T) {
 	doInitConsumer()
 	extension.SetProtocol("dubbo", GetProtocol)
 	m := consumerConfig.References["MockService"]
@@ -234,7 +235,7 @@ func Test_ReferP2P(t *testing.T) {
 	consumerConfig = nil
 }
 
-func Test_ReferMultiP2P(t *testing.T) {
+func TestReferMultiP2P(t *testing.T) {
 	doInitConsumer()
 	extension.SetProtocol("dubbo", GetProtocol)
 	m := consumerConfig.References["MockService"]
@@ -248,7 +249,7 @@ func Test_ReferMultiP2P(t *testing.T) {
 	consumerConfig = nil
 }
 
-func Test_ReferMultiP2PWithReg(t *testing.T) {
+func TestReferMultiP2PWithReg(t *testing.T) {
 	doInitConsumer()
 	extension.SetProtocol("dubbo", GetProtocol)
 	extension.SetProtocol("registry", GetProtocol)
@@ -263,7 +264,7 @@ func Test_ReferMultiP2PWithReg(t *testing.T) {
 	consumerConfig = nil
 }
 
-func Test_Implement(t *testing.T) {
+func TestImplement(t *testing.T) {
 	doInitConsumer()
 	extension.SetProtocol("registry", GetProtocol)
 	extension.SetCluster("registryAware", cluster_impl.NewRegistryAwareCluster)
@@ -276,7 +277,7 @@ func Test_Implement(t *testing.T) {
 	consumerConfig = nil
 }
 
-func Test_Forking(t *testing.T) {
+func TestForking(t *testing.T) {
 	doInitConsumer()
 	extension.SetProtocol("dubbo", GetProtocol)
 	extension.SetProtocol("registry", GetProtocol)
@@ -293,7 +294,7 @@ func Test_Forking(t *testing.T) {
 	consumerConfig = nil
 }
 
-func Test_Sticky(t *testing.T) {
+func TestSticky(t *testing.T) {
 	doInitConsumer()
 	extension.SetProtocol("dubbo", GetProtocol)
 	extension.SetProtocol("registry", GetProtocol)
@@ -332,4 +333,6 @@ func (*mockRegistryProtocol) Export(invoker protocol.Invoker) protocol.Exporter
 	return protocol.NewBaseExporter("test", invoker, &sync.Map{})
 }
 
-func (*mockRegistryProtocol) Destroy() {}
+func (*mockRegistryProtocol) Destroy() {
+	// Destroy is a mock function
+}
diff --git a/config/registry_config.go b/config/registry_config.go
index f3d22311b86d4cc3b66f12e9926dff9565ae4cd6..ef527c827e9dac4cd2762f579d30254e9e51150f 100644
--- a/config/registry_config.go
+++ b/config/registry_config.go
@@ -33,20 +33,21 @@ 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
+	// I changed "type" to "protocol" ,the same as "protocol" field in java class RegistryConfig
 	TimeoutStr string `yaml:"timeout" default:"5s" json:"timeout,omitempty" property:"timeout"` // unit: second
 	Group      string `yaml:"group" json:"group,omitempty" property:"group"`
-	//for registry
-	Address  string            `yaml:"address" json:"address,omitempty" property:"address"`
-	Username string            `yaml:"username" json:"username,omitempty" property:"username"`
-	Password string            `yaml:"password" json:"password,omitempty"  property:"password"`
-	Params   map[string]string `yaml:"params" json:"params,omitempty" property:"params"`
+	// for registry
+	Address    string            `yaml:"address" json:"address,omitempty" property:"address"`
+	Username   string            `yaml:"username" json:"username,omitempty" property:"username"`
+	Password   string            `yaml:"password" json:"password,omitempty"  property:"password"`
+	Simplified bool              `yaml:"simplified" json:"simplified,omitempty"  property:"simplified"`
+	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
@@ -58,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
 }
@@ -70,9 +71,11 @@ func loadRegistries(targetRegistries string, registries map[string]*RegistryConf
 	for k, registryConf := range registries {
 		target := false
 
-		// if user not config targetRegistries,default load all
-		// Notice:in func "func Split(s, sep string) []string"  comment : if s does not contain sep and sep is not empty, SplitAfter returns a slice of length 1 whose only element is s.
-		// So we have to add the condition when targetRegistries string is not set (it will be "" when not set)
+		// if user not config targetRegistries, default load all
+		// Notice: in func "func Split(s, sep string) []string" comment:
+		// if s does not contain sep and sep is not empty, SplitAfter returns
+		// a slice of length 1 whose only element is s. So we have to add the
+		// condition when targetRegistries string is not set (it will be "" when not set)
 		if len(trSlice) == 0 || (len(trSlice) == 1 && trSlice[0] == "") {
 			target = true
 		} else {
@@ -86,29 +89,24 @@ func loadRegistries(targetRegistries string, registries map[string]*RegistryConf
 		}
 
 		if target {
-			var (
-				url common.URL
-				err error
-			)
-
 			addresses := strings.Split(registryConf.Address, ",")
 			address := addresses[0]
 			address = translateRegistryConf(address, registryConf)
-			url, err = common.NewURL(constant.REGISTRY_PROTOCOL+"://"+address,
+			url, err := common.NewURL(constant.REGISTRY_PROTOCOL+"://"+address,
 				common.WithParams(registryConf.getUrlMap(roleType)),
+				common.WithParamsValue("simplified", strconv.FormatBool(registryConf.Simplified)),
 				common.WithUsername(registryConf.Username),
 				common.WithPassword(registryConf.Password),
 				common.WithLocation(registryConf.Address),
 			)
 
 			if err != nil {
-				logger.Errorf("The registry id:%s url is invalid , error: %#v", k, err)
+				logger.Errorf("The registry id: %s url is invalid, error: %#v", k, err)
 				panic(err)
 			} else {
 				urls = append(urls, &url)
 			}
 		}
-
 	}
 
 	return urls
@@ -123,7 +121,6 @@ func (c *RegistryConfig) getUrlMap(roleType common.RoleType) url.Values {
 	for k, v := range c.Params {
 		urlMap.Set(k, v)
 	}
-
 	return urlMap
 }
 
@@ -131,7 +128,7 @@ func translateRegistryConf(address string, registryConf *RegistryConfig) string
 	if strings.Contains(address, "://") {
 		translatedUrl, err := url.Parse(address)
 		if err != nil {
-			logger.Errorf("The registry  url is invalid , error: %#v", err)
+			logger.Errorf("The registry url is invalid, error: %#v", err)
 			panic(err)
 		}
 		address = translatedUrl.Host
diff --git a/config/registry_config_test.go b/config/registry_config_test.go
index 6c2fed605d6c50b483f7ad2900e5a483b3986e1b..6e5dedc34ff5489fc190841bce73cd015eb78132 100644
--- a/config/registry_config_test.go
+++ b/config/registry_config_test.go
@@ -29,7 +29,7 @@ import (
 	"github.com/apache/dubbo-go/common"
 )
 
-func Test_loadRegistries(t *testing.T) {
+func TestLoadRegistries(t *testing.T) {
 	target := "shanghai1"
 	regs := map[string]*RegistryConfig{
 
@@ -47,7 +47,7 @@ func Test_loadRegistries(t *testing.T) {
 	assert.Equal(t, "127.0.0.2:2181,128.0.0.1:2181", urls[0].Location)
 }
 
-func Test_loadRegistries1(t *testing.T) {
+func TestLoadRegistries1(t *testing.T) {
 	target := "shanghai1"
 	regs := map[string]*RegistryConfig{
 
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 50bf5e12c3247340f177a84c72446383ec5c3450..70a344c7b8c858a25e9a556ac6f4e899b1626ab4 100644
--- a/config/service_config.go
+++ b/config/service_config.go
@@ -18,6 +18,7 @@
 package config
 
 import (
+	"container/list"
 	"context"
 	"fmt"
 	"net/url"
@@ -29,6 +30,7 @@ import (
 
 import (
 	"github.com/creasty/defaults"
+	gxnet "github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
 	"go.uber.org/atomic"
 )
@@ -42,7 +44,7 @@ import (
 	"github.com/apache/dubbo-go/protocol/protocolwrapper"
 )
 
-// ServiceConfig ...
+// ServiceConfig is the configuration of the service provider
 type ServiceConfig struct {
 	context                     context.Context
 	id                          string
@@ -78,12 +80,12 @@ type ServiceConfig struct {
 	cacheMutex    sync.Mutex
 }
 
-// Prefix ...
+// nolint
 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
@@ -105,6 +107,24 @@ func NewServiceConfig(id string, context context.Context) *ServiceConfig {
 	}
 }
 
+// Get Random Port
+func getRandomPort(protocolConfigs []*ProtocolConfig) *list.List {
+	ports := list.New()
+	for _, proto := range protocolConfigs {
+		if len(proto.Port) > 0 {
+			continue
+		}
+
+		tcp, err := gxnet.ListenOnTCPRandomPort(proto.Ip)
+		if err != nil {
+			panic(perrors.New(fmt.Sprintf("Get tcp port error,err is {%v}", err)))
+		}
+		defer tcp.Close()
+		ports.PushBack(strings.Split(tcp.Addr().String(), ":")[1])
+	}
+	return ports
+}
+
 // Export ...
 func (c *ServiceConfig) Export() error {
 	// TODO: config center start here
@@ -127,19 +147,29 @@ func (c *ServiceConfig) Export() error {
 		logger.Warnf("The service %v's '%v' protocols don't has right protocolConfigs ", c.InterfaceName, c.Protocol)
 		return nil
 	}
+
+	ports := getRandomPort(protocolConfigs)
+	nextPort := ports.Front()
 	for _, proto := range protocolConfigs {
 		// registry the service reflect
 		methods, err := common.ServiceMap.Register(c.InterfaceName, proto.Name, c.rpcService)
 		if err != nil {
-			err := perrors.Errorf("The service %v  export the protocol %v error! Error message is %v .", c.InterfaceName, proto.Name, err.Error())
-			logger.Errorf(err.Error())
-			return err
+			formatErr := perrors.Errorf("The service %v  export the protocol %v error! Error message is %v .", c.InterfaceName, proto.Name, err.Error())
+			logger.Errorf(formatErr.Error())
+			return formatErr
+		}
+
+		port := proto.Port
+
+		if len(proto.Port) == 0 {
+			port = nextPort.Value.(string)
+			nextPort = nextPort.Next()
 		}
 		ivkURL := common.NewURLWithOptions(
 			common.WithPath(c.id),
 			common.WithProtocol(proto.Name),
 			common.WithIp(proto.Ip),
-			common.WithPort(proto.Port),
+			common.WithPort(port),
 			common.WithParams(urlMap),
 			common.WithParamsValue(constant.BEAN_NAME_KEY, c.id),
 			common.WithMethods(strings.Split(methods, ",")),
diff --git a/config/service_config_test.go b/config/service_config_test.go
index 6f3230890348e77ea26c9c0eaf9165090c8cd09f..798984874a7983f4236a3e60d369b0dc9b255357 100644
--- a/config/service_config_test.go
+++ b/config/service_config_test.go
@@ -21,6 +21,11 @@ import (
 	"testing"
 )
 
+import (
+	gxnet "github.com/dubbogo/gost/net"
+	"github.com/stretchr/testify/assert"
+)
+
 import (
 	"github.com/apache/dubbo-go/common/extension"
 )
@@ -178,7 +183,7 @@ func doInitProviderWithSingleRegistry() {
 	}
 }
 
-func Test_Export(t *testing.T) {
+func TestExport(t *testing.T) {
 	doInitProvider()
 	extension.SetProtocol("registry", GetProtocol)
 
@@ -189,3 +194,35 @@ func Test_Export(t *testing.T) {
 	}
 	providerConfig = nil
 }
+
+func TestgetRandomPort(t *testing.T) {
+	protocolConfigs := make([]*ProtocolConfig, 0, 3)
+
+	ip, err := gxnet.GetLocalIP()
+	protocolConfigs = append(protocolConfigs, &ProtocolConfig{
+		Ip: ip,
+	})
+	protocolConfigs = append(protocolConfigs, &ProtocolConfig{
+		Ip: ip,
+	})
+	protocolConfigs = append(protocolConfigs, &ProtocolConfig{
+		Ip: ip,
+	})
+	assert.NoError(t, err)
+	ports := getRandomPort(protocolConfigs)
+
+	assert.Equal(t, ports.Len(), len(protocolConfigs))
+
+	front := ports.Front()
+	for {
+		if front == nil {
+			break
+		}
+		t.Logf("port:%v", front.Value)
+		front = front.Next()
+	}
+
+	protocolConfigs = make([]*ProtocolConfig, 0, 3)
+	ports = getRandomPort(protocolConfigs)
+	assert.Equal(t, ports.Len(), len(protocolConfigs))
+}
diff --git a/config_center/apollo/impl_test.go b/config_center/apollo/impl_test.go
index a95524b41b887313993aad4e774ed6d96b24c08f..335fb71045ca6349557cf7c736cead0565bdc193 100644
--- a/config_center/apollo/impl_test.go
+++ b/config_center/apollo/impl_test.go
@@ -125,7 +125,7 @@ func initApollo() *httptest.Server {
 	return runMockConfigServer(handlerMap, notifyResponse)
 }
 
-func configResponse(rw http.ResponseWriter, req *http.Request) {
+func configResponse(rw http.ResponseWriter, _ *http.Request) {
 	result := fmt.Sprintf(mockConfigRes)
 	fmt.Fprintf(rw, "%s", result)
 }
@@ -135,7 +135,7 @@ func notifyResponse(rw http.ResponseWriter, req *http.Request) {
 	fmt.Fprintf(rw, "%s", result)
 }
 
-func serviceConfigResponse(rw http.ResponseWriter, req *http.Request) {
+func serviceConfigResponse(rw http.ResponseWriter, _ *http.Request) {
 	result := fmt.Sprintf(mockServiceConfigRes)
 	fmt.Fprintf(rw, "%s", result)
 }
@@ -164,7 +164,7 @@ func runMockConfigServer(handlerMap map[string]func(http.ResponseWriter, *http.R
 	return ts
 }
 
-func Test_GetConfig(t *testing.T) {
+func TestGetConfig(t *testing.T) {
 	configuration := initMockApollo(t)
 	configs, err := configuration.GetProperties(mockNamespace, config_center.WithGroup("dubbo"))
 	assert.NoError(t, err)
@@ -175,7 +175,7 @@ func Test_GetConfig(t *testing.T) {
 	deleteMockJson(t)
 }
 
-func Test_GetConfigItem(t *testing.T) {
+func TestGetConfigItem(t *testing.T) {
 	configuration := initMockApollo(t)
 	configs, err := configuration.GetInternalProperty("application.organization")
 	assert.NoError(t, err)
@@ -238,7 +238,7 @@ func TestRemoveListener(t *testing.T) {
 	apollo.RemoveListener(mockNamespace, listener)
 	assert.Equal(t, "", listener.event)
 	listenerCount := 0
-	apollo.listeners.Range(func(key, value interface{}) bool {
+	apollo.listeners.Range(func(_, value interface{}) bool {
 		apolloListener := value.(*apolloListener)
 		for e := range apolloListener.listeners {
 			fmt.Println(e)
diff --git a/config_center/apollo/listener.go b/config_center/apollo/listener.go
index fb257a4828aed077f61568685ee7823e9c215cf9..1cf65ed22ba0a1f765af66191ed19a04f81b0fe6 100644
--- a/config_center/apollo/listener.go
+++ b/config_center/apollo/listener.go
@@ -29,7 +29,7 @@ type apolloListener struct {
 	listeners map[config_center.ConfigurationListener]struct{}
 }
 
-// NewApolloListener ...
+// NewApolloListener creates a new apolloListener
 func NewApolloListener() *apolloListener {
 	return &apolloListener{
 		listeners: make(map[config_center.ConfigurationListener]struct{}, 0),
@@ -49,7 +49,7 @@ func (a *apolloListener) OnChange(changeEvent *agollo.ChangeEvent) {
 	}
 }
 
-// AddListener ...
+// AddListener adds a listener for apollo
 func (a *apolloListener) AddListener(l config_center.ConfigurationListener) {
 	if _, ok := a.listeners[l]; !ok {
 		a.listeners[l] = struct{}{}
@@ -57,7 +57,7 @@ func (a *apolloListener) AddListener(l config_center.ConfigurationListener) {
 	}
 }
 
-// RemoveListener ...
+// RemoveListener removes listeners of apollo
 func (a *apolloListener) RemoveListener(l config_center.ConfigurationListener) {
 	delete(a.listeners, l)
 }
diff --git a/config_center/configuration_listener.go b/config_center/configuration_listener.go
index e70e4f68075c51c33f1110ef44a7b703e36fb78d..97fd9c70923f5c921ce2ca2b4028a71ea2b49e27 100644
--- a/config_center/configuration_listener.go
+++ b/config_center/configuration_listener.go
@@ -25,12 +25,13 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
-// ConfigurationListener ...
+// ConfigurationListener for changing listener's event
 type ConfigurationListener interface {
+	// Process the notification event once there's any change happens on the config
 	Process(*ConfigChangeEvent)
 }
 
-// ConfigChangeEvent ...
+// ConfigChangeEvent for changing listener's event
 type ConfigChangeEvent struct {
 	Key        string
 	Value      interface{}
diff --git a/config_center/configurator.go b/config_center/configurator.go
index ffa9034e05c4c3d4cc254886e2ed19576f155dec..9db4804365689d8eb357965973a2916e86383cf8 100644
--- a/config_center/configurator.go
+++ b/config_center/configurator.go
@@ -21,7 +21,7 @@ import (
 	"github.com/apache/dubbo-go/common"
 )
 
-// Configurator ...
+// Configurator supports GetUrl and constructor
 type Configurator interface {
 	GetUrl() *common.URL
 	Configure(url *common.URL)
diff --git a/config_center/configurator/mock.go b/config_center/configurator/mock.go
index d294b9195db9cfe60056bc29ec26816f740ea396..7ec7179634cfd967cd27e85ed248e2075c387cb5 100644
--- a/config_center/configurator/mock.go
+++ b/config_center/configurator/mock.go
@@ -23,7 +23,7 @@ import (
 	"github.com/apache/dubbo-go/config_center"
 )
 
-// NewMockConfigurator ...
+// NewMockConfigurator creates a new mockConfigurator
 func NewMockConfigurator(url *common.URL) config_center.Configurator {
 	return &mockConfigurator{configuratorUrl: url}
 }
@@ -32,12 +32,12 @@ type mockConfigurator struct {
 	configuratorUrl *common.URL
 }
 
-// GetUrl ...
+// GetUrl gets a configuratorUrl
 func (c *mockConfigurator) GetUrl() *common.URL {
 	return c.configuratorUrl
 }
 
-// Configure ...
+// Configure sets up param CLUSTER_KEY and cluster for url
 func (c *mockConfigurator) Configure(url *common.URL) {
 	if cluster := c.GetUrl().GetParam(constant.CLUSTER_KEY, ""); cluster != "" {
 		url.SetParam(constant.CLUSTER_KEY, cluster)
diff --git a/config_center/configurator/override.go b/config_center/configurator/override.go
index 18415bee3a28b37ffc2f3f73cc7309b685de5408..294a60ebb2e4e18cfc47cd90aedeaa615b5626d2 100644
--- a/config_center/configurator/override.go
+++ b/config_center/configurator/override.go
@@ -50,12 +50,12 @@ func (c *overrideConfigurator) GetUrl() *common.URL {
 }
 
 func (c *overrideConfigurator) Configure(url *common.URL) {
-	//remove configuratorUrl some param that can not be configured
+	// remove configuratorUrl some param that can not be configured
 	if c.configuratorUrl.GetParam(constant.ENABLED_KEY, "true") == "false" || len(c.configuratorUrl.Location) == 0 {
 		return
 	}
 
-	//branch for version 2.7.x
+	// branch for version 2.7.x
 	apiVersion := c.configuratorUrl.GetParam(constant.CONFIG_VERSION_KEY, "")
 	if len(apiVersion) != 0 {
 		currentSide := url.GetParam(constant.SIDE_KEY, "")
@@ -67,48 +67,51 @@ func (c *overrideConfigurator) Configure(url *common.URL) {
 			c.configureIfMatch(url.Ip, url)
 		}
 	} else {
-		//branch for version 2.6.x and less
+		// branch for version 2.6.x and less
 		c.configureDeprecated(url)
 	}
 }
 
-//translate from java, compatible rules in java
+func (c *overrideConfigurator) configureIfMatchInternal(url *common.URL) {
+	configApp := c.configuratorUrl.GetParam(constant.APPLICATION_KEY, c.configuratorUrl.Username)
+	currentApp := url.GetParam(constant.APPLICATION_KEY, url.Username)
+	if len(configApp) == 0 || constant.ANY_VALUE == configApp || configApp == currentApp {
+		conditionKeys := gxset.NewSet()
+		conditionKeys.Add(constant.CATEGORY_KEY)
+		conditionKeys.Add(constant.CHECK_KEY)
+		conditionKeys.Add(constant.ENABLED_KEY)
+		conditionKeys.Add(constant.GROUP_KEY)
+		conditionKeys.Add(constant.VERSION_KEY)
+		conditionKeys.Add(constant.APPLICATION_KEY)
+		conditionKeys.Add(constant.SIDE_KEY)
+		conditionKeys.Add(constant.CONFIG_VERSION_KEY)
+		conditionKeys.Add(constant.COMPATIBLE_CONFIG_KEY)
+		returnUrl := false
+		c.configuratorUrl.RangeParams(func(k, _ string) bool {
+			value := c.configuratorUrl.GetParam(k, "")
+			if strings.HasPrefix(k, "~") || k == constant.APPLICATION_KEY || k == constant.SIDE_KEY {
+				conditionKeys.Add(k)
+				if len(value) != 0 && value != constant.ANY_VALUE && value != url.GetParam(strings.TrimPrefix(k, "~"), "") {
+					returnUrl = true
+					return false
+				}
+			}
+			return true
+		})
+		if returnUrl {
+			return
+		}
+		configUrl := c.configuratorUrl.CloneExceptParams(conditionKeys)
+		url.SetParams(configUrl.GetParams())
+	}
+}
+
+// configureIfMatch translate from java, compatible rules in java
 func (c *overrideConfigurator) configureIfMatch(host string, url *common.URL) {
 	if constant.ANYHOST_VALUE == c.configuratorUrl.Ip || host == c.configuratorUrl.Ip {
 		providers := c.configuratorUrl.GetParam(constant.OVERRIDE_PROVIDERS_KEY, "")
 		if len(providers) == 0 || strings.Index(providers, url.Location) >= 0 || strings.Index(providers, constant.ANYHOST_VALUE) >= 0 {
-			configApp := c.configuratorUrl.GetParam(constant.APPLICATION_KEY, c.configuratorUrl.Username)
-			currentApp := url.GetParam(constant.APPLICATION_KEY, url.Username)
-			if len(configApp) == 0 || constant.ANY_VALUE == configApp || configApp == currentApp {
-				conditionKeys := gxset.NewSet()
-				conditionKeys.Add(constant.CATEGORY_KEY)
-				conditionKeys.Add(constant.CHECK_KEY)
-				conditionKeys.Add(constant.ENABLED_KEY)
-				conditionKeys.Add(constant.GROUP_KEY)
-				conditionKeys.Add(constant.VERSION_KEY)
-				conditionKeys.Add(constant.APPLICATION_KEY)
-				conditionKeys.Add(constant.SIDE_KEY)
-				conditionKeys.Add(constant.CONFIG_VERSION_KEY)
-				conditionKeys.Add(constant.COMPATIBLE_CONFIG_KEY)
-				returnUrl := false
-				c.configuratorUrl.RangeParams(func(k, v string) bool {
-					value := c.configuratorUrl.GetParam(k, "")
-					if strings.HasPrefix(k, "~") || k == constant.APPLICATION_KEY || k == constant.SIDE_KEY {
-						conditionKeys.Add(k)
-						if len(value) != 0 && value != constant.ANY_VALUE && value != url.GetParam(strings.TrimPrefix(k, "~"), "") {
-							returnUrl = true
-							return false
-						}
-					}
-					return true
-				})
-				if returnUrl {
-					return
-				}
-				configUrl := c.configuratorUrl.Clone()
-				configUrl.RemoveParams(conditionKeys)
-				url.SetParams(configUrl.GetParams())
-			}
+			c.configureIfMatchInternal(url)
 		}
 	}
 }
diff --git a/config_center/configurator/override_test.go b/config_center/configurator/override_test.go
index c0aeb15130e7862fcb00d6cb82cbef60df777acb..8eccb5091272b033cf31b612dfb19bce6514ccce 100644
--- a/config_center/configurator/override_test.go
+++ b/config_center/configurator/override_test.go
@@ -30,51 +30,58 @@ import (
 	"github.com/apache/dubbo-go/common/extension"
 )
 
-func Test_configureVerison2p6(t *testing.T) {
+const (
+	defaults = "default"
+	override = "override"
+	failfast = "failfast"
+	failover = "failover"
+)
+
+func TestConfigureVerison2p6(t *testing.T) {
 	url, err := common.NewURL("override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService")
 	assert.NoError(t, err)
-	configurator := extension.GetConfigurator("default", &url)
-	assert.Equal(t, "override", configurator.GetUrl().Protocol)
+	configurator := extension.GetConfigurator(defaults, &url)
+	assert.Equal(t, override, configurator.GetUrl().Protocol)
 
 	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
 	assert.NoError(t, err)
 	configurator.Configure(&providerUrl)
-	assert.Equal(t, "failfast", providerUrl.GetParam(constant.CLUSTER_KEY, ""))
+	assert.Equal(t, failfast, providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 }
 
-func Test_configureVerisonOverrideAddr(t *testing.T) {
+func TestConfigureVerisonOverrideAddr(t *testing.T) {
 	url, err := common.NewURL("override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&providerAddresses=127.0.0.2:20001|127.0.0.3:20001")
 	assert.NoError(t, err)
-	configurator := extension.GetConfigurator("default", &url)
-	assert.Equal(t, "override", configurator.GetUrl().Protocol)
+	configurator := extension.GetConfigurator(defaults, &url)
+	assert.Equal(t, override, configurator.GetUrl().Protocol)
 
 	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
 	assert.NoError(t, err)
 	configurator.Configure(&providerUrl)
-	assert.Equal(t, "failover", providerUrl.GetParam(constant.CLUSTER_KEY, ""))
+	assert.Equal(t, failover, providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 }
 
-func Test_configureVerison2p6WithIp(t *testing.T) {
+func TestConfigureVerison2p6WithIp(t *testing.T) {
 	url, err := common.NewURL("override://127.0.0.1:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService")
 	assert.NoError(t, err)
-	configurator := extension.GetConfigurator("default", &url)
-	assert.Equal(t, "override", configurator.GetUrl().Protocol)
+	configurator := extension.GetConfigurator(defaults, &url)
+	assert.Equal(t, override, configurator.GetUrl().Protocol)
 
 	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
 	assert.NoError(t, err)
 	configurator.Configure(&providerUrl)
-	assert.Equal(t, "failfast", providerUrl.GetParam(constant.CLUSTER_KEY, ""))
+	assert.Equal(t, failfast, providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 
 }
 
-func Test_configureVerison2p7(t *testing.T) {
+func TestConfigureVerison2p7(t *testing.T) {
 	url, err := common.NewURL("jsonrpc://0.0.0.0:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&configVersion=1.0&side=provider")
 	assert.NoError(t, err)
-	configurator := extension.GetConfigurator("default", &url)
+	configurator := extension.GetConfigurator(defaults, &url)
 
 	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
 	assert.NoError(t, err)
 	configurator.Configure(&providerUrl)
-	assert.Equal(t, "failfast", providerUrl.GetParam(constant.CLUSTER_KEY, ""))
+	assert.Equal(t, failfast, providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 
 }
diff --git a/config_center/dynamic_configuration.go b/config_center/dynamic_configuration.go
index 9013d7140e757520f2e8f048ce53a5ac2a13f982..540febc9d38e164afcc62538478df140b7d671c7 100644
--- a/config_center/dynamic_configuration.go
+++ b/config_center/dynamic_configuration.go
@@ -40,7 +40,7 @@ const (
 	DEFAULT_CONFIG_TIMEOUT = "10s"
 )
 
-// DynamicConfiguration ...
+// DynamicConfiguration for modify listener and get properties file
 type DynamicConfiguration interface {
 	Parser() parser.ConfigurationParser
 	SetParser(parser.ConfigurationParser)
@@ -71,14 +71,14 @@ type Options struct {
 // Option ...
 type Option func(*Options)
 
-// WithGroup ...
+// WithGroup assigns group to opt.Group
 func WithGroup(group string) Option {
 	return func(opt *Options) {
 		opt.Group = group
 	}
 }
 
-// WithTimeout ...
+// WithTimeout assigns time to opt.Timeout
 func WithTimeout(time time.Duration) Option {
 	return func(opt *Options) {
 		opt.Timeout = time
diff --git a/config_center/dynamic_configuration_factory.go b/config_center/dynamic_configuration_factory.go
index 9f9b13227f6623a02b0261c46d8d1e43624005f8..46faf864443b7f8780584213b758f26395224956 100644
--- a/config_center/dynamic_configuration_factory.go
+++ b/config_center/dynamic_configuration_factory.go
@@ -21,7 +21,7 @@ import (
 	"github.com/apache/dubbo-go/common"
 )
 
-// DynamicConfigurationFactory ...
+// DynamicConfigurationFactory gets the DynamicConfiguration
 type DynamicConfigurationFactory interface {
 	GetDynamicConfiguration(*common.URL) (DynamicConfiguration, error)
 }
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/mock_dynamic_config.go b/config_center/mock_dynamic_config.go
index 59c788b65bce2a4773975ea1a96a314649781832..de208946f1715878c2afc62fdd41df93f74797c7 100644
--- a/config_center/mock_dynamic_config.go
+++ b/config_center/mock_dynamic_config.go
@@ -38,12 +38,16 @@ type MockDynamicConfigurationFactory struct {
 	Content string
 }
 
+const (
+	mockServiceName = "org.apache.dubbo-go.mockService"
+)
+
 var (
 	once                 sync.Once
 	dynamicConfiguration *MockDynamicConfiguration
 )
 
-// GetDynamicConfiguration ...
+// GetDynamicConfiguration returns a DynamicConfiguration
 func (f *MockDynamicConfigurationFactory) GetDynamicConfiguration(_ *common.URL) (DynamicConfiguration, error) {
 	var err error
 	once.Do(func() {
@@ -99,16 +103,17 @@ type MockDynamicConfiguration struct {
 	listener map[string]ConfigurationListener
 }
 
-// AddListener ...
+// AddListener adds a listener for MockDynamicConfiguration
 func (c *MockDynamicConfiguration) AddListener(key string, listener ConfigurationListener, _ ...Option) {
 	c.listener[key] = listener
 }
 
-// RemoveListener ...
+// RemoveListener removes the listener for MockDynamicConfiguration
 func (c *MockDynamicConfiguration) RemoveListener(_ string, _ ConfigurationListener, _ ...Option) {
+	// mock remove
 }
 
-// GetConfig ...
+// GetConfig returns content of MockDynamicConfiguration
 func (c *MockDynamicConfiguration) GetConfig(_ string, _ ...Option) (string, error) {
 
 	return c.content, nil
@@ -119,17 +124,17 @@ func (c *MockDynamicConfiguration) GetConfigs(key string, opts ...Option) (strin
 	return c.GetConfig(key, opts...)
 }
 
-// Parser ...
+// Parser returns a parser of MockDynamicConfiguration
 func (c *MockDynamicConfiguration) Parser() parser.ConfigurationParser {
 	return c.parser
 }
 
-// SetParser ...
+// SetParser sets parser of MockDynamicConfiguration
 func (c *MockDynamicConfiguration) SetParser(p parser.ConfigurationParser) {
 	c.parser = p
 }
 
-// GetProperties ...
+// GetProperties gets content of MockDynamicConfiguration
 func (c *MockDynamicConfiguration) GetProperties(_ string, _ ...Option) (string, error) {
 	return c.content, nil
 }
@@ -139,7 +144,7 @@ func (c *MockDynamicConfiguration) GetInternalProperty(key string, opts ...Optio
 	return c.GetProperties(key, opts...)
 }
 
-// GetRule ...
+// GetRule gets properties of MockDynamicConfiguration
 func (c *MockDynamicConfiguration) GetRule(key string, opts ...Option) (string, error) {
 	return c.GetProperties(key, opts...)
 }
@@ -149,20 +154,20 @@ func (c *MockDynamicConfiguration) MockServiceConfigEvent() {
 	config := &parser.ConfiguratorConfig{
 		ConfigVersion: "2.7.1",
 		Scope:         parser.GeneralType,
-		Key:           "org.apache.dubbo-go.mockService",
+		Key:           mockServiceName,
 		Enabled:       true,
 		Configs: []parser.ConfigItem{
 			{Type: parser.GeneralType,
 				Enabled:    true,
 				Addresses:  []string{"0.0.0.0"},
-				Services:   []string{"org.apache.dubbo-go.mockService"},
+				Services:   []string{mockServiceName},
 				Side:       "provider",
 				Parameters: map[string]string{"cluster": "mock1"},
 			},
 		},
 	}
 	value, _ := yaml.Marshal(config)
-	key := "group*org.apache.dubbo-go.mockService:1.0.0" + constant.CONFIGURATORS_SUFFIX
+	key := "group*" + mockServiceName + ":1.0.0" + constant.CONFIGURATORS_SUFFIX
 	c.listener[key].Process(&ConfigChangeEvent{Key: key, Value: string(value), ConfigType: remoting.EventTypeAdd})
 }
 
@@ -171,13 +176,13 @@ func (c *MockDynamicConfiguration) MockApplicationConfigEvent() {
 	config := &parser.ConfiguratorConfig{
 		ConfigVersion: "2.7.1",
 		Scope:         parser.ScopeApplication,
-		Key:           "org.apache.dubbo-go.mockService",
+		Key:           mockServiceName,
 		Enabled:       true,
 		Configs: []parser.ConfigItem{
 			{Type: parser.ScopeApplication,
 				Enabled:    true,
 				Addresses:  []string{"0.0.0.0"},
-				Services:   []string{"org.apache.dubbo-go.mockService"},
+				Services:   []string{mockServiceName},
 				Side:       "provider",
 				Parameters: map[string]string{"cluster": "mock1"},
 			},
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..2e7f4645149b8cd70510713d49ced9ba31d66bb6 100644
--- a/config_center/nacos/client_test.go
+++ b/config_center/nacos/client_test.go
@@ -31,7 +31,7 @@ import (
 	"github.com/apache/dubbo-go/common"
 )
 
-func Test_newNacosClient(t *testing.T) {
+func TestNewNacosClient(t *testing.T) {
 	server := mockCommonNacosServer()
 	nacosURL := strings.ReplaceAll(server.URL, "http", "registry")
 	registryUrl, _ := common.NewURL(nacosURL)
@@ -53,3 +53,62 @@ func Test_newNacosClient(t *testing.T) {
 	<-c.client.Done()
 	c.Destroy()
 }
+
+func TestSetNacosClient(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,
+		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 TestNewNacosClient_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_test.go b/config_center/nacos/impl_test.go
index 4032c91cda512b649140db6eea3dc11eeb482f27..453fa11f955c83ae2925a959e7a2465a2a0e7796 100644
--- a/config_center/nacos/impl_test.go
+++ b/config_center/nacos/impl_test.go
@@ -59,10 +59,10 @@ func runMockConfigServer(configHandler func(http.ResponseWriter, *http.Request),
 }
 
 func mockCommonNacosServer() *httptest.Server {
-	return runMockConfigServer(func(writer http.ResponseWriter, request *http.Request) {
+	return runMockConfigServer(func(writer http.ResponseWriter, _ *http.Request) {
 		data := "true"
 		fmt.Fprintf(writer, "%s", data)
-	}, func(writer http.ResponseWriter, request *http.Request) {
+	}, func(writer http.ResponseWriter, _ *http.Request) {
 		data := `dubbo.properties%02dubbo%02dubbo.service.com.ikurento.user.UserProvider.cluster=failback`
 		fmt.Fprintf(writer, "%s", data)
 	})
@@ -72,15 +72,16 @@ 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) {
+func TestGetConfig(t *testing.T) {
 	nacos, err := initNacosData(t)
 	assert.NoError(t, err)
 	configs, err := nacos.GetProperties("dubbo.properties", config_center.WithGroup("dubbo"))
@@ -88,7 +89,7 @@ func Test_GetConfig(t *testing.T) {
 	assert.NoError(t, err)
 }
 
-func TestNacosDynamicConfiguration_PublishConfig(t *testing.T) {
+func TestNacosDynamicConfigurationPublishConfig(t *testing.T) {
 	nacos, err := initNacosData(t)
 	assert.Nil(t, err)
 	key := "myKey"
@@ -98,7 +99,7 @@ func TestNacosDynamicConfiguration_PublishConfig(t *testing.T) {
 	assert.Nil(t, err)
 }
 
-func Test_AddListener(t *testing.T) {
+func TestAddListener(t *testing.T) {
 	nacos, err := initNacosData(t)
 	assert.NoError(t, err)
 	listener := &mockDataListener{}
@@ -108,7 +109,7 @@ func Test_AddListener(t *testing.T) {
 	listener.wg.Wait()
 }
 
-func Test_RemoveListener(t *testing.T) {
+func TestRemoveListener(_ *testing.T) {
 	//TODO not supported in current go_nacos_sdk version
 }
 
diff --git a/config_center/nacos/listener.go b/config_center/nacos/listener.go
index de74cff8f64683a47278825b670352a04b69b791..4c995389d38e1a39670aff26025f030bd4bfb1ec 100644
--- a/config_center/nacos/listener.go
+++ b/config_center/nacos/listener.go
@@ -31,7 +31,7 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
-func callback(listener config_center.ConfigurationListener, namespace, group, dataId, data string) {
+func callback(listener config_center.ConfigurationListener, _, _, dataId, data string) {
 	listener.Process(&config_center.ConfigChangeEvent{Key: dataId, Value: data, ConfigType: remoting.EventTypeUpdate})
 }
 
diff --git a/config_center/parser/configuration_parser.go b/config_center/parser/configuration_parser.go
index f33b4ba866da69e1d23b493f42152bbb0f437878..6fbdc27d4339150bfec624f7dc5ea0f6a608d7a7 100644
--- a/config_center/parser/configuration_parser.go
+++ b/config_center/parser/configuration_parser.go
@@ -47,7 +47,7 @@ type ConfigurationParser interface {
 	ParseToUrls(content string) ([]*common.URL, error)
 }
 
-// DefaultConfigurationParser for support properties file in config center
+// DefaultConfigurationParser for supporting properties file in config center
 type DefaultConfigurationParser struct{}
 
 // ConfiguratorConfig ...
@@ -71,7 +71,7 @@ type ConfigItem struct {
 	Side              string            `yaml:"side"`
 }
 
-// Parse ...
+// Parse load content
 func (parser *DefaultConfigurationParser) Parse(content string) (map[string]string, error) {
 	pps, err := properties.LoadString(content)
 	if err != nil {
diff --git a/config_center/parser/configuration_parser_test.go b/config_center/parser/configuration_parser_test.go
index 7a59ea9b48b8b8d2a84735a416bcba1bb9ec8652..be2d45b25e835eb6cf6c2cf69afe2d9d69d3f90a 100644
--- a/config_center/parser/configuration_parser_test.go
+++ b/config_center/parser/configuration_parser_test.go
@@ -25,10 +25,65 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func TestDefaultConfigurationParser_Parser(t *testing.T) {
+func TestDefaultConfigurationParserParser(t *testing.T) {
 	parser := &DefaultConfigurationParser{}
 	m, err := parser.Parse("dubbo.registry.address=172.0.0.1\ndubbo.registry.name=test")
 	assert.NoError(t, err)
 	assert.Equal(t, 2, len(m))
 	assert.Equal(t, "172.0.0.1", m["dubbo.registry.address"])
 }
+
+func TestDefaultConfigurationParserAppItemToUrls_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 TestDefaultConfigurationParserServiceItemToUrls_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..ecc3527c486fdd2aa2bc6f4d2f2adab1147e495a 100644
--- a/config_center/zookeeper/impl_test.go
+++ b/config_center/zookeeper/impl_test.go
@@ -18,6 +18,8 @@ package zookeeper
 
 import (
 	"fmt"
+	"path"
+	"strconv"
 	"sync"
 	"testing"
 )
@@ -30,16 +32,32 @@ 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{})
+const (
+	dubboPropertyFileName = "dubbo.properties"
+)
 
+func initZkData(group string, t *testing.T) (*zk.TestCluster, *zookeeperDynamicConfiguration) {
+	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,37 +81,43 @@ 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(path.Join(zreg.rootPath, "dubbo", dubboPropertyFileName))
 		assert.NoError(t, err)
 
-		_, err = reg.client.Conn.Set(reg.rootPath+"/dubbo/dubbo.properties", []byte(data), 0)
+		_, err = zreg.client.Conn.Set(path.Join(zreg.rootPath, "dubbo", dubboPropertyFileName), []byte(data), 0)
 		assert.NoError(t, err)
 	} else {
-		err = reg.client.Create(reg.rootPath + "/dubbo.properties")
+		err = zreg.client.Create(path.Join(zreg.rootPath, dubboPropertyFileName))
 		assert.NoError(t, err)
 
-		_, err = reg.client.Conn.Set(reg.rootPath+"/dubbo.properties", []byte(data), 0)
+		_, err = zreg.client.Conn.Set(path.Join(zreg.rootPath, dubboPropertyFileName), []byte(data), 0)
 		assert.NoError(t, err)
 	}
 
-	return ts, reg
+	return ts, zreg
 }
 
-func Test_GetConfig(t *testing.T) {
+func TestGetConfig(t *testing.T) {
 	ts, reg := initZkData("dubbo", t)
 	defer ts.Stop()
-	configs, err := reg.GetProperties("dubbo.properties", config_center.WithGroup("dubbo"))
+	configs, err := reg.GetProperties(dubboPropertyFileName, config_center.WithGroup("dubbo"))
 	assert.NoError(t, err)
 	m, err := reg.Parser().Parse(configs)
 	assert.NoError(t, err)
 	assert.Equal(t, "5s", m["dubbo.consumer.request_timeout"])
+	configs, err = reg.GetProperties(dubboPropertyFileName)
+	assert.Error(t, err)
+	configs, err = reg.GetInternalProperty(dubboPropertyFileName)
+	assert.Error(t, err)
+	configs, err = reg.GetRule(dubboPropertyFileName)
+	assert.Error(t, err)
 }
 
-func Test_AddListener(t *testing.T) {
+func TestAddListener(t *testing.T) {
 	ts, reg := initZkData("", t)
 	defer ts.Stop()
 	listener := &mockDataListener{}
-	reg.AddListener("dubbo.properties", listener)
+	reg.AddListener(dubboPropertyFileName, listener)
 	listener.wg.Add(1)
 	data := `
 	dubbo.consumer.request_timeout=3s
@@ -116,17 +140,17 @@ func Test_AddListener(t *testing.T) {
 	dubbo.service.com.ikurento.user.UserProvider.warmup=100
 	dubbo.service.com.ikurento.user.UserProvider.cluster=failover
 `
-	_, err := reg.client.Conn.Set(reg.rootPath+"/dubbo.properties", []byte(data), 1)
+	_, err := reg.client.Conn.Set(path.Join(reg.rootPath, dubboPropertyFileName), []byte(data), 1)
 	assert.NoError(t, err)
 	listener.wg.Wait()
-	assert.Equal(t, "dubbo.properties", listener.event)
+	assert.Equal(t, dubboPropertyFileName, listener.event)
 }
 
-func Test_RemoveListener(t *testing.T) {
+func TestRemoveListener(t *testing.T) {
 	ts, reg := initZkData("", t)
 	defer ts.Stop()
 	listener := &mockDataListener{}
-	reg.AddListener("dubbo.properties", listener)
+	reg.AddListener(dubboPropertyFileName, listener)
 	listener.wg.Add(1)
 	data := `
 	dubbo.consumer.request_timeout=3s
@@ -149,15 +173,15 @@ func Test_RemoveListener(t *testing.T) {
 	dubbo.service.com.ikurento.user.UserProvider.warmup=100
 	dubbo.service.com.ikurento.user.UserProvider.cluster=failover
 `
-	reg.RemoveListener("dubbo.properties", listener)
+	reg.RemoveListener(dubboPropertyFileName, listener)
 	listener.wg.Done()
-	_, err := reg.client.Conn.Set(reg.rootPath+"/dubbo.properties", []byte(data), 1)
+	_, err := reg.client.Conn.Set(path.Join(reg.rootPath, dubboPropertyFileName), []byte(data), 1)
 	assert.NoError(t, err)
 	listener.wg.Wait()
 	assert.Equal(t, "", listener.event)
 }
 
-func TestZookeeperDynamicConfiguration_PublishConfig(t *testing.T) {
+func TestZookeeperDynamicConfigurationPublishConfig(t *testing.T) {
 	value := "Test Data"
 	customGroup := "Custom Group"
 	key := "myKey"
diff --git a/config_center/zookeeper/listener.go b/config_center/zookeeper/listener.go
index 122dfaf4f268a706151de6acdaa78bb46e59f8fb..747c4be352add3f549eaf02e83da6442a8a84c6a 100644
--- a/config_center/zookeeper/listener.go
+++ b/config_center/zookeeper/listener.go
@@ -33,12 +33,12 @@ type CacheListener struct {
 	rootPath     string
 }
 
-// NewCacheListener ...
+// NewCacheListener creates a new CacheListener
 func NewCacheListener(rootPath string) *CacheListener {
 	return &CacheListener{rootPath: rootPath}
 }
 
-// AddListener ...
+// AddListener will add a listener if loaded
 func (l *CacheListener) AddListener(key string, listener config_center.ConfigurationListener) {
 
 	// reference from https://stackoverflow.com/questions/34018908/golang-why-dont-we-have-a-set-datastructure
@@ -50,7 +50,7 @@ func (l *CacheListener) AddListener(key string, listener config_center.Configura
 	}
 }
 
-// RemoveListener ...
+// RemoveListener will delete a listener if loaded
 func (l *CacheListener) RemoveListener(key string, listener config_center.ConfigurationListener) {
 	listeners, loaded := l.keyListeners.Load(key)
 	if loaded {
@@ -58,7 +58,7 @@ func (l *CacheListener) RemoveListener(key string, listener config_center.Config
 	}
 }
 
-// DataChange ...
+// DataChange changes all listeners' event
 func (l *CacheListener) DataChange(event remoting.Event) bool {
 	if event.Content == "" {
 		//meanings new node
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/access_log_filter.go b/filter/filter_impl/access_log_filter.go
index fbfe7565170c7df468f755a4bd1aadde166a79c1..49cdc2287c28ae0cbbd0fcab3700536595bb0f5e 100644
--- a/filter/filter_impl/access_log_filter.go
+++ b/filter/filter_impl/access_log_filter.go
@@ -71,14 +71,18 @@ func init() {
  *
  * the value of "accesslog" can be "true" or "default" too.
  * If the value is one of them, the access log will be record in log file which defined in log.yml
+ * AccessLogFilter is designed to be singleton
  */
 type AccessLogFilter struct {
 	logChan chan AccessLogData
 }
 
-// Invoke ...
+// Invoke will check whether user wants to use this filter.
+// If we find the value of key constant.ACCESS_LOG_KEY, we will log the invocation info
 func (ef *AccessLogFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	accessLog := invoker.GetUrl().GetParam(constant.ACCESS_LOG_KEY, "")
+
+	// the user do not
 	if len(accessLog) > 0 {
 		accessLogData := AccessLogData{data: ef.buildAccessLogData(invoker, invocation), accessLog: accessLog}
 		ef.logIntoChannel(accessLogData)
@@ -86,7 +90,7 @@ func (ef *AccessLogFilter) Invoke(ctx context.Context, invoker protocol.Invoker,
 	return invoker.Invoke(ctx, invocation)
 }
 
-// it won't block the invocation
+// logIntoChannel won't block the invocation
 func (ef *AccessLogFilter) logIntoChannel(accessLogData AccessLogData) {
 	select {
 	case ef.logChan <- accessLogData:
@@ -97,6 +101,7 @@ func (ef *AccessLogFilter) logIntoChannel(accessLogData AccessLogData) {
 	}
 }
 
+// buildAccessLogData builds the access log data
 func (ef *AccessLogFilter) buildAccessLogData(_ protocol.Invoker, invocation protocol.Invocation) map[string]string {
 	dataMap := make(map[string]string, 16)
 	attachments := invocation.Attachments()
@@ -130,11 +135,12 @@ func (ef *AccessLogFilter) buildAccessLogData(_ protocol.Invoker, invocation pro
 	return dataMap
 }
 
-// OnResponse ...
+// OnResponse do nothing
 func (ef *AccessLogFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker, _ protocol.Invocation) protocol.Result {
 	return result
 }
 
+// writeLogToFile actually write the logs into file
 func (ef *AccessLogFilter) writeLogToFile(data AccessLogData) {
 	accessLog := data.accessLog
 	if isDefault(accessLog) {
@@ -156,6 +162,12 @@ func (ef *AccessLogFilter) writeLogToFile(data AccessLogData) {
 	}
 }
 
+// openLogFile will open the log file with append mode.
+// If the file is not found, it will create the file.
+// Actually, the accessLog is the filename
+// You may find out that, once we want to write access log into log file,
+// we open the file again and again.
+// It needs to be optimized.
 func (ef *AccessLogFilter) openLogFile(accessLog string) (*os.File, error) {
 	logFile, err := os.OpenFile(accessLog, os.O_CREATE|os.O_APPEND|os.O_RDWR, LogFileMode)
 	if err != nil {
@@ -169,6 +181,12 @@ func (ef *AccessLogFilter) openLogFile(accessLog string) (*os.File, error) {
 		return nil, err
 	}
 	last := fileInfo.ModTime().Format(FileDateFormat)
+
+	// this is confused.
+	// for example, if the last = '2020-03-04'
+	// and today is '2020-03-05'
+	// we will create one new file to log access data
+	// By this way, we can split the access log based on days.
 	if now != last {
 		err = os.Rename(fileInfo.Name(), fileInfo.Name()+"."+now)
 		if err != nil {
@@ -180,11 +198,12 @@ func (ef *AccessLogFilter) openLogFile(accessLog string) (*os.File, error) {
 	return logFile, err
 }
 
+// isDefault check whether accessLog == true or accessLog == default
 func isDefault(accessLog string) bool {
 	return strings.EqualFold("true", accessLog) || strings.EqualFold("default", accessLog)
 }
 
-// GetAccessLogFilter ...
+// GetAccessLogFilter return the instance of AccessLogFilter
 func GetAccessLogFilter() filter.Filter {
 	accessLogFilter := &AccessLogFilter{logChan: make(chan AccessLogData, LogMaxBuffer)}
 	go func() {
@@ -195,12 +214,13 @@ func GetAccessLogFilter() filter.Filter {
 	return accessLogFilter
 }
 
-// AccessLogData ...
+// AccessLogData defines the data that will be log into file
 type AccessLogData struct {
 	accessLog string
 	data      map[string]string
 }
 
+// toLogMessage convert the AccessLogData to String
 func (ef *AccessLogData) toLogMessage() string {
 	builder := strings.Builder{}
 	builder.WriteString("[")
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 9fd97b57b677c9aa8ec492151df9aace6dc78b62..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())
 
@@ -124,7 +124,7 @@ func (hf *HystrixFilter) Invoke(ctx context.Context, invoker protocol.Invoker, i
 	_, _, err := hystrix.GetCircuit(cmdName)
 	configLoadMutex.RUnlock()
 	if err != nil {
-		logger.Errorf("[Hystrix Filter]Errors occurred getting circuit for %s , will invoke without hystrix, error is: ", cmdName, err)
+		logger.Errorf("[Hystrix Filter]Errors occurred getting circuit for %s , will invoke without hystrix, error is: %+v", cmdName, err)
 		return invoker.Invoke(ctx, invocation)
 	}
 	logger.Infof("[Hystrix Filter]Using hystrix filter: %s", cmdName)
@@ -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/token_filter_test.go b/filter/filter_impl/token_filter_test.go
index d7a7f20a5d7648f6ee18fd26f041acb313dd97fe..b8b297e67267640a1c294541afdd4e062bfebb25 100644
--- a/filter/filter_impl/token_filter_test.go
+++ b/filter/filter_impl/token_filter_test.go
@@ -53,10 +53,10 @@ func TestTokenFilter_Invoke(t *testing.T) {
 func TestTokenFilter_InvokeEmptyToken(t *testing.T) {
 	filter := GetTokenFilter()
 
-	url := common.URL{}
+	testUrl := common.URL{}
 	attch := make(map[string]string, 0)
 	attch[constant.TOKEN_KEY] = "ori_key"
-	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(url), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(testUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 }
@@ -64,23 +64,23 @@ func TestTokenFilter_InvokeEmptyToken(t *testing.T) {
 func TestTokenFilter_InvokeEmptyAttach(t *testing.T) {
 	filter := GetTokenFilter()
 
-	url := common.NewURLWithOptions(
+	testUrl := common.NewURLWithOptions(
 		common.WithParams(url.Values{}),
 		common.WithParamsValue(constant.TOKEN_KEY, "ori_key"))
 	attch := make(map[string]string, 0)
-	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(*url), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(*testUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.NotNil(t, result.Error())
 }
 
 func TestTokenFilter_InvokeNotEqual(t *testing.T) {
 	filter := GetTokenFilter()
 
-	url := common.NewURLWithOptions(
+	testUrl := common.NewURLWithOptions(
 		common.WithParams(url.Values{}),
 		common.WithParamsValue(constant.TOKEN_KEY, "ori_key"))
 	attch := make(map[string]string, 0)
 	attch[constant.TOKEN_KEY] = "err_key"
 	result := filter.Invoke(context.Background(),
-		protocol.NewBaseInvoker(*url), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+		protocol.NewBaseInvoker(*testUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.NotNil(t, result.Error())
 }
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 7fe8de9237b82415a09083c2be59df5e232ecaf0..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"
@@ -115,7 +114,12 @@ type MethodServiceTpsLimiterImpl struct {
 	tpsState *concurrent.Map
 }
 
-// IsAllowable ...
+// IsAllowable based on method-level and service-level.
+// The method-level has high priority which means that if there is any rate limit configuration for the method,
+// the service-level rate limit strategy will be ignored.
+// The key point is how to keep thread-safe
+// This implementation use concurrent map + loadOrStore to make implementation thread-safe
+// You can image that even multiple threads create limiter, but only one could store the limiter into tpsState
 func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocation protocol.Invocation) bool {
 
 	methodConfigPrefix := "methods." + invocation.MethodName() + "."
@@ -123,23 +127,30 @@ func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocatio
 	methodLimitRateConfig := url.GetParam(methodConfigPrefix+constant.TPS_LIMIT_RATE_KEY, "")
 	methodIntervalConfig := url.GetParam(methodConfigPrefix+constant.TPS_LIMIT_INTERVAL_KEY, "")
 
+	// service-level tps limit
 	limitTarget := url.ServiceKey()
 
 	// method-level tps limit
 	if len(methodIntervalConfig) > 0 || len(methodLimitRateConfig) > 0 {
+		// it means that if the method-level rate limit exist, we will use method-level rate limit strategy
 		limitTarget = limitTarget + "#" + invocation.MethodName()
 	}
 
+	// looking up the limiter from 'cache'
 	limitState, found := limiter.tpsState.Load(limitTarget)
 	if found {
+		// the limiter has been cached, we return its result
 		return limitState.(filter.TpsLimitStrategy).IsAllowable()
 	}
 
+	// we could not find the limiter, and try to create one.
+
 	limitRate := getLimitConfig(methodLimitRateConfig, url, invocation,
 		constant.TPS_LIMIT_RATE_KEY,
 		constant.DEFAULT_TPS_LIMIT_RATE)
 
 	if limitRate < 0 {
+		// the limitTarget is not necessary to be limited.
 		return true
 	}
 
@@ -150,13 +161,20 @@ func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocatio
 		panic(fmt.Sprintf("The interval must be positive, please check your configuration! url: %s", url.String()))
 	}
 
+	// find the strategy config and then create one
 	limitStrategyConfig := url.GetParam(methodConfigPrefix+constant.TPS_LIMIT_STRATEGY_KEY,
 		url.GetParam(constant.TPS_LIMIT_STRATEGY_KEY, constant.DEFAULT_KEY))
 	limitStateCreator := extension.GetTpsLimitStrategyCreator(limitStrategyConfig)
+
+	// we using loadOrStore to ensure thread-safe
 	limitState, _ = limiter.tpsState.LoadOrStore(limitTarget, limitStateCreator.Create(int(limitRate), int(limitInterval)))
+
 	return limitState.(filter.TpsLimitStrategy).IsAllowable()
 }
 
+// getLimitConfig will try to fetch the configuration from url.
+// If we can convert the methodLevelConfig to int64, return;
+// Or, we will try to look up server-level configuration and then convert it to int64
 func getLimitConfig(methodLevelConfig string,
 	url common.URL,
 	invocation protocol.Invocation,
@@ -172,6 +190,8 @@ func getLimitConfig(methodLevelConfig string,
 		return result
 	}
 
+	// actually there is no method-level configuration, so we use the service-level configuration
+
 	result, err := strconv.ParseInt(url.GetParam(configKey, defaultVal), 0, 0)
 
 	if err != nil {
@@ -183,7 +203,7 @@ func getLimitConfig(methodLevelConfig string,
 var methodServiceTpsLimiterInstance *MethodServiceTpsLimiterImpl
 var methodServiceTpsLimiterOnce sync.Once
 
-// GetMethodServiceTpsLimiter ...
+// GetMethodServiceTpsLimiter will return an MethodServiceTpsLimiterImpl instance.
 func GetMethodServiceTpsLimiter() filter.TpsLimiter {
 	methodServiceTpsLimiterOnce.Do(func() {
 		methodServiceTpsLimiterInstance = &MethodServiceTpsLimiterImpl{
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 0f9003c7df2165a2f3a364a5afc47f578db1d243..52ac1765f78172c0062de8884198e759b8d494ca 100644
--- a/filter/handler/rejected_execution_handler_only_log.go
+++ b/filter/handler/rejected_execution_handler_only_log.go
@@ -36,6 +36,7 @@ const (
 )
 
 func init() {
+	// this implementation is the the default implementation of RejectedExecutionHandler
 	extension.SetRejectedExecutionHandler(HandlerName, GetOnlyLogRejectedExecutionHandler)
 	extension.SetRejectedExecutionHandler(constant.DEFAULT_KEY, GetOnlyLogRejectedExecutionHandler)
 }
@@ -43,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":
@@ -56,11 +57,12 @@ var onlyLogHandlerOnce sync.Once
  *   tps.limit.rejected.handler: "default" or "log"
  *   methods:
  *    - name: "GetUser"
+ * OnlyLogRejectedExecutionHandler is designed to be singleton
  */
 type OnlyLogRejectedExecutionHandler struct {
 }
 
-// RejectedExecution ...
+// RejectedExecution will do nothing, it only log the invocation.
 func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL,
 	_ protocol.Invocation) protocol.Result {
 
@@ -68,7 +70,7 @@ func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL
 	return &protocol.RPCResult{}
 }
 
-// GetOnlyLogRejectedExecutionHandler ...
+// GetOnlyLogRejectedExecutionHandler will return the instance of OnlyLogRejectedExecutionHandler
 func GetOnlyLogRejectedExecutionHandler() filter.RejectedExecutionHandler {
 	onlyLogHandlerOnce.Do(func() {
 		onlyLogHandlerInstance = &OnlyLogRejectedExecutionHandler{}
diff --git a/filter/rejected_execution_handler.go b/filter/rejected_execution_handler.go
index caeea1db6631d0968fd58f59f9577ee9272f3ca0..3d1e1c1e641a836411ce0f71f97acf5d5a55f6d1 100644
--- a/filter/rejected_execution_handler.go
+++ b/filter/rejected_execution_handler.go
@@ -22,8 +22,8 @@ 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 common case is that sometimes you want to return the default value when the request was rejected.
@@ -31,5 +31,7 @@ import (
  * In such situation, implement this interface and register it by invoking extension.SetRejectedExecutionHandler.
  */
 type RejectedExecutionHandler interface {
+
+	// RejectedExecution will be called if the invocation was rejected by some component.
 	RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result
 }
diff --git a/filter/tps_limit_strategy.go b/filter/tps_limit_strategy.go
index 5edf32ce1912642c7ad0ea0b3f6144b45c267eb4..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"
@@ -33,10 +33,16 @@ package filter
  *      tps.limit.strategy: "name of implementation" # method-level
  */
 type TpsLimitStrategy interface {
+	// IsAllowable will return true if this invocation is not over limitation
 	IsAllowable() bool
 }
 
-// TpsLimitStrategyCreator ...
+// TpsLimitStrategyCreator is the creator abstraction for TpsLimitStrategy
 type TpsLimitStrategyCreator interface {
-	Create(rate int, interval int) TpsLimitStrategy
+	// Create will create an instance of TpsLimitStrategy
+	// It will be a little hard to understand this method.
+	// The unit of interval is ms
+	// for example, if the limit = 100, interval = 1000
+	// which means that the tps limitation is 100 times per 1000ms (100/1000ms)
+	Create(limit int, interval int) TpsLimitStrategy
 }
diff --git a/filter/tps_limiter.go b/filter/tps_limiter.go
index dbc9f76838a4406b4788e7757453098613253d58..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":
@@ -34,5 +34,6 @@ import (
  *   tps.limiter: "the name of limiter",
  */
 type TpsLimiter interface {
+	// IsAllowable will check whether this invocation should be enabled for further process
 	IsAllowable(common.URL, protocol.Invocation) bool
 }
diff --git a/go.mod b/go.mod
index b77fd3edae0f5b37392c37b6191468f03d2f44bb..9a9adc3b237b4c50c93e4a2c5a9ba7262f116626 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ require (
 	github.com/Workiva/go-datastructures v1.0.50
 	github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
 	github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e // indirect
-	github.com/apache/dubbo-go-hessian2 v1.5.0
+	github.com/apache/dubbo-go-hessian2 v1.6.1-0.20200623062814-707fde850279
 	github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 // indirect
 	github.com/coreos/bbolt v1.3.3 // indirect
 	github.com/coreos/etcd v3.3.13+incompatible
@@ -12,9 +12,9 @@ require (
 	github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
 	github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
 	github.com/creasty/defaults v1.3.0
-	github.com/dubbogo/getty v1.3.4
+	github.com/dubbogo/getty v1.3.7
 	github.com/dubbogo/go-zookeeper v1.0.0
-	github.com/dubbogo/gost v1.8.0
+	github.com/dubbogo/gost v1.9.0
 	github.com/emicklei/go-restful/v3 v3.0.0
 	github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
 	github.com/go-errors/errors v1.0.1 // indirect
@@ -32,6 +32,8 @@ require (
 	github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
 	github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8
 	github.com/jonboulle/clockwork v0.1.0 // indirect
+	github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 // indirect
+	github.com/juju/testing v0.0.0-20191001232224-ce9dec17d28b // indirect
 	github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect
 	github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect
 	github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
@@ -40,7 +42,7 @@ require (
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
 	github.com/nacos-group/nacos-sdk-go v0.0.0-20191128082542-fe1b325b125c
 	github.com/opentracing/opentracing-go v1.1.0
-	github.com/pkg/errors v0.8.1
+	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/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect
@@ -51,10 +53,9 @@ require (
 	github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 // 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.3 // indirect
-	go.etcd.io/etcd v3.3.13+incompatible
-	go.uber.org/atomic v1.4.0
-	go.uber.org/zap v1.10.0
+	go.etcd.io/bbolt v1.3.4 // indirect
+	go.uber.org/atomic v1.6.0
+	go.uber.org/zap v1.15.0
 	google.golang.org/grpc v1.22.1
 	gopkg.in/yaml.v2 v2.2.2
 	k8s.io/api v0.0.0-20190325185214-7544f9db76f6
diff --git a/go.sum b/go.sum
index e0e1c7a9ff49221d4c2657ee7d8cb6fb7e6991af..f5610cb4b29d664c71c434a21c118de94f7986b1 100644
--- a/go.sum
+++ b/go.sum
@@ -7,6 +7,7 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX
 github.com/Azure/go-autorest v10.7.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest v10.15.3+incompatible h1:nhKI/bvazIs3C3TFGoSqKY6hZ8f5od5mb5/UcS6HVIY=
 github.com/Azure/go-autorest v10.15.3+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/DataDog/datadog-go v2.2.0+incompatible h1:V5BKkxACZLjzHjSgBbr2gvLA2Ae49yhc6CSY7MLy5k4=
 github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
@@ -38,10 +39,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
 github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e h1:MSuLXx/mveDbpDNhVrcWTMeV4lbYWKcyO4rH+jAxmX0=
 github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
 github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
-github.com/apache/dubbo-go-hessian2 v1.4.0 h1:Cb9FQVTy3G93dnDr7P93U8DeKFYpDTJjQp44JG5TafA=
-github.com/apache/dubbo-go-hessian2 v1.4.0/go.mod h1:VwEnsOMidkM1usya2uPfGpSLO9XUF//WQcWn3y+jFz8=
-github.com/apache/dubbo-go-hessian2 v1.5.0 h1:fzulDG5G7nX0ccgKdiN9XipJ7tZ4WXKgmk4stdlDS6s=
-github.com/apache/dubbo-go-hessian2 v1.5.0/go.mod h1:VwEnsOMidkM1usya2uPfGpSLO9XUF//WQcWn3y+jFz8=
+github.com/apache/dubbo-go-hessian2 v1.6.1-0.20200623062814-707fde850279 h1:1g3IJdaUjXWs++NA9Ail8+r6WgrkfhjS6hD/YXvRzjk=
+github.com/apache/dubbo-go-hessian2 v1.6.1-0.20200623062814-707fde850279/go.mod h1:7rEw9guWABQa6Aqb8HeZcsYPHsOS7XT1qtJvkmI6c5w=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -104,24 +103,16 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
 github.com/digitalocean/godo v1.1.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
 github.com/digitalocean/godo v1.10.0 h1:uW1/FcvZE/hoixnJcnlmIUvTVNdZCLjRLzmDtRi1xXY=
 github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
-github.com/divebomb/dubbo-go v1.0.0 h1:QsQxD6UU2WbcaA8YCxU9stiuPUsVCPabFg8hhKGJR8A=
 github.com/docker/go-connections v0.3.0 h1:3lOnM9cSzgGwx8VfK/NGOW5fLQ0GjIlCkaktF+n1M6o=
 github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
 github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/dubbogo/getty v1.3.3 h1:8m4zZBqFHO+NmhH7rMPlFuuYRVjcPD7cUhumevqMZZs=
-github.com/dubbogo/getty v1.3.3/go.mod h1:U92BDyJ6sW9Jpohr2Vlz8w2uUbIbNZ3d+6rJvFTSPp0=
-github.com/dubbogo/getty v1.3.4 h1:5TvH213pnSIKYzY7IK8TT/r6yr5uPTB/U6YNLT+GsU0=
-github.com/dubbogo/getty v1.3.4/go.mod h1:36f+gH/ekaqcDWKbxNBQk9b9HXcGtaI6YHxp4YTntX8=
+github.com/dubbogo/getty v1.3.7 h1:xlkYD2/AH34iGteuLMsGjLl2PwBVrbIhHjf3tlUsv1M=
+github.com/dubbogo/getty v1.3.7/go.mod h1:XWO4+wAaMqgnBN9Ykv2YxxOAkGxymg6LGO9RK+EiCDY=
 github.com/dubbogo/go-zookeeper v1.0.0 h1:RsYdlGwhDW+iKXM3eIIcvt34P2swLdmQfuIJxsHlGoM=
 github.com/dubbogo/go-zookeeper v1.0.0/go.mod h1:fn6n2CAEer3novYgk9ULLwAjuV8/g4DdC2ENwRb6E+c=
-github.com/dubbogo/gost v1.5.1/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
-github.com/dubbogo/gost v1.5.2 h1:ri/03971hdpnn3QeCU+4UZgnRNGDXLDGDucR/iozZm8=
-github.com/dubbogo/gost v1.5.2/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
-github.com/dubbogo/gost v1.7.0 h1:lWNBIE2hk1Aj2be2uXkyRTpZG0RQZj0/xbXnkIq6EHE=
-github.com/dubbogo/gost v1.7.0/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
-github.com/dubbogo/gost v1.8.0 h1:9ACbQe5OwMjqtinQcNJC5xp16kky27OsfSGw5L9A6vw=
-github.com/dubbogo/gost v1.8.0/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
+github.com/dubbogo/gost v1.9.0 h1:UT+dWwvLyJiDotxJERO75jB3Yxgsdy10KztR5ycxRAk=
+github.com/dubbogo/gost v1.9.0/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
 github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74 h1:2MIhn2R6oXQbgW5yHfS+d6YqyMfXiu2L55rFZC4UD/M=
 github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo=
 github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0 h1:ZoRgc53qJCfSLimXqJDrmBhnt5GChDsExMCK7t48o0Y=
@@ -205,6 +196,7 @@ github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSN
 github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
 github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
 github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g=
 github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
@@ -213,8 +205,8 @@ github.com/gophercloud/gophercloud v0.0.0-20180828235145-f29afc2cceca/go.mod h1:
 github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
-github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI=
 github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
@@ -331,7 +323,12 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
 github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/juju/errors v0.0.0-20190930114154-d42613fe1ab9 h1:hJix6idebFclqlfZCHE7EUX7uqLCyb70nHNHH1XKGBg=
 github.com/juju/errors v0.0.0-20190930114154-d42613fe1ab9/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
+github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 h1:UUHMLvzt/31azWTN/ifGWef4WUqvXk0iRqdhdy/2uzI=
+github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
+github.com/juju/testing v0.0.0-20191001232224-ce9dec17d28b h1:Rrp0ByJXEjhREMPGTt3aWYjoIsUGCbt21ekbeJcTWv0=
+github.com/juju/testing v0.0.0-20191001232224-ce9dec17d28b/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/keybase/go-crypto v0.0.0-20180614160407-5114a9a81e1b h1:VE6r2OwP5gj+Z9aCkSKl3MlmnZbfMAjhvR5T7abKHEo=
 github.com/keybase/go-crypto v0.0.0-20180614160407-5114a9a81e1b/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
@@ -391,8 +388,6 @@ 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.0.0-20190723125407-0242d42e3dbb h1:lbmvw8r9W55w+aQgWn35W1nuleRIECMoqUrmwAOAvoI=
-github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb/go.mod h1:CEkSvEpoveoYjA81m4HNeYQ0sge0LFGKSEqO3JKHllo=
 github.com/nacos-group/nacos-sdk-go v0.0.0-20191128082542-fe1b325b125c h1:WoCa3AvgQMVKNs+RIFlWPRgY9QVJwUxJDrGxHs0fcRo=
 github.com/nacos-group/nacos-sdk-go v0.0.0-20191128082542-fe1b325b125c/go.mod h1:CEkSvEpoveoYjA81m4HNeYQ0sge0LFGKSEqO3JKHllo=
 github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 h1:BQ1HW7hr4IVovMwWg0E0PYcyW8CzqDcVmaew9cujU4s=
@@ -428,6 +423,8 @@ github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -453,6 +450,7 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
 github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOekn6B5G/+GMtks9UKbvRU/CMM/o=
 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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 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=
@@ -508,23 +506,28 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/zouyx/agollo v0.0.0-20191114083447-dde9fc9f35b8 h1:k8TV7Gz7cpWpOw/dz71fx8cCZdWoPuckHJ/wkJl+meg=
 github.com/zouyx/agollo v0.0.0-20191114083447-dde9fc9f35b8/go.mod h1:S1cAa98KMFv4Sa8SbJ6ZtvOmf0VlgH0QJ1gXI0lBfBY=
-go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
-go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/etcd v3.3.13+incompatible h1:jCejD5EMnlGxFvcGRyEV4VGlENZc7oPQX6o0t7n3xbw=
-go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
-go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
-go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
+go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
+go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
 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 h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
 golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 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/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 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=
@@ -533,8 +536,10 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r
 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-20190404232315-eb5bcb51f2a3/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
 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=
@@ -554,10 +559,13 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h
 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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 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 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0=
 golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@@ -573,6 +581,11 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
 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=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.0.0-20180829000535-087779f1d2c9 h1:z1TeLUmxf9ws9KLICfmX+KGXTs+rjm+aGWzfsv7MZ9w=
 google.golang.org/api v0.0.0-20180829000535-087779f1d2c9/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
 google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
@@ -590,6 +603,7 @@ gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUy
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 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=
@@ -614,6 +628,8 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
 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=
+honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 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 h1:9MWtbqhwTyDvF4cS1qAhxDb9Mi8taXiAu+5nEacl7gY=
diff --git a/integrate_test.sh b/integrate_test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..c9c2f23b5b07f0baf96260d8092e7464d4d15659
--- /dev/null
+++ b/integrate_test.sh
@@ -0,0 +1,66 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+#!/bin/bash
+
+set -e
+set -x
+
+echo 'start integrate-test'
+
+# set root workspace
+ROOT_DIR=$(pwd)
+echo "integrate-test root work-space -> ${ROOT_DIR}"
+
+# show all travis-env
+echo "travis current commit id  -> ${TRAVIS_COMMIT}"
+echo "travis pull request -> ${TRAVIS_PULL_REQUEST}"
+echo "travis pull request branch -> ${TRAVIS_PULL_REQUEST_BRANCH}"
+echo "travis pull request slug -> ${TRAVIS_PULL_REQUEST_SLUG}"
+echo "travis pull request sha -> ${TRAVIS_PULL_REQUEST_SHA}"
+echo "travis pull request repo slug -> ${TRAVIS_REPO_SLUG}"
+
+
+# #start etcd registry  insecure listen in [:]:2379
+# docker run -d --network host k8s.gcr.io/etcd:3.3.10 etcd
+# echo "etcdv3 listen in [:]2379"
+
+# #start consul registry insecure listen in [:]:8500
+# docker run -d --network host consul
+# echo "consul listen in [:]8500"
+
+# #start nacos registry insecure listen in [:]:8848
+# docker run -d --network host nacos/nacos-server:latest
+# echo "ncacos listen in [:]8848"
+
+# default use zk as registry
+#start zookeeper registry insecure listen in [:]:2181
+docker run -d --network host zookeeper
+echo "zookeeper listen in [:]2181"
+
+# build go-server image
+cd ./test/integrate/dubbo/go-server
+docker build . -t  ci-provider --build-arg PR_ORIGIN_REPO=${TRAVIS_PULL_REQUEST_SLUG} --build-arg PR_ORIGIN_COMMITID=${TRAVIS_PULL_REQUEST_SHA}
+cd ${ROOT_DIR}
+docker run -d --network host ci-provider
+
+# build go-client image
+cd ./test/integrate/dubbo/go-client
+docker build . -t  ci-consumer --build-arg PR_ORIGIN_REPO=${TRAVIS_PULL_REQUEST_SLUG} --build-arg PR_ORIGIN_COMMITID=${TRAVIS_PULL_REQUEST_SHA}
+cd ${ROOT_DIR}
+# run provider
+# check consumer status
+docker run -it --network host ci-consumer
diff --git a/metadata/identifier/base_metadata_identifier.go b/metadata/identifier/base_metadata_identifier.go
index a314671055be523844fd7d8f9589b8b6031632bc..5f3df4c607e69d2b56e1258d081c148524cd7aca 100644
--- a/metadata/identifier/base_metadata_identifier.go
+++ b/metadata/identifier/base_metadata_identifier.go
@@ -25,11 +25,13 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
+// BaseMetadataIdentifier defined for description the Metadata base identify
 type BaseMetadataIdentifier interface {
 	getFilePathKey(params ...string) string
 	getIdentifierKey(params ...string) string
 }
 
+// BaseMetadataIdentifier is the base implement of BaseMetadataIdentifier interface
 type BaseServiceMetadataIdentifier struct {
 	serviceInterface string
 	version          string
@@ -37,7 +39,7 @@ type BaseServiceMetadataIdentifier struct {
 	side             string
 }
 
-// joinParams...
+// joinParams will join the specified char in slice, and return a string
 func joinParams(joinChar string, params []string) string {
 	var joinedStr string
 	for _, param := range params {
@@ -47,7 +49,7 @@ func joinParams(joinChar string, params []string) string {
 	return joinedStr
 }
 
-// getIdentifierKey...
+// getIdentifierKey returns string that format is service:Version:Group:Side:param1:param2...
 func (mdi *BaseServiceMetadataIdentifier) getIdentifierKey(params ...string) string {
 	return mdi.serviceInterface +
 		constant.KEY_SEPARATOR + mdi.version +
@@ -56,7 +58,7 @@ func (mdi *BaseServiceMetadataIdentifier) getIdentifierKey(params ...string) str
 		joinParams(constant.KEY_SEPARATOR, params)
 }
 
-// getFilePathKey...
+// getFilePathKey returns string that format is metadata/path/Version/Group/Side/param1/param2...
 func (mdi *BaseServiceMetadataIdentifier) getFilePathKey(params ...string) string {
 	path := serviceToPath(mdi.serviceInterface)
 
@@ -69,7 +71,6 @@ func (mdi *BaseServiceMetadataIdentifier) getFilePathKey(params ...string) strin
 
 }
 
-// serviceToPath...
 func serviceToPath(serviceInterface string) string {
 	if serviceInterface == constant.ANY_VALUE {
 		return ""
@@ -83,7 +84,6 @@ func serviceToPath(serviceInterface string) string {
 
 }
 
-//withPathSeparator...
 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 f3df8f36546093a826279c4e9ec1546f78d444bd..7e72c10da9c088ca167fa4fbc4dcb57f44b8c06d 100644
--- a/metadata/identifier/metadata_identifier.go
+++ b/metadata/identifier/metadata_identifier.go
@@ -17,17 +17,18 @@
 
 package identifier
 
+// MetadataIdentifier is inherit baseMetaIdentifier with Application name
 type MetadataIdentifier struct {
 	application string
 	BaseMetadataIdentifier
 }
 
-// getIdentifierKey...
+// GetIdentifierKey returns string that format is service:Version:Group:Side:Application
 func (mdi *MetadataIdentifier) getIdentifierKey(params ...string) string {
 	return mdi.BaseMetadataIdentifier.getIdentifierKey(mdi.application)
 }
 
-// getIdentifierKey...
+// GetFilePathKey returns string that format is metadata/path/Version/Group/Side/Application
 func (mdi *MetadataIdentifier) getFilePathKey(params ...string) string {
 	return mdi.BaseMetadataIdentifier.getFilePathKey(mdi.application)
 }
diff --git a/metadata/identifier/service_metadata_identifier.go b/metadata/identifier/service_metadata_identifier.go
index 373df0130dd1f87e3175918bde50060c4be89616..ccc149f7306c125b19a25373d4da660a154cc84e 100644
--- a/metadata/identifier/service_metadata_identifier.go
+++ b/metadata/identifier/service_metadata_identifier.go
@@ -21,18 +21,19 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 )
 
+// ServiceMetadataIdentifier is inherit baseMetaIdentifier with service params: Revision and Protocol
 type ServiceMetadataIdentifier struct {
 	revision string
 	protocol string
 	BaseMetadataIdentifier
 }
 
-// getIdentifierKey...
+// GetIdentifierKey returns string that format is service:Version:Group:Side:Protocol:"revision"+Revision
 func (mdi *ServiceMetadataIdentifier) getIdentifierKey(params ...string) string {
 	return mdi.BaseMetadataIdentifier.getIdentifierKey(mdi.protocol + constant.KEY_REVISON_PREFIX + mdi.revision)
 }
 
-// getIdentifierKey...
+// GetFilePathKey returns string that format is metadata/path/Version/Group/Side/Protocol/"revision"+Revision
 func (mdi *ServiceMetadataIdentifier) getFilePathKey(params ...string) 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 321a216a3e3ad3f2390ab832782924a81e226160..38f3ebbd462338b581d83cd19403a00a5064b5a4 100644
--- a/metadata/identifier/subscribe_metadata_identifier.go
+++ b/metadata/identifier/subscribe_metadata_identifier.go
@@ -17,17 +17,18 @@
 
 package identifier
 
+// SubscriberMetadataIdentifier is inherit baseMetaIdentifier with service params: Revision
 type SubscriberMetadataIdentifier struct {
 	revision string
 	BaseMetadataIdentifier
 }
 
-// getIdentifierKey...
+// GetIdentifierKey returns string that format is service:Version:Group:Side:Revision
 func (mdi *SubscriberMetadataIdentifier) getIdentifierKey(params ...string) string {
 	return mdi.BaseMetadataIdentifier.getIdentifierKey(mdi.revision)
 }
 
-// getIdentifierKey...
+// GetFilePathKey returns string that format is metadata/path/Version/Group/Side/Revision
 func (mdi *SubscriberMetadataIdentifier) getFilePathKey(params ...string) string {
 	return mdi.BaseMetadataIdentifier.getFilePathKey(mdi.revision)
 }
diff --git a/metadata/report.go b/metadata/report.go
index 3fcc71241411d4a8f9577bb5fb3233e67942cd52..f2380f50cd0eb15182c137f02e5f78b4ba8e4fd2 100644
--- a/metadata/report.go
+++ b/metadata/report.go
@@ -25,7 +25,7 @@ import (
 
 type MetadataReport interface {
 	StoreProviderMetadata(*identifier.MetadataIdentifier, *definition.ServiceDefinition)
-	StoreConsumeretadata(*identifier.MetadataIdentifier, map[string]string)
+	StoreConsumerMetadata(*identifier.MetadataIdentifier, map[string]string)
 	SaveServiceMetadata(*identifier.ServiceMetadataIdentifier, *common.URL)
 	RemoveServiceMetadata(*identifier.ServiceMetadataIdentifier)
 	GetExportedURLs(*identifier.ServiceMetadataIdentifier) []string
diff --git a/metadata/service.go b/metadata/service.go
index d85703c95a57183d5c0a5b2445839e946dc6a59b..89df68fb313b1abe63082c0c220b0114c11fca19 100644
--- a/metadata/service.go
+++ b/metadata/service.go
@@ -22,6 +22,9 @@ import (
 	gxset "github.com/dubbogo/gost/container/set"
 )
 
+// Metadata service is a built-in service around the metadata of Dubbo services,
+// whose interface is provided by Dubbo Framework and exported automatically before subscription after other services exporting,
+// which may be used for Dubbo subscribers and admin.
 type MetadataService interface {
 	ServiceName() string
 	ExportURL(url *common.URL) bool
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 5ec7db51af0ddfa6e49d3c65910355f0bf2de414..6d1b771bf4108d17372e0ceb5ca818323278afd2 100644
--- a/protocol/dubbo/client.go
+++ b/protocol/dubbo/client.go
@@ -88,7 +88,7 @@ func init() {
 	rand.Seed(time.Now().UnixNano())
 }
 
-// SetClientConf ...
+// SetClientConf set dubbo client config.
 func SetClientConf(c ClientConfig) {
 	clientConf = &c
 	err := clientConf.CheckValidity()
@@ -99,7 +99,7 @@ func SetClientConf(c ClientConfig) {
 	setClientGrpool()
 }
 
-// GetClientConf ...
+// GetClientConf get dubbo client config.
 func GetClientConf() ClientConfig {
 	return *clientConf
 }
@@ -111,7 +111,7 @@ func setClientGrpool() {
 	}
 }
 
-// Options ...
+// Options is option for create dubbo client
 type Options struct {
 	// connect timeout
 	ConnectTimeout time.Duration
@@ -129,7 +129,7 @@ type AsyncCallbackResponse struct {
 	Reply     interface{}
 }
 
-// Client ...
+// Client is dubbo protocol client.
 type Client struct {
 	opts     Options
 	conf     ClientConfig
@@ -139,7 +139,7 @@ type Client struct {
 	pendingResponses *sync.Map
 }
 
-// NewClient ...
+// NewClient create a new Client.
 func NewClient(opt Options) *Client {
 
 	switch {
@@ -167,7 +167,7 @@ func NewClient(opt Options) *Client {
 	return c
 }
 
-// Request ...
+// Request is dubbo protocol request.
 type Request struct {
 	addr   string
 	svcUrl common.URL
@@ -176,7 +176,7 @@ type Request struct {
 	atta   map[string]string
 }
 
-// NewRequest ...
+// NewRequest create a new Request.
 func NewRequest(addr string, svcUrl common.URL, method string, args interface{}, atta map[string]string) *Request {
 	return &Request{
 		addr:   addr,
@@ -187,13 +187,13 @@ func NewRequest(addr string, svcUrl common.URL, method string, args interface{},
 	}
 }
 
-// Response ...
+// Response is dubbo protocol response.
 type Response struct {
 	reply interface{}
 	atta  map[string]string
 }
 
-// NewResponse ...
+// NewResponse  create a new Response.
 func NewResponse(reply interface{}, atta map[string]string) *Response {
 	return &Response{
 		reply: reply,
@@ -201,15 +201,14 @@ func NewResponse(reply interface{}, atta map[string]string) *Response {
 	}
 }
 
-// CallOneway call one way
+// CallOneway call by one way
 func (c *Client) CallOneway(request *Request) error {
 
 	return perrors.WithStack(c.call(CT_OneWay, request, NewResponse(nil, nil), nil))
 }
 
-// Call if @response is nil, the transport layer will get the response without notify the invoker.
+// Call call remoting by two way or one way, if @response.reply is nil, the way of call is one way.
 func (c *Client) Call(request *Request, response *Response) error {
-
 	ct := CT_TwoWay
 	if response.reply == nil {
 		ct = CT_OneWay
@@ -218,14 +217,12 @@ func (c *Client) Call(request *Request, response *Response) error {
 	return perrors.WithStack(c.call(ct, request, response, nil))
 }
 
-// AsyncCall ...
+// AsyncCall call remoting by async with callback.
 func (c *Client) AsyncCall(request *Request, callback common.AsyncCallback, response *Response) error {
-
 	return perrors.WithStack(c.call(CT_TwoWay, request, response, callback))
 }
 
 func (c *Client) call(ct CallType, request *Request, response *Response, callback common.AsyncCallback) error {
-
 	p := &DubboPackage{}
 	p.Service.Path = strings.TrimPrefix(request.svcUrl.Path, "/")
 	p.Service.Interface = request.svcUrl.GetParam(constant.INTERFACE_KEY, "")
@@ -293,7 +290,7 @@ func (c *Client) call(ct CallType, request *Request, response *Response, callbac
 	return perrors.WithStack(err)
 }
 
-// Close ...
+// Close close the client pool.
 func (c *Client) Close() {
 	if c.pool != nil {
 		c.pool.close()
diff --git a/protocol/dubbo/client_test.go b/protocol/dubbo/client_test.go
index 744ffa80d6bc65e8526201b8cd327bb12b43caef..8b0ba169b82910652c64011c47568c7a018ae5e0 100644
--- a/protocol/dubbo/client_test.go
+++ b/protocol/dubbo/client_test.go
@@ -37,7 +37,13 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-func TestClient_CallOneway(t *testing.T) {
+const (
+	mockMethodNameGetUser   = "GetUser"
+	mockMethodNameGetBigPkg = "GetBigPkg"
+	mockAddress             = "127.0.0.1:20000"
+)
+
+func TestClientCallOneway(t *testing.T) {
 	proto, url := InitTest(t)
 
 	c := &Client{
@@ -50,15 +56,14 @@ func TestClient_CallOneway(t *testing.T) {
 	}
 	c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL))
 
-	//user := &User{}
-	err := c.CallOneway(NewRequest("127.0.0.1:20000", url, "GetUser", []interface{}{"1", "username"}, nil))
+	err := c.CallOneway(NewRequest(mockAddress, url, mockMethodNameGetUser, []interface{}{"1", "username"}, nil))
 	assert.NoError(t, err)
 
 	// destroy
 	proto.Destroy()
 }
 
-func TestClient_Call(t *testing.T) {
+func TestClientCall(t *testing.T) {
 	proto, url := InitTest(t)
 
 	c := &Client{
@@ -77,50 +82,50 @@ func TestClient_Call(t *testing.T) {
 	)
 
 	user = &User{}
-	err = c.Call(NewRequest("127.0.0.1:20000", url, "GetBigPkg", []interface{}{nil}, nil), NewResponse(user, nil))
+	err = c.Call(NewRequest(mockAddress, url, mockMethodNameGetBigPkg, []interface{}{nil}, nil), NewResponse(user, nil))
 	assert.NoError(t, err)
 	assert.NotEqual(t, "", user.Id)
 	assert.NotEqual(t, "", user.Name)
 
 	user = &User{}
-	err = c.Call(NewRequest("127.0.0.1:20000", url, "GetUser", []interface{}{"1", "username"}, nil), NewResponse(user, nil))
+	err = c.Call(NewRequest(mockAddress, url, mockMethodNameGetUser, []interface{}{"1", "username"}, nil), NewResponse(user, nil))
 	assert.NoError(t, err)
 	assert.Equal(t, User{Id: "1", Name: "username"}, *user)
 
 	user = &User{}
-	err = c.Call(NewRequest("127.0.0.1:20000", url, "GetUser0", []interface{}{"1", nil, "username"}, nil), NewResponse(user, nil))
+	err = c.Call(NewRequest(mockAddress, url, "GetUser0", []interface{}{"1", nil, "username"}, nil), NewResponse(user, nil))
 	assert.NoError(t, err)
 	assert.Equal(t, User{Id: "1", Name: "username"}, *user)
 
-	err = c.Call(NewRequest("127.0.0.1:20000", url, "GetUser1", []interface{}{}, nil), NewResponse(user, nil))
+	err = c.Call(NewRequest(mockAddress, url, "GetUser1", []interface{}{}, nil), NewResponse(user, nil))
 	assert.NoError(t, err)
 
-	err = c.Call(NewRequest("127.0.0.1:20000", url, "GetUser2", []interface{}{}, nil), NewResponse(user, nil))
+	err = c.Call(NewRequest(mockAddress, url, "GetUser2", []interface{}{}, nil), NewResponse(user, nil))
 	assert.EqualError(t, err, "error")
 
 	user2 := []interface{}{}
-	err = c.Call(NewRequest("127.0.0.1:20000", url, "GetUser3", []interface{}{}, nil), NewResponse(&user2, nil))
+	err = c.Call(NewRequest(mockAddress, url, "GetUser3", []interface{}{}, nil), NewResponse(&user2, nil))
 	assert.NoError(t, err)
 	assert.Equal(t, &User{Id: "1", Name: "username"}, user2[0])
 
 	user2 = []interface{}{}
-	err = c.Call(NewRequest("127.0.0.1:20000", url, "GetUser4", []interface{}{[]interface{}{"1", "username"}}, nil), NewResponse(&user2, nil))
+	err = c.Call(NewRequest(mockAddress, url, "GetUser4", []interface{}{[]interface{}{"1", "username"}}, nil), NewResponse(&user2, nil))
 	assert.NoError(t, err)
 	assert.Equal(t, &User{Id: "1", Name: "username"}, user2[0])
 
 	user3 := map[interface{}]interface{}{}
-	err = c.Call(NewRequest("127.0.0.1:20000", url, "GetUser5", []interface{}{map[interface{}]interface{}{"id": "1", "name": "username"}}, nil), NewResponse(&user3, nil))
+	err = c.Call(NewRequest(mockAddress, url, "GetUser5", []interface{}{map[interface{}]interface{}{"id": "1", "name": "username"}}, nil), NewResponse(&user3, nil))
 	assert.NoError(t, err)
 	assert.NotNil(t, user3)
 	assert.Equal(t, &User{Id: "1", Name: "username"}, user3["key"])
 
 	user = &User{}
-	err = c.Call(NewRequest("127.0.0.1:20000", url, "GetUser6", []interface{}{0}, nil), NewResponse(user, nil))
+	err = c.Call(NewRequest(mockAddress, url, "GetUser6", []interface{}{0}, nil), NewResponse(user, nil))
 	assert.NoError(t, err)
 	assert.Equal(t, User{Id: "", Name: ""}, *user)
 
 	user = &User{}
-	err = c.Call(NewRequest("127.0.0.1:20000", url, "GetUser6", []interface{}{1}, nil), NewResponse(user, nil))
+	err = c.Call(NewRequest(mockAddress, url, "GetUser6", []interface{}{1}, nil), NewResponse(user, nil))
 	assert.NoError(t, err)
 	assert.Equal(t, User{Id: "1", Name: ""}, *user)
 
@@ -128,7 +133,7 @@ func TestClient_Call(t *testing.T) {
 	proto.Destroy()
 }
 
-func TestClient_AsyncCall(t *testing.T) {
+func TestClientAsyncCall(t *testing.T) {
 	proto, url := InitTest(t)
 
 	c := &Client{
@@ -144,7 +149,7 @@ func TestClient_AsyncCall(t *testing.T) {
 	user := &User{}
 	lock := sync.Mutex{}
 	lock.Lock()
-	err := c.AsyncCall(NewRequest("127.0.0.1:20000", url, "GetUser", []interface{}{"1", "username"}, nil), func(response common.CallbackResponse) {
+	err := c.AsyncCall(NewRequest(mockAddress, url, mockMethodNameGetUser, []interface{}{"1", "username"}, nil), func(response common.CallbackResponse) {
 		r := response.(AsyncCallbackResponse)
 		assert.Equal(t, User{Id: "1", Name: "username"}, *r.Reply.(*Response).reply.(*User))
 		lock.Unlock()
diff --git a/protocol/dubbo/codec.go b/protocol/dubbo/codec.go
index 76416b2baf1e1db516c00d92ecb8ad618bf186bd..1f7d107544a06d0ef83bcb54ff6f03daf2dc517b 100644
--- a/protocol/dubbo/codec.go
+++ b/protocol/dubbo/codec.go
@@ -65,11 +65,12 @@ 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)
 }
 
-// Marshal ...
+// Marshal encode hessian package.
 func (p *DubboPackage) Marshal() (*bytes.Buffer, error) {
 	codec := hessian.NewHessianCodec(nil)
 
@@ -81,7 +82,7 @@ func (p *DubboPackage) Marshal() (*bytes.Buffer, error) {
 	return bytes.NewBuffer(pkg), nil
 }
 
-// Unmarshal ...
+// Unmarshal dncode hessian package.
 func (p *DubboPackage) Unmarshal(buf *bytes.Buffer, opts ...interface{}) error {
 	// fix issue https://github.com/apache/dubbo-go/issues/380
 	bufLen := buf.Len()
@@ -125,7 +126,7 @@ func (p *DubboPackage) Unmarshal(buf *bytes.Buffer, opts ...interface{}) error {
 // PendingResponse
 ////////////////////////////////////////////
 
-// PendingResponse ...
+// PendingResponse is a pending response.
 type PendingResponse struct {
 	seq       uint64
 	err       error
@@ -136,7 +137,7 @@ type PendingResponse struct {
 	done      chan struct{}
 }
 
-// NewPendingResponse ...
+// NewPendingResponse create a PendingResponses.
 func NewPendingResponse() *PendingResponse {
 	return &PendingResponse{
 		start:    time.Now(),
@@ -145,7 +146,7 @@ func NewPendingResponse() *PendingResponse {
 	}
 }
 
-// GetCallResponse ...
+// GetCallResponse get AsyncCallbackResponse.
 func (r PendingResponse) GetCallResponse() common.CallbackResponse {
 	return AsyncCallbackResponse{
 		Cause:     r.err,
diff --git a/protocol/dubbo/codec_test.go b/protocol/dubbo/codec_test.go
index 5dc71f0d080c8c862d68029c7983a4407913307e..c2ca443637e23101679770e464f49e0cbdeab2a9 100644
--- a/protocol/dubbo/codec_test.go
+++ b/protocol/dubbo/codec_test.go
@@ -29,7 +29,7 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func TestDubboPackage_MarshalAndUnmarshal(t *testing.T) {
+func TestDubboPackageMarshalAndUnmarshal(t *testing.T) {
 	pkg := &DubboPackage{}
 	pkg.Body = []interface{}{"a"}
 	pkg.Header.Type = hessian.PackageHeartbeat
diff --git a/protocol/dubbo/config.go b/protocol/dubbo/config.go
index dbc6989c54780afacef717f1d110833d92967f9f..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",
@@ -147,7 +145,7 @@ func GetDefaultServerConfig() ServerConfig {
 	}
 }
 
-// CheckValidity ...
+// CheckValidity confirm getty sessian params.
 func (c *GettySessionParam) CheckValidity() error {
 	var err error
 
@@ -170,7 +168,7 @@ func (c *GettySessionParam) CheckValidity() error {
 	return nil
 }
 
-// CheckValidity ...
+// CheckValidity confirm client params.
 func (c *ClientConfig) CheckValidity() error {
 	var err error
 
@@ -192,7 +190,7 @@ func (c *ClientConfig) CheckValidity() error {
 	return perrors.WithStack(c.GettySessionParam.CheckValidity())
 }
 
-// CheckValidity ...
+// CheckValidity confirm server params.
 func (c *ServerConfig) CheckValidity() error {
 	var err error
 
diff --git a/protocol/dubbo/dubbo_exporter.go b/protocol/dubbo/dubbo_exporter.go
index 1c45c40056f7690ba64838f641fe0b13a1554727..dd80937c5bdf6718c2047b102115d8c08afcd899 100644
--- a/protocol/dubbo/dubbo_exporter.go
+++ b/protocol/dubbo/dubbo_exporter.go
@@ -28,19 +28,19 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-// DubboExporter ...
+// DubboExporter is dubbo service exporter.
 type DubboExporter struct {
 	protocol.BaseExporter
 }
 
-// NewDubboExporter ...
+// NewDubboExporter get a DubboExporter.
 func NewDubboExporter(key string, invoker protocol.Invoker, exporterMap *sync.Map) *DubboExporter {
 	return &DubboExporter{
 		BaseExporter: *protocol.NewBaseExporter(key, invoker, exporterMap),
 	}
 }
 
-// Unexport ...
+// Unexport unexport dubbo service exporter.
 func (de *DubboExporter) Unexport() {
 	serviceId := de.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "")
 	interfaceName := de.GetInvoker().GetUrl().GetParam(constant.INTERFACE_KEY, "")
diff --git a/protocol/dubbo/dubbo_invoker.go b/protocol/dubbo/dubbo_invoker.go
index 09c3725710d2a0b821d8e641b0cb7b367189c244..59202d5f49f30acb9e75c4e2f135601285f08e13 100644
--- a/protocol/dubbo/dubbo_invoker.go
+++ b/protocol/dubbo/dubbo_invoker.go
@@ -39,8 +39,9 @@ import (
 )
 
 var (
-	// ErrNoReply ...
-	ErrNoReply          = perrors.New("request need @response")
+	// ErrNoReply
+	ErrNoReply = perrors.New("request need @response")
+	// ErrDestroyedInvoker
 	ErrDestroyedInvoker = perrors.New("request Destroyed invoker")
 )
 
@@ -48,7 +49,7 @@ var (
 	attachmentKey = []string{constant.INTERFACE_KEY, constant.GROUP_KEY, constant.TOKEN_KEY, constant.TIMEOUT_KEY}
 )
 
-// DubboInvoker ...
+// DubboInvoker is dubbo client invoker.
 type DubboInvoker struct {
 	protocol.BaseInvoker
 	client   *Client
@@ -57,7 +58,7 @@ type DubboInvoker struct {
 	reqNum int64
 }
 
-// NewDubboInvoker ...
+// NewDubboInvoker create dubbo client invoker.
 func NewDubboInvoker(url common.URL, client *Client) *DubboInvoker {
 	return &DubboInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
@@ -66,7 +67,7 @@ func NewDubboInvoker(url common.URL, client *Client) *DubboInvoker {
 	}
 }
 
-// Invoke ...
+// Invoke call remoting.
 func (di *DubboInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
 	var (
 		err    error
@@ -122,7 +123,7 @@ func (di *DubboInvoker) Invoke(ctx context.Context, invocation protocol.Invocati
 	return &result
 }
 
-// Destroy ...
+// Destroy destroy dubbo client invoker.
 func (di *DubboInvoker) Destroy() {
 	di.quitOnce.Do(func() {
 		for {
diff --git a/protocol/dubbo/dubbo_invoker_test.go b/protocol/dubbo/dubbo_invoker_test.go
index 1a64301f8200a4264001284cca1af3f0f1e07814..c0640d5558fcb9fb00f02eba0fddc54bb4162592 100644
--- a/protocol/dubbo/dubbo_invoker_test.go
+++ b/protocol/dubbo/dubbo_invoker_test.go
@@ -35,7 +35,7 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-func TestDubboInvoker_Invoke(t *testing.T) {
+func TestDubboInvokerInvoke(t *testing.T) {
 	proto, url := InitTest(t)
 
 	c := &Client{
@@ -51,7 +51,7 @@ func TestDubboInvoker_Invoke(t *testing.T) {
 	invoker := NewDubboInvoker(url, c)
 	user := &User{}
 
-	inv := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("GetUser"), invocation.WithArguments([]interface{}{"1", "username"}),
+	inv := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName(mockMethodNameGetUser), invocation.WithArguments([]interface{}{"1", "username"}),
 		invocation.WithReply(user), invocation.WithAttachments(map[string]string{"test_key": "test_value"}))
 
 	// Call
diff --git a/protocol/dubbo/dubbo_protocol.go b/protocol/dubbo/dubbo_protocol.go
index 355dbc802488338ef4dbdd7290166038b312f183..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"
 )
 
@@ -45,14 +45,14 @@ var (
 	dubboProtocol *DubboProtocol
 )
 
-// DubboProtocol ...
+// DubboProtocol is a dubbo protocol implement.
 type DubboProtocol struct {
 	protocol.BaseProtocol
 	serverMap  map[string]*Server
 	serverLock sync.Mutex
 }
 
-// NewDubboProtocol ...
+// NewDubboProtocol create a dubbo protocol.
 func NewDubboProtocol() *DubboProtocol {
 	return &DubboProtocol{
 		BaseProtocol: protocol.NewBaseProtocol(),
@@ -60,7 +60,7 @@ func NewDubboProtocol() *DubboProtocol {
 	}
 }
 
-// Export ...
+// Export export dubbo service.
 func (dp *DubboProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	url := invoker.GetUrl()
 	serviceKey := url.ServiceKey()
@@ -73,7 +73,7 @@ func (dp *DubboProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	return exporter
 }
 
-// Refer ...
+// Refer create dubbo service reference.
 func (dp *DubboProtocol) Refer(url common.URL) protocol.Invoker {
 	//default requestTimeout
 	var requestTimeout = config.GetConsumerConfig().RequestTimeout
@@ -92,7 +92,7 @@ func (dp *DubboProtocol) Refer(url common.URL) protocol.Invoker {
 	return invoker
 }
 
-// Destroy ...
+// Destroy destroy dubbo service.
 func (dp *DubboProtocol) Destroy() {
 	logger.Infof("DubboProtocol destroy.")
 
@@ -124,7 +124,7 @@ func (dp *DubboProtocol) openServer(url common.URL) {
 	}
 }
 
-// GetProtocol ...
+// GetProtocol get a single dubbo protocol.
 func GetProtocol() protocol.Protocol {
 	if dubboProtocol == nil {
 		dubboProtocol = NewDubboProtocol()
diff --git a/protocol/dubbo/dubbo_protocol_test.go b/protocol/dubbo/dubbo_protocol_test.go
index 14f6868ad4a7f2bf6f549a2fbbce8234cbb4aa12..6f3892be67be533dea09dc7bd54de56844dbc79c 100644
--- a/protocol/dubbo/dubbo_protocol_test.go
+++ b/protocol/dubbo/dubbo_protocol_test.go
@@ -31,15 +31,19 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-func TestDubboProtocol_Export(t *testing.T) {
-	// Export
-	proto := GetProtocol()
-	srvConf = &ServerConfig{}
-	url, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
+const (
+	mockCommonUrl = "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
 		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
 		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
 		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
-		"side=provider&timeout=3000&timestamp=1556509797245")
+		"side=provider&timeout=3000&timestamp=1556509797245"
+)
+
+func TestDubboProtocolExport(t *testing.T) {
+	// Export
+	proto := GetProtocol()
+	srvConf = &ServerConfig{}
+	url, err := common.NewURL(mockCommonUrl)
 	assert.NoError(t, err)
 	exporter := proto.Export(protocol.NewBaseInvoker(url))
 
@@ -48,11 +52,7 @@ func TestDubboProtocol_Export(t *testing.T) {
 	assert.True(t, eq)
 
 	// second service: the same path and the different version
-	url2, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
-		"side=provider&timeout=3000&timestamp=1556509797245", common.WithParamsValue(constant.VERSION_KEY, "v1.1"))
+	url2, err := common.NewURL(mockCommonUrl, common.WithParamsValue(constant.VERSION_KEY, "v1.1"))
 	assert.NoError(t, err)
 	exporter2 := proto.Export(protocol.NewBaseInvoker(url2))
 	// make sure url
@@ -74,14 +74,10 @@ func TestDubboProtocol_Export(t *testing.T) {
 	assert.False(t, ok)
 }
 
-func TestDubboProtocol_Refer(t *testing.T) {
+func TestDubboProtocolRefer(t *testing.T) {
 	// Refer
 	proto := GetProtocol()
-	url, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
-		"side=provider&timeout=3000&timestamp=1556509797245")
+	url, err := common.NewURL(mockCommonUrl)
 	assert.NoError(t, err)
 	clientConf = &ClientConfig{}
 	invoker := proto.Refer(url)
diff --git a/protocol/dubbo/listener.go b/protocol/dubbo/listener.go
index 0251b78a2b0d27a68461c16c284b1af53bcb08aa..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.Infof("session{%s} got error{%v}, will be closed.", session.Stat(), err)
+	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,9 +142,9 @@ 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) {
-	rpcSession, err := h.conn.getClientRpcSession(session)
+	clientRpcSession, err := h.conn.getClientRpcSession(session)
 	if err != nil {
 		logger.Errorf("client.getClientSession(session{%s}) = error{%v}",
 			session.Stat(), perrors.WithStack(err))
@@ -151,7 +152,7 @@ func (h *RpcClientHandler) OnCron(session getty.Session) {
 	}
 	if h.conn.pool.rpcClient.conf.sessionTimeout.Nanoseconds() < time.Since(session.GetActive()).Nanoseconds() {
 		logger.Warnf("session{%s} timeout{%s}, reqNum{%d}",
-			session.Stat(), time.Since(session.GetActive()).String(), rpcSession.reqNum)
+			session.Stat(), time.Since(session.GetActive()).String(), clientRpcSession.reqNum)
 		h.conn.removeSession(session) // -> h.conn.close() -> h.conn.pool.remove(h.conn)
 		return
 	}
@@ -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,15 +200,15 @@ 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.Infof("session{%s} got error{%v}, will be closed.", session.Stat(), err)
+	logger.Warnf("session{%s} got error{%v}, will be closed.", session.Stat(), err)
 	h.rwlock.Lock()
 	delete(h.sessionMap, session)
 	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 918514c2676cfc69336a9f53e6d16d7f23cf7dca..c9f5e34fadf61fb36e92356f1b1d40fbc67e4c99 100644
--- a/protocol/dubbo/pool.go
+++ b/protocol/dubbo/pool.go
@@ -219,25 +219,25 @@ func (c *gettyRPCClient) updateSession(session getty.Session) {
 
 func (c *gettyRPCClient) getClientRpcSession(session getty.Session) (rpcSession, error) {
 	var (
-		err        error
-		rpcSession rpcSession
+		err              error
+		rpcClientSession rpcSession
 	)
 	c.lock.RLock()
 	defer c.lock.RUnlock()
 	if c.sessions == nil {
-		return rpcSession, errClientClosed
+		return rpcClientSession, errClientClosed
 	}
 
 	err = errSessionNotExist
 	for _, s := range c.sessions {
 		if s.session == session {
-			rpcSession = *s
+			rpcClientSession = *s
 			err = nil
 			break
 		}
 	}
 
-	return rpcSession, perrors.WithStack(err)
+	return rpcClientSession, perrors.WithStack(err)
 }
 
 func (c *gettyRPCClient) isAvailable() bool {
@@ -319,8 +319,7 @@ func (p *gettyRPCClientPool) getGettyRpcClient(protocol, addr string) (*gettyRPC
 	conn, err := p.get()
 	if err == nil && conn == nil {
 		// create new conn
-		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/dubbo/readwriter.go b/protocol/dubbo/readwriter.go
index b5c4f509190dbdc85825ad424656240b234786df..9cc7ea25cdfa6152d632f278b33285d7d38f47c9 100644
--- a/protocol/dubbo/readwriter.go
+++ b/protocol/dubbo/readwriter.go
@@ -38,16 +38,17 @@ import (
 // RpcClientPackageHandler
 ////////////////////////////////////////////
 
-// RpcClientPackageHandler ...
+// RpcClientPackageHandler handle package for client in getty.
 type RpcClientPackageHandler struct {
 	client *Client
 }
 
-// NewRpcClientPackageHandler ...
+// NewRpcClientPackageHandler create a RpcClientPackageHandler.
 func NewRpcClientPackageHandler(client *Client) *RpcClientPackageHandler {
 	return &RpcClientPackageHandler{client: client}
 }
 
+// Read decode @data to DubboPackage.
 func (p *RpcClientPackageHandler) Read(ss getty.Session, data []byte) (interface{}, int, error) {
 	pkg := &DubboPackage{}
 
@@ -72,6 +73,7 @@ func (p *RpcClientPackageHandler) Read(ss getty.Session, data []byte) (interface
 	return pkg, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil
 }
 
+// Write encode @pkg.
 func (p *RpcClientPackageHandler) Write(ss getty.Session, pkg interface{}) ([]byte, error) {
 	req, ok := pkg.(*DubboPackage)
 	if !ok {
@@ -96,9 +98,10 @@ var (
 	rpcServerPkgHandler = &RpcServerPackageHandler{}
 )
 
-// RpcServerPackageHandler ...
+// RpcServerPackageHandler handle package for server in getty.
 type RpcServerPackageHandler struct{}
 
+// Read decode @data to DubboPackage.
 func (p *RpcServerPackageHandler) Read(ss getty.Session, data []byte) (interface{}, int, error) {
 	pkg := &DubboPackage{
 		Body: make([]interface{}, 7),
@@ -169,6 +172,7 @@ func (p *RpcServerPackageHandler) Read(ss getty.Session, data []byte) (interface
 	return pkg, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil
 }
 
+// Write encode @pkg.
 func (p *RpcServerPackageHandler) Write(ss getty.Session, pkg interface{}) ([]byte, error) {
 	res, ok := pkg.(*DubboPackage)
 	if !ok {
diff --git a/protocol/dubbo/server.go b/protocol/dubbo/server.go
index bd2b37b7a9f055745e183524d19a442af03360f4..8de353a0b372785e89585f4bf2b00b2c42540a2b 100644
--- a/protocol/dubbo/server.go
+++ b/protocol/dubbo/server.go
@@ -71,10 +71,10 @@ func init() {
 	if err := srvConf.CheckValidity(); err != nil {
 		panic(err)
 	}
-	SetServerGrpool()
+	setServerGrpool()
 }
 
-// SetServerConfig ...
+// SetServerConfig set dubbo server config.
 func SetServerConfig(s ServerConfig) {
 	srvConf = &s
 	err := srvConf.CheckValidity()
@@ -82,30 +82,29 @@ func SetServerConfig(s ServerConfig) {
 		logger.Warnf("[ServerConfig CheckValidity] error: %v", err)
 		return
 	}
-	SetServerGrpool()
+	setServerGrpool()
 }
 
-// GetServerConfig ...
+// GetServerConfig get dubbo server config.
 func GetServerConfig() ServerConfig {
 	return *srvConf
 }
 
-// SetServerGrpool ...
-func SetServerGrpool() {
+func setServerGrpool() {
 	if srvConf.GrPoolSize > 1 {
 		srvGrpool = gxsync.NewTaskPool(gxsync.WithTaskPoolTaskPoolSize(srvConf.GrPoolSize), gxsync.WithTaskPoolTaskQueueLength(srvConf.QueueLen),
 			gxsync.WithTaskPoolTaskQueueNumber(srvConf.QueueNumber))
 	}
 }
 
-// Server ...
+// Server is dubbo protocol server.
 type Server struct {
 	conf       ServerConfig
 	tcpServer  getty.Server
 	rpcHandler *RpcServerHandler
 }
 
-// NewServer ...
+// NewServer create a new Server.
 func NewServer() *Server {
 
 	s := &Server{
@@ -156,7 +155,7 @@ func (s *Server) newSession(session getty.Session) error {
 	return nil
 }
 
-// Start ...
+// Start start dubbo server.
 func (s *Server) Start(url common.URL) {
 	var (
 		addr      string
@@ -173,7 +172,7 @@ func (s *Server) Start(url common.URL) {
 
 }
 
-// Stop ...
+// Stop stop dubbo server.
 func (s *Server) Stop() {
 	s.tcpServer.Close()
 }
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/common_test.go b/protocol/grpc/common_test.go
index 33c2fc617d52795d13d9b4fc02054ef5a79d0934..b732283a9bf9d316c1b9d4356a1b9563bfa1d3ec 100644
--- a/protocol/grpc/common_test.go
+++ b/protocol/grpc/common_test.go
@@ -106,7 +106,7 @@ func dubboGreeterSayHelloHandler(srv interface{}, ctx context.Context,
 		Server:     srv,
 		FullMethod: "/helloworld.Greeter/SayHello",
 	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+	handler := func(context.Context, interface{}) (interface{}, error) {
 		result := base.GetProxyImpl().Invoke(context.Background(), invo)
 		return result.Result(), result.Error()
 	}
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_invoker_test.go b/protocol/grpc/grpc_invoker_test.go
index 3054ada13340a9c9cc038a63d89c45ced9ec7ac7..d5ebbb4f47a324791a3367a649bd49b06281540f 100644
--- a/protocol/grpc/grpc_invoker_test.go
+++ b/protocol/grpc/grpc_invoker_test.go
@@ -33,11 +33,19 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
+const (
+	mockGrpcCommonUrl = "grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl" +
+		"&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter" +
+		"&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=" +
+		"&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown&registry.role=3&remote.timestamp=1576923717&retries=" +
+		"&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider&timestamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!"
+)
+
 func TestInvoke(t *testing.T) {
 	go internal.InitGrpcServer()
 	defer internal.ShutdownGrpcServer()
 
-	url, err := common.NewURL("grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown&registry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider&timestamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!")
+	url, err := common.NewURL(mockGrpcCommonUrl)
 	assert.Nil(t, err)
 
 	cli := NewClient(url)
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/grpc_protocol_test.go b/protocol/grpc/grpc_protocol_test.go
index d028f8ef4285b0183e6e0b5b32deede59ce5c531..87ce714fc7437eca53509bb368ed7bc774929634 100644
--- a/protocol/grpc/grpc_protocol_test.go
+++ b/protocol/grpc/grpc_protocol_test.go
@@ -32,12 +32,12 @@ import (
 	"github.com/apache/dubbo-go/protocol/grpc/internal"
 )
 
-func TestGrpcProtocol_Export(t *testing.T) {
+func TestGrpcProtocolExport(t *testing.T) {
 	// Export
 	addService()
 
 	proto := GetProtocol()
-	url, err := common.NewURL("grpc://127.0.0.1:40000/GrpcGreeterImpl?accesslog=&app.version=0.0.1&application=BDTService&bean.name=GrpcGreeterImpl&cluster=failover&environment=dev&execute.limit=&execute.limit.rejected.handler=&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&timestamp=1576923717&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100")
+	url, err := common.NewURL(mockGrpcCommonUrl)
 	assert.NoError(t, err)
 	exporter := proto.Export(protocol.NewBaseInvoker(url))
 	time.Sleep(time.Second)
@@ -61,13 +61,13 @@ func TestGrpcProtocol_Export(t *testing.T) {
 	assert.False(t, ok)
 }
 
-func TestGrpcProtocol_Refer(t *testing.T) {
+func TestGrpcProtocolRefer(t *testing.T) {
 	go internal.InitGrpcServer()
 	defer internal.ShutdownGrpcServer()
 	time.Sleep(time.Second)
 
 	proto := GetProtocol()
-	url, err := common.NewURL("grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown&registry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider&timestamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!")
+	url, err := common.NewURL(mockGrpcCommonUrl)
 	assert.NoError(t, err)
 	invoker := proto.Refer(url)
 
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 f32f2c3449ac063ecb89952bd4653312a07a3df4..ba5949794c0120874ebdf31cfb1fd9c7d8ac08e4 100644
--- a/protocol/invocation.go
+++ b/protocol/invocation.go
@@ -21,14 +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
+	// 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 b207fd0b0cc4eb7de8409a8c46c6fc9ef0baa5c7..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
@@ -40,64 +40,70 @@ type RPCInvocation struct {
 	reply           interface{}
 	callBack        interface{}
 	attachments     map[string]string
-	invoker         protocol.Invoker
-	lock            sync.RWMutex
+	// Refer to dubbo 2.7.6.  It is different from attachment. It is used in internal process.
+	attributes map[string]interface{}
+	invoker    protocol.Invoker
+	lock       sync.RWMutex
 }
 
-// NewRPCInvocation ...
+// NewRPCInvocation creates a RPC invocation.
 func NewRPCInvocation(methodName string, arguments []interface{}, attachments map[string]string) *RPCInvocation {
 	return &RPCInvocation{
 		methodName:  methodName,
 		arguments:   arguments,
 		attachments: attachments,
+		attributes:  make(map[string]interface{}, 8),
 	}
 }
 
-// NewRPCInvocationWithOptions ...
+// NewRPCInvocationWithOptions creates a RPC invocation with @opts.
 func NewRPCInvocationWithOptions(opts ...option) *RPCInvocation {
 	invo := &RPCInvocation{}
 	for _, opt := range opts {
 		opt(invo)
 	}
+	if invo.attributes == nil {
+		invo.attributes = make(map[string]interface{})
+	}
 	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()
@@ -111,7 +117,23 @@ func (r *RPCInvocation) AttachmentsByKey(key string, defaultValue string) string
 	return defaultValue
 }
 
-// SetAttachments ...
+// Attributes gets all attributes of RPC.
+func (r *RPCInvocation) Attributes() map[string]interface{} {
+	return r.attributes
+}
+
+// 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()
+	value, ok := r.attributes[key]
+	if ok {
+		return value
+	}
+	return defaultValue
+}
+
+// SetAttachments sets attribute by @key and @value.
 func (r *RPCInvocation) SetAttachments(key string, value string) {
 	r.lock.Lock()
 	defer r.lock.Unlock()
@@ -121,22 +143,29 @@ func (r *RPCInvocation) SetAttachments(key string, value string) {
 	r.attachments[key] = value
 }
 
-// Invoker ...
+// 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 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
 }
@@ -147,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 ba7197dbc857c2ed7acda1a9f246a5b826e86915..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{}
@@ -172,7 +172,7 @@ func (c *HTTPClient) Do(addr, path string, httpHeader http.Header, body []byte)
 	httpReq.Close = true
 
 	reqBuf := bytes.NewBuffer(make([]byte, 0))
-	if err := httpReq.Write(reqBuf); err != nil {
+	if err = httpReq.Write(reqBuf); err != nil {
 		return nil, perrors.WithStack(err)
 	}
 
@@ -191,7 +191,7 @@ func (c *HTTPClient) Do(addr, path string, httpHeader http.Header, body []byte)
 	}
 	setNetConnTimeout(tcpConn, c.options.HTTPTimeout)
 
-	if _, err := reqBuf.WriteTo(tcpConn); err != nil {
+	if _, err = reqBuf.WriteTo(tcpConn); err != nil {
 		return nil, perrors.WithStack(err)
 	}
 
diff --git a/protocol/jsonrpc/http_test.go b/protocol/jsonrpc/http_test.go
index f8480bf32e15ad428209eedb72757a299455eb20..576591940dd3021e7bbd9d2eda0ac5498391a1f7 100644
--- a/protocol/jsonrpc/http_test.go
+++ b/protocol/jsonrpc/http_test.go
@@ -48,7 +48,15 @@ type (
 	}
 )
 
-func TestHTTPClient_Call(t *testing.T) {
+const (
+	mockJsonCommonUrl = "jsonrpc://127.0.0.1:20001/UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
+		"side=provider&timeout=3000&timestamp=1556509797245&bean.name=UserProvider"
+)
+
+func TestHTTPClientCall(t *testing.T) {
 
 	methods, err := common.ServiceMap.Register("com.ikurento.user.UserProvider", "jsonrpc", &UserProvider{})
 	assert.NoError(t, err)
@@ -56,11 +64,7 @@ func TestHTTPClient_Call(t *testing.T) {
 
 	// Export
 	proto := GetProtocol()
-	url, err := common.NewURL("jsonrpc://127.0.0.1:20001/UserProvider?anyhost=true&" +
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
-		"side=provider&timeout=3000&timestamp=1556509797245&bean.name=UserProvider")
+	url, err := common.NewURL(mockJsonCommonUrl)
 	assert.NoError(t, err)
 	proto.Export(&proxy_factory.ProxyInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
diff --git a/protocol/jsonrpc/json.go b/protocol/jsonrpc/json.go
index d1c2a858b4e4223ac32fc1160b56f6ee1862c8ce..7b05a229437958b44a405780bbe1649a995478d0 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,11 +64,12 @@ 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 {
-		msg, err := json.Marshal(err.Error())
-		if err != nil {
+		msg, retryErr := json.Marshal(err.Error())
+		if retryErr != nil {
 			msg = []byte("jsonrpc2.Error: json.Marshal failed")
 		}
 		return fmt.Sprintf(`{"code":%d,"message":%s}`, -32001, string(msg))
@@ -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.
@@ -122,10 +124,8 @@ func (c *jsonClientCodec) Write(d *CodecData) ([]byte, error) {
 	if param != nil {
 		switch k := reflect.TypeOf(param).Kind(); k {
 		case reflect.Map:
-			if reflect.TypeOf(param).Key().Kind() == reflect.String {
-				if reflect.ValueOf(param).IsNil() {
-					param = nil
-				}
+			if reflect.TypeOf(param).Key().Kind() == reflect.String && reflect.ValueOf(param).IsNil() {
+				param = nil
 			}
 		case reflect.Slice:
 			if reflect.ValueOf(param).IsNil() {
@@ -133,12 +133,10 @@ func (c *jsonClientCodec) Write(d *CodecData) ([]byte, error) {
 			}
 		case reflect.Array, reflect.Struct:
 		case reflect.Ptr:
-			switch k := reflect.TypeOf(param).Elem().Kind(); k {
+			switch ptrK := reflect.TypeOf(param).Elem().Kind(); ptrK {
 			case reflect.Map:
-				if reflect.TypeOf(param).Elem().Key().Kind() == reflect.String {
-					if reflect.ValueOf(param).Elem().IsNil() {
-						param = nil
-					}
+				if reflect.TypeOf(param).Elem().Key().Kind() == reflect.String && reflect.ValueOf(param).Elem().IsNil() {
+					param = nil
 				}
 			case reflect.Slice:
 				if reflect.ValueOf(param).Elem().IsNil() {
@@ -146,7 +144,7 @@ func (c *jsonClientCodec) Write(d *CodecData) ([]byte, error) {
 				}
 			case reflect.Array, reflect.Struct:
 			default:
-				return nil, perrors.New("unsupported param type: Ptr to " + k.String())
+				return nil, perrors.New("unsupported param type: Ptr to " + ptrK.String())
 			}
 		default:
 			return nil, perrors.New("unsupported param type: " + k.String())
@@ -170,6 +168,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 +222,7 @@ func (r *serverRequest) reset() {
 	}
 }
 
+// UnmarshalJSON unmarshals JSON for server request.
 func (r *serverRequest) UnmarshalJSON(raw []byte) error {
 	r.reset()
 
@@ -281,7 +281,7 @@ type serverResponse struct {
 	Error   interface{}      `json:"error,omitempty"`
 }
 
-// ServerCodec ...
+// ServerCodec is codec data for request server.
 type ServerCodec struct {
 	req serverRequest
 }
@@ -296,7 +296,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 +328,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 +339,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 +362,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 +380,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/json_test.go b/protocol/jsonrpc/json_test.go
index ade74246121b5f275c8dbeaa5923228dbab2804f..a3814e9ad5e1df2c3a8d8cc4305e5787b44596ec 100644
--- a/protocol/jsonrpc/json_test.go
+++ b/protocol/jsonrpc/json_test.go
@@ -30,7 +30,7 @@ type TestData struct {
 	Test string
 }
 
-func TestJsonClientCodec_Write(t *testing.T) {
+func TestJsonClientCodecWrite(t *testing.T) {
 	cd := &CodecData{
 		ID:     1,
 		Method: "GetUser",
@@ -46,7 +46,7 @@ func TestJsonClientCodec_Write(t *testing.T) {
 	assert.EqualError(t, err, "unsupported param type: int")
 }
 
-func TestJsonClientCodec_Read(t *testing.T) {
+func TestJsonClientCodecRead(t *testing.T) {
 	codec := newJsonClientCodec()
 	codec.pending[1] = "GetUser"
 	rsp := &TestData{}
@@ -60,7 +60,7 @@ func TestJsonClientCodec_Read(t *testing.T) {
 	assert.EqualError(t, err, "{\"code\":-32000,\"message\":\"error\"}")
 }
 
-func TestServerCodec_Write(t *testing.T) {
+func TestServerCodecWrite(t *testing.T) {
 	codec := newServerCodec()
 	a := json.RawMessage([]byte("1"))
 	codec.req = serverRequest{Version: "1.0", Method: "GetUser", ID: &a}
@@ -73,7 +73,7 @@ func TestServerCodec_Write(t *testing.T) {
 	assert.Equal(t, "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"Test\":\"test\"},\"error\":{\"code\":-32000,\"message\":\"error\"}}\n", string(data))
 }
 
-func TestServerCodec_Read(t *testing.T) {
+func TestServerCodecRead(t *testing.T) {
 	codec := newServerCodec()
 	header := map[string]string{}
 	err := codec.ReadHeader(header, []byte("{\"jsonrpc\":\"2.0\",\"method\":\"GetUser\",\"params\":[\"args\",2],\"id\":1}\n"))
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_invoker_test.go b/protocol/jsonrpc/jsonrpc_invoker_test.go
index 0f14ba11e2dec18bbd4d63e87e8c0fb2727f3755..d7124ca07c6ba6d79dc72e7fb6bd98cd4b3a97b2 100644
--- a/protocol/jsonrpc/jsonrpc_invoker_test.go
+++ b/protocol/jsonrpc/jsonrpc_invoker_test.go
@@ -34,7 +34,7 @@ import (
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
-func TestJsonrpcInvoker_Invoke(t *testing.T) {
+func TestJsonrpcInvokerInvoke(t *testing.T) {
 
 	methods, err := common.ServiceMap.Register("UserProvider", "jsonrpc", &UserProvider{})
 	assert.NoError(t, err)
diff --git a/protocol/jsonrpc/jsonrpc_protocol.go b/protocol/jsonrpc/jsonrpc_protocol.go
index bed7099ab60a6c05c3799f993c0bb348a4b00f02..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.")
 
@@ -109,8 +109,8 @@ func (jp *JsonrpcProtocol) Destroy() {
 func (jp *JsonrpcProtocol) openServer(url common.URL) {
 	_, ok := jp.serverMap[url.Location]
 	if !ok {
-		_, ok := jp.ExporterMap().Load(strings.TrimPrefix(url.Path, "/"))
-		if !ok {
+		_, loadOk := jp.ExporterMap().Load(strings.TrimPrefix(url.Path, "/"))
+		if !loadOk {
 			panic("[JsonrpcProtocol]" + url.Key() + "is not existing")
 		}
 
@@ -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/jsonrpc_protocol_test.go b/protocol/jsonrpc/jsonrpc_protocol_test.go
index c00bed12fe9fbb4937f21810cee548a25e3b1c05..10a9016913c77551efc54a92149ef377ade399f5 100644
--- a/protocol/jsonrpc/jsonrpc_protocol_test.go
+++ b/protocol/jsonrpc/jsonrpc_protocol_test.go
@@ -34,7 +34,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-func TestJsonrpcProtocol_Export(t *testing.T) {
+func TestJsonrpcProtocolExport(t *testing.T) {
 	// Export
 	proto := GetProtocol()
 	url, err := common.NewURL("jsonrpc://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
@@ -65,7 +65,7 @@ func TestJsonrpcProtocol_Export(t *testing.T) {
 	assert.False(t, ok)
 }
 
-func TestJsonrpcProtocol_Refer(t *testing.T) {
+func TestJsonrpcProtocolRefer(t *testing.T) {
 	// Refer
 	proto := GetProtocol()
 	url, err := common.NewURL("jsonrpc://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
diff --git a/protocol/jsonrpc/server.go b/protocol/jsonrpc/server.go
index 8600f02dad3d32d797613823de0bbe40261d2e71..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)
@@ -349,9 +349,9 @@ func serveRequest(ctx context.Context,
 			constant.PATH_KEY:    path,
 			constant.VERSION_KEY: codec.req.Version}))
 		if err := result.Error(); err != nil {
-			rspStream, err := codec.Write(err.Error(), invalidRequest)
-			if err != nil {
-				return perrors.WithStack(err)
+			rspStream, codecErr := codec.Write(err.Error(), invalidRequest)
+			if codecErr != nil {
+				return perrors.WithStack(codecErr)
 			}
 			if errRsp := sendErrorResp(header, rspStream); errRsp != nil {
 				logger.Warnf("Exporter: sendErrorResp(header:%#v, error:%v) = error:%s",
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..2e9ffed06f03d196c91f6679df21538612bac405 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() {
-
+	return
 }
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/protocolwrapper/protocol_filter_wrapper_test.go b/protocol/protocolwrapper/protocol_filter_wrapper_test.go
index 8491d57462d47d6af72040d41b78dcb30e6da697..b03ea7b9b66d926aff8851f88e1bd7434b254903 100644
--- a/protocol/protocolwrapper/protocol_filter_wrapper_test.go
+++ b/protocol/protocolwrapper/protocol_filter_wrapper_test.go
@@ -36,7 +36,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 )
 
-func TestProtocolFilterWrapper_Export(t *testing.T) {
+func TestProtocolFilterWrapperExport(t *testing.T) {
 	filtProto := extension.GetProtocol(FILTER)
 	filtProto.(*ProtocolFilterWrapper).protocol = &protocol.BaseProtocol{}
 
@@ -48,7 +48,7 @@ func TestProtocolFilterWrapper_Export(t *testing.T) {
 	assert.True(t, ok)
 }
 
-func TestProtocolFilterWrapper_Refer(t *testing.T) {
+func TestProtocolFilterWrapperRefer(t *testing.T) {
 	filtProto := extension.GetProtocol(FILTER)
 	filtProto.(*ProtocolFilterWrapper).protocol = &protocol.BaseProtocol{}
 
diff --git a/protocol/rest/client/client_impl/resty_client.go b/protocol/rest/client/client_impl/resty_client.go
index b60f50a5a70cde01a051dbb2a4490cbb792e0116..f301d945045a445b5370252044442080f042d126 100644
--- a/protocol/rest/client/client_impl/resty_client.go
+++ b/protocol/rest/client/client_impl/resty_client.go
@@ -50,7 +50,7 @@ func NewRestyClient(restOption *client.RestOptions) client.RestClient {
 	client := resty.New()
 	client.SetTransport(
 		&http.Transport{
-			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
+			DialContext: func(_ context.Context, network, addr string) (net.Conn, error) {
 				c, err := net.DialTimeout(network, addr, restOption.ConnectTimeout)
 				if err != nil {
 					return nil, err
diff --git a/protocol/rest/config/reader/rest_config_reader_test.go b/protocol/rest/config/reader/rest_config_reader_test.go
index d2dba40b9b85a6cd7772e0fee619720c79e91eb4..c6f891262ce3ba5ec6645ade9084005d14716789 100644
--- a/protocol/rest/config/reader/rest_config_reader_test.go
+++ b/protocol/rest/config/reader/rest_config_reader_test.go
@@ -31,7 +31,7 @@ import (
 	"github.com/apache/dubbo-go/protocol/rest/config"
 )
 
-func TestRestConfigReader_ReadConsumerConfig(t *testing.T) {
+func TestRestConfigReaderReadConsumerConfig(t *testing.T) {
 	bs, err := yaml.LoadYMLConfig("./testdata/consumer_config.yml")
 	assert.NoError(t, err)
 	configReader := NewRestConfigReader()
@@ -40,7 +40,7 @@ func TestRestConfigReader_ReadConsumerConfig(t *testing.T) {
 	assert.NotEmpty(t, config.GetRestConsumerServiceConfigMap())
 }
 
-func TestRestConfigReader_ReadProviderConfig(t *testing.T) {
+func TestRestConfigReaderReadProviderConfig(t *testing.T) {
 	bs, err := yaml.LoadYMLConfig("./testdata/provider_config.yml")
 	assert.NoError(t, err)
 	configReader := NewRestConfigReader()
diff --git a/protocol/rest/rest_invoker_test.go b/protocol/rest/rest_invoker_test.go
index 2ea260c58d03c27a691e48b953ce6d64f75040a2..9df97a211e9d90daa3206b94926ceeac42df4606 100644
--- a/protocol/rest/rest_invoker_test.go
+++ b/protocol/rest/rest_invoker_test.go
@@ -39,7 +39,15 @@ import (
 	"github.com/apache/dubbo-go/protocol/rest/server/server_impl"
 )
 
-func TestRestInvoker_Invoke(t *testing.T) {
+const (
+	mockRestCommonUrl = "rest://127.0.0.1:8877/com.ikurento.user.UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
+		"side=provider&timeout=3000&timestamp=1556509797245"
+)
+
+func TestRestInvokerInvoke(t *testing.T) {
 	// Refer
 	proto := GetRestProtocol()
 	defer proto.Destroy()
@@ -55,11 +63,7 @@ func TestRestInvoker_Invoke(t *testing.T) {
 		chain.ProcessFilter(request, response)
 	})
 
-	url, err := common.NewURL("rest://127.0.0.1:8877/com.ikurento.user.UserProvider?anyhost=true&" +
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
-		"side=provider&timeout=3000&timestamp=1556509797245")
+	url, err := common.NewURL(mockRestCommonUrl)
 	assert.NoError(t, err)
 	_, err = common.ServiceMap.Register("UserProvider", url.Protocol, &UserProvider{})
 	assert.NoError(t, err)
diff --git a/protocol/rest/rest_protocol_test.go b/protocol/rest/rest_protocol_test.go
index 9117148777ca868cb7d2672236e800c836d3de84..9ff4e7df7fe41d7fd028bf476cc2192cf7cefcca 100644
--- a/protocol/rest/rest_protocol_test.go
+++ b/protocol/rest/rest_protocol_test.go
@@ -38,14 +38,10 @@ import (
 	rest_config "github.com/apache/dubbo-go/protocol/rest/config"
 )
 
-func TestRestProtocol_Refer(t *testing.T) {
+func TestRestProtocolRefer(t *testing.T) {
 	// Refer
 	proto := GetRestProtocol()
-	url, err := common.NewURL("rest://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" +
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
-		"side=provider&timeout=3000&timestamp=1556509797245")
+	url, err := common.NewURL(mockRestCommonUrl)
 	assert.NoError(t, err)
 	con := config.ConsumerConfig{
 		ConnectTimeout: 5 * time.Second,
@@ -71,14 +67,10 @@ func TestRestProtocol_Refer(t *testing.T) {
 	assert.Equal(t, 0, invokersLen)
 }
 
-func TestRestProtocol_Export(t *testing.T) {
+func TestRestProtocolExport(t *testing.T) {
 	// Export
 	proto := GetRestProtocol()
-	url, err := common.NewURL("rest://127.0.0.1:8888/com.ikurento.user.UserProvider?anyhost=true&" +
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
-		"side=provider&timeout=3000&timestamp=1556509797245")
+	url, err := common.NewURL(mockRestCommonUrl)
 	assert.NoError(t, err)
 	_, err = common.ServiceMap.Register("UserProvider", url.Protocol, &UserProvider{})
 	assert.NoError(t, err)
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..60becfb34135470b0e69972c25a743f44efe19d5 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,19 +163,19 @@ func endCount0(rpcStatus *RPCStatus, elapsed int64, succeeded bool) {
 	}
 }
 
-// CurrentTimeMillis ...
+// CurrentTimeMillis get current timestamp
 func CurrentTimeMillis() int64 {
 	return time.Now().UnixNano() / int64(time.Millisecond)
 }
 
 // Destroy is used to clean all status
 func CleanAllStatus() {
-	delete1 := func(key interface{}, value interface{}) bool {
+	delete1 := func(key, _ interface{}) bool {
 		methodStatistics.Delete(key)
 		return true
 	}
 	methodStatistics.Range(delete1)
-	delete2 := func(key interface{}, value interface{}) bool {
+	delete2 := func(key, _ interface{}) bool {
 		serviceStatistic.Delete(key)
 		return true
 	}
diff --git a/protocol/rpc_status_test.go b/protocol/rpc_status_test.go
index 611b7cba6e453cdf00624b4414d468278fd62cb1..cc12753cf25007ab6d1010836b203aee22d78ca9 100644
--- a/protocol/rpc_status_test.go
+++ b/protocol/rpc_status_test.go
@@ -30,10 +30,14 @@ import (
 	"github.com/apache/dubbo-go/common"
 )
 
+const (
+	mockCommonDubboUrl = "dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider"
+)
+
 func TestBeginCount(t *testing.T) {
 	defer CleanAllStatus()
 
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(mockCommonDubboUrl)
 	BeginCount(url, "test")
 	urlStatus := GetURLStatus(url)
 	methodStatus := GetMethodStatus(url, "test")
@@ -47,7 +51,7 @@ func TestBeginCount(t *testing.T) {
 func TestEndCount(t *testing.T) {
 	defer CleanAllStatus()
 
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(mockCommonDubboUrl)
 	EndCount(url, "test", 100, true)
 	urlStatus := GetURLStatus(url)
 	methodStatus := GetMethodStatus(url, "test")
@@ -60,7 +64,7 @@ func TestEndCount(t *testing.T) {
 func TestGetMethodStatus(t *testing.T) {
 	defer CleanAllStatus()
 
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(mockCommonDubboUrl)
 	status := GetMethodStatus(url, "test")
 	assert.NotNil(t, status)
 	assert.Equal(t, int32(0), status.total)
@@ -69,25 +73,25 @@ func TestGetMethodStatus(t *testing.T) {
 func TestGetUrlStatus(t *testing.T) {
 	defer CleanAllStatus()
 
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(mockCommonDubboUrl)
 	status := GetURLStatus(url)
 	assert.NotNil(t, status)
 	assert.Equal(t, int32(0), status.total)
 }
 
-func Test_beginCount0(t *testing.T) {
+func TestbeginCount0(t *testing.T) {
 	defer CleanAllStatus()
 
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(mockCommonDubboUrl)
 	status := GetURLStatus(url)
 	beginCount0(status)
 	assert.Equal(t, int32(1), status.active)
 }
 
-func Test_All(t *testing.T) {
+func TestAll(t *testing.T) {
 	defer CleanAllStatus()
 
-	url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider")
+	url, _ := common.NewURL(mockCommonDubboUrl)
 	request(url, "test", 100, false, true)
 	urlStatus := GetURLStatus(url)
 	methodStatus := GetMethodStatus(url, "test")
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/consul/listener.go b/registry/consul/listener.go
index b047a4c08c9f6c809ed3dca8bd0d06ceaa576cae..cf3888dd16ee4a9b504664383be69ca1faf4d842 100644
--- a/registry/consul/listener.go
+++ b/registry/consul/listener.go
@@ -142,7 +142,6 @@ func (l *consulListener) run() {
 func (l *consulListener) handler(idx uint64, raw interface{}) {
 	var (
 		service *consul.ServiceEntry
-		event   *registry.ServiceEvent
 		url     common.URL
 		ok      bool
 		err     error
@@ -183,11 +182,12 @@ func (l *consulListener) handler(idx uint64, raw interface{}) {
 	}
 
 	l.urls = newUrls
-	for _, event = range events {
+	for _, event := range events {
 		l.eventCh <- event
 	}
 }
 
+// Next returns the service event from consul.
 func (l *consulListener) Next() (*registry.ServiceEvent, error) {
 	select {
 	case event := <-l.eventCh:
@@ -197,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 c5b8510a6c87068a5b4f1ce52203d401a896a6c2..4ef87394687aecc8804b2cebedd58fc0e72e8e6e 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,7 @@ func newConsulRegistry(url *common.URL) (registry.Registry, error) {
 	return r, nil
 }
 
+// Register service to consul registry center
 func (r *consulRegistry) Register(url common.URL) error {
 	var err error
 
@@ -95,6 +95,7 @@ func (r *consulRegistry) register(url common.URL) error {
 	return r.client.Agent().ServiceRegister(service)
 }
 
+// Unregister service from consul registry center
 func (r *consulRegistry) Unregister(url common.URL) error {
 	var err error
 
@@ -112,6 +113,7 @@ func (r *consulRegistry) unregister(url common.URL) error {
 	return r.client.Agent().ServiceDeregister(buildId(url))
 }
 
+// Subscribe service from consul registry center
 func (r *consulRegistry) Subscribe(url *common.URL, notifyListener registry.NotifyListener) {
 	role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, ""))
 	if role == common.CONSUMER {
@@ -133,7 +135,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
 		}
 
@@ -156,10 +158,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:
@@ -169,6 +173,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 552aa57061c99bf92ff986b6e672743ebb375e76..e845db01f1b8f76897f2beeaee45a84537c96d83 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
@@ -61,7 +63,7 @@ type RegistryDirectory struct {
 	forbidden                      atomic.Bool
 }
 
-// NewRegistryDirectory ...
+// NewRegistryDirectory will create a new RegistryDirectory
 func NewRegistryDirectory(url *common.URL, registry registry.Registry) (cluster.Directory, error) {
 	if url.SubURL == nil {
 		return nil, perrors.Errorf("url is invalid, suburl can not be nil")
@@ -79,13 +81,14 @@ func NewRegistryDirectory(url *common.URL, registry registry.Registry) (cluster.
 	return dir, nil
 }
 
-//subscribe from registry
+// subscribe from registry
 func (dir *RegistryDirectory) subscribe(url *common.URL) {
 	dir.consumerConfigurationListener.addNotifyListener(dir)
 	dir.referenceConfigurationListener = newReferenceConfigurationListener(dir, url)
 	dir.registry.Subscribe(url, dir)
 }
 
+// Notify monitor changes from registry,and update the cacheServices
 func (dir *RegistryDirectory) Notify(event *registry.ServiceEvent) {
 	go dir.update(event)
 }
@@ -152,9 +155,11 @@ func (dir *RegistryDirectory) refreshInvokers(res *registry.ServiceEvent) {
 }
 
 func (dir *RegistryDirectory) toGroupInvokers() []protocol.Invoker {
-	newInvokersList := []protocol.Invoker{}
+	var (
+		err             error
+		newInvokersList []protocol.Invoker
+	)
 	groupInvokersMap := make(map[string][]protocol.Invoker)
-	groupInvokersList := []protocol.Invoker{}
 
 	dir.cacheInvokersMap.Range(func(key, value interface{}) bool {
 		newInvokersList = append(newInvokersList, value.(protocol.Invoker))
@@ -170,6 +175,7 @@ func (dir *RegistryDirectory) toGroupInvokers() []protocol.Invoker {
 			groupInvokersMap[group] = []protocol.Invoker{invoker}
 		}
 	}
+	groupInvokersList := make([]protocol.Invoker, 0, len(groupInvokersMap))
 	if len(groupInvokersMap) == 1 {
 		//len is 1 it means no group setting ,so do not need cluster again
 		for _, invokers := range groupInvokersMap {
@@ -178,9 +184,13 @@ func (dir *RegistryDirectory) toGroupInvokers() []protocol.Invoker {
 	} else {
 		for _, invokers := range groupInvokersMap {
 			staticDir := directory.NewStaticDirectory(invokers)
-			cluster := extension.GetCluster(dir.GetUrl().SubURL.GetParam(constant.CLUSTER_KEY, constant.DEFAULT_CLUSTER))
-			staticDir.BuildRouterChain(invokers)
-			groupInvokersList = append(groupInvokersList, cluster.Join(staticDir))
+			cst := extension.GetCluster(dir.GetUrl().SubURL.GetParam(constant.CLUSTER_KEY, constant.DEFAULT_CLUSTER))
+			err = staticDir.BuildRouterChain(invokers)
+			if err != nil {
+				logger.Error(err)
+				continue
+			}
+			groupInvokersList = append(groupInvokersList, cst.Join(staticDir))
 		}
 	}
 
@@ -244,6 +254,7 @@ func (dir *RegistryDirectory) List(invocation protocol.Invocation) []protocol.In
 	return routerChain.Route(invokers, dir.cacheOriginUrl, invocation)
 }
 
+// IsAvailable  whether the directory is available
 func (dir *RegistryDirectory) IsAvailable() bool {
 	if !dir.BaseDirectory.IsAvailable() {
 		return dir.BaseDirectory.IsAvailable()
@@ -258,6 +269,7 @@ func (dir *RegistryDirectory) IsAvailable() bool {
 	return false
 }
 
+// Destroy method
 func (dir *RegistryDirectory) Destroy() {
 	//TODO:unregister & unsubscribe
 	dir.BaseDirectory.Destroy(func() {
@@ -297,6 +309,7 @@ func newReferenceConfigurationListener(dir *RegistryDirectory, url *common.URL)
 	return listener
 }
 
+// Process handle events and update Invokers
 func (l *referenceConfigurationListener) Process(event *config_center.ConfigChangeEvent) {
 	l.BaseConfigurationListener.Process(event)
 	l.directory.refreshInvokers(nil)
@@ -322,6 +335,7 @@ func (l *consumerConfigurationListener) addNotifyListener(listener registry.Noti
 	l.listeners = append(l.listeners, listener)
 }
 
+// Process handles events from Configuration Center and update Invokers
 func (l *consumerConfigurationListener) Process(event *config_center.ConfigChangeEvent) {
 	l.BaseConfigurationListener.Process(event)
 	l.directory.refreshInvokers(nil)
diff --git a/registry/directory/directory_test.go b/registry/directory/directory_test.go
index f1d5ce434aa00185f784f208eefe603274f05ab0..ac3f7124c12788959f529193b871652085fe6303 100644
--- a/registry/directory/directory_test.go
+++ b/registry/directory/directory_test.go
@@ -25,6 +25,7 @@ import (
 )
 
 import (
+	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -37,6 +38,7 @@ import (
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/config"
 	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/protocol/mock"
 	"github.com/apache/dubbo-go/protocol/protocolwrapper"
 	"github.com/apache/dubbo-go/registry"
 	"github.com/apache/dubbo-go/remoting"
@@ -169,7 +171,21 @@ Loop1:
 			break Loop1
 		}
 	}
+}
 
+func Test_toGroupInvokers(t *testing.T) {
+	registryDirectory, _ := normalRegistryDir()
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	invoker := mock.NewMockInvoker(ctrl)
+	newUrl, _ := common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+	invoker.EXPECT().GetUrl().Return(newUrl).AnyTimes()
+
+	registryDirectory.cacheInvokersMap.Store("group1", invoker)
+	registryDirectory.cacheInvokersMap.Store("group2", invoker)
+	registryDirectory.cacheInvokersMap.Store("group1", invoker)
+	groupInvokers := registryDirectory.toGroupInvokers()
+	assert.Len(t, groupInvokers, 2)
 }
 
 func normalRegistryDir(noMockEvent ...bool) (*RegistryDirectory, *registry.MockRegistry) {
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/listener_test.go b/registry/etcdv3/listener_test.go
index e691ae3cf1204ee97f130764496a7fc5bf67ac42..f27e7ce8ba5ab3515f8290b208b4823872ba48a3 100644
--- a/registry/etcdv3/listener_test.go
+++ b/registry/etcdv3/listener_test.go
@@ -24,9 +24,9 @@ import (
 )
 
 import (
+	"github.com/coreos/etcd/embed"
 	"github.com/dubbogo/getty"
 	"github.com/stretchr/testify/suite"
-	"go.etcd.io/etcd/embed"
 )
 
 import (
diff --git a/registry/etcdv3/registry.go b/registry/etcdv3/registry.go
index 5d389c36374fe9de5561418bc90d44a7d780fd48..f3df78177bda2b068d0ad88156b593ab3d48c5d7 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,27 +104,32 @@ 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), "")
 }
 
+// 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:] {
@@ -137,6 +142,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/event.go b/registry/event.go
index be9f11d00bb5a70b0d787d15bcdc98471aad0a4b..5fe6df6a379e1de8662917fb76c6d16fa9a17f37 100644
--- a/registry/event.go
+++ b/registry/event.go
@@ -36,7 +36,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_listener.go b/registry/event_listener.go
index b8d6148442d9e10e210958dead690c4a95b33fb6..1805f2833c96bd08c4cf9c92337d7d221e8829e9 100644
--- a/registry/event_listener.go
+++ b/registry/event_listener.go
@@ -36,6 +36,7 @@ type ConditionalEventListener interface {
 	Accept(e Event) bool
 }
 
+// ServiceInstancesChangedListener is used when the Service Discovery Changed
 // TODO (implement ConditionalEventListener)
 type ServiceInstancesChangedListener struct {
 	ServiceName string
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 c50b5b670a5491b9813652f7aa46bec18a35a7d7..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,67 +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")
@@ -253,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 8a02d0e3e693b58946a97e7b47238e0be4272dcf..f06d80124b7a627954ca3f4de0ae189e424708fd 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,10 +109,12 @@ 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), "")
 }
 
+// DoSubscribe actually subscribe the provider URL
 func (r *kubernetesRegistry) DoSubscribe(svc *common.URL) (registry.Listener, error) {
 
 	var (
@@ -139,6 +147,7 @@ func (r *kubernetesRegistry) DoSubscribe(svc *common.URL) (registry.Listener, er
 	return configListener, nil
 }
 
+// InitListeners init listeners of kubernetes registry center
 func (r *kubernetesRegistry) InitListeners() {
 	r.listener = kubernetes.NewEventListener(r.client)
 	r.configListener = NewConfigurationListener(r)
@@ -160,15 +169,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
@@ -176,7 +184,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")
 	}
@@ -184,6 +192,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 ea6d7663a9ceeab241c7a94a91f94288ab2990fc..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 {
 
-	t := s.T()
+	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]
 
-	r := s.initRegistry()
+	env := map[string]string{
+		nameSpaceKey:            currentPod.GetNamespace(),
+		podNameKey:              currentPod.GetName(),
+		needWatchedNameSpaceKey: "default",
+	}
+
+	for k, v := range env {
+		if err := os.Setenv(k, v); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	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() {
-		err := r.Register(url)
-		if err != nil {
-			t.Fatal(err)
+
+		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() {
-
-	t := s.T()
+func TestConsumerDestroy(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"),
@@ -105,11 +314,9 @@ func (s *KubernetesRegistryTestSuite) TestConsumerDestroy() {
 
 }
 
-func (s *KubernetesRegistryTestSuite) TestProviderDestroy() {
+func TestProviderDestroy(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"),
@@ -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 9591928eebd22bf2a99ec9dcfeb285c4519a3b90..2b83d5ab8892f673e1123cd01fa74e48e3d2dc22 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,23 +46,23 @@ 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
 }
 
-// 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{}
 }
@@ -71,7 +71,7 @@ func (r *MockRegistry) subscribe(*common.URL) (Listener, error) {
 	return r.listener, nil
 }
 
-// Subscribe ...
+// nolint
 func (r *MockRegistry) Subscribe(url *common.URL, notifyListener NotifyListener) {
 	go func() {
 		for {
@@ -123,7 +123,7 @@ func (*listener) Close() {
 
 }
 
-// MockEvent ...
+// nolint
 func (r *MockRegistry) MockEvent(event *ServiceEvent) {
 	r.listener.listenChan <- event
 }
diff --git a/registry/nacos/base_registry.go b/registry/nacos/base_registry.go
index 63f4999675470853d0f48d1a22b709efdc1c9d26..f09754ebfb069da892881ea0d1754dfb11746675 100644
--- a/registry/nacos/base_registry.go
+++ b/registry/nacos/base_registry.go
@@ -95,6 +95,7 @@ func getNacosConfig(url *common.URL) (map[string]interface{}, error) {
 	clientConfig.CacheDir = url.GetParam(constant.NACOS_CACHE_DIR_KEY, "")
 	clientConfig.LogDir = url.GetParam(constant.NACOS_LOG_DIR_KEY, "")
 	clientConfig.Endpoint = url.GetParam(constant.NACOS_ENDPOINT, "")
+	clientConfig.NamespaceId = url.GetParam(constant.NACOS_NAMESPACE_ID, "")
 	clientConfig.NotLoadCacheAtStart = true
 	configMap["clientConfig"] = clientConfig
 
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 a436b85064829b9f42c9dcc45545e5bf2fd2fefe..3eeb7680abb3da98f5ed08f1aea57d490b2caf85 100644
--- a/registry/nacos/registry.go
+++ b/registry/nacos/registry.go
@@ -123,6 +123,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)
@@ -140,7 +141,7 @@ func (nr *nacosRegistry) subscribe(conf *common.URL) (registry.Listener, error)
 	return NewNacosListener(*conf, nr.namingClient)
 }
 
-//subscribe from registry
+// subscribe from registry
 func (nr *nacosRegistry) Subscribe(url *common.URL, notifyListener registry.NotifyListener) {
 	for {
 		if !nr.IsAvailable() {
@@ -174,14 +175,17 @@ func (nr *nacosRegistry) Subscribe(url *common.URL, notifyListener registry.Noti
 	}
 }
 
+// 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 {
 	return true
 }
 
+// nolint
 func (nr *nacosRegistry) Destroy() {
 	return
 }
diff --git a/registry/nacos/registry_test.go b/registry/nacos/registry_test.go
index 7475b455c0dda09da65012465711ece264bb3dd5..d0311b200b27081c60bc97b2307a54774ca977bd 100644
--- a/registry/nacos/registry_test.go
+++ b/registry/nacos/registry_test.go
@@ -42,7 +42,7 @@ func TestNacosRegistry_Register(t *testing.T) {
 	urlMap.Set(constant.INTERFACE_KEY, "com.ikurento.user.UserProvider")
 	urlMap.Set(constant.VERSION_KEY, "1.0.0")
 	urlMap.Set(constant.CLUSTER_KEY, "mock")
-	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+	testUrl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	reg, err := newNacosRegistry(&regurl)
 	assert.Nil(t, err)
@@ -50,7 +50,7 @@ func TestNacosRegistry_Register(t *testing.T) {
 		t.Errorf("new nacos registry error:%s \n", err.Error())
 		return
 	}
-	err = reg.Register(url)
+	err = reg.Register(testUrl)
 	assert.Nil(t, err)
 	if err != nil {
 		t.Errorf("register error:%s \n", err.Error())
@@ -72,10 +72,10 @@ func TestNacosRegistry_Subscribe(t *testing.T) {
 	urlMap.Set(constant.VERSION_KEY, "1.0.0")
 	urlMap.Set(constant.CLUSTER_KEY, "mock")
 	urlMap.Set(constant.NACOS_PATH_KEY, "")
-	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+	testUrl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	reg, _ := newNacosRegistry(&regurl)
-	err := reg.Register(url)
+	err := reg.Register(testUrl)
 	assert.Nil(t, err)
 	if err != nil {
 		t.Errorf("new nacos registry error:%s \n", err.Error())
@@ -84,7 +84,7 @@ func TestNacosRegistry_Subscribe(t *testing.T) {
 
 	regurl.SetParam(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
 	reg2, _ := newNacosRegistry(&regurl)
-	listener, err := reg2.(*nacosRegistry).subscribe(&url)
+	listener, err := reg2.(*nacosRegistry).subscribe(&testUrl)
 	assert.Nil(t, err)
 	if err != nil {
 		t.Errorf("subscribe error:%s \n", err.Error())
diff --git a/registry/nacos/service_discovery.go b/registry/nacos/service_discovery.go
index 7d3406cac233dd5293c7522b4f12148fdcdd704e..2611a8dc58d2a45e578d90aa6a5d1aeb7e7f4f63 100644
--- a/registry/nacos/service_discovery.go
+++ b/registry/nacos/service_discovery.go
@@ -34,8 +34,9 @@ import (
 )
 
 const (
-	defaultGroup = "DEFAULT_GROUP"
-	idKey        = "id"
+	defaultGroup    = "DEFAULT_GROUP"
+	idKey           = "id"
+	defaultPageSize = 100
 )
 
 // init will put the service discovery into extension
@@ -92,7 +93,7 @@ func (n *nacosServiceDiscovery) Unregister(instance registry.ServiceInstance) er
 
 // GetDefaultPageSize will return the constant registry.DefaultPageSize
 func (n *nacosServiceDiscovery) GetDefaultPageSize() int {
-	return registry.DefaultPageSize
+	return defaultPageSize
 }
 
 // GetServices will return the all services
diff --git a/registry/nacos/service_discovery_test.go b/registry/nacos/service_discovery_test.go
index a756e8669301919d406a4bcf0e1c962cf532a5c6..04431a614b40288b2a21f75d69c4be313bd7721f 100644
--- a/registry/nacos/service_discovery_test.go
+++ b/registry/nacos/service_discovery_test.go
@@ -113,7 +113,7 @@ func TestNacosServiceDiscovery_CRUD(t *testing.T) {
 
 func TestNacosServiceDiscovery_GetDefaultPageSize(t *testing.T) {
 	serviceDiscovry, _ := extension.GetServiceDiscovery(constant.NACOS_KEY, mockUrl())
-	assert.Equal(t, registry.DefaultPageSize, serviceDiscovry.GetDefaultPageSize())
+	assert.Equal(t, defaultPageSize, serviceDiscovry.GetDefaultPageSize())
 }
 
 func mockUrl() *common.URL {
diff --git a/registry/protocol/protocol.go b/registry/protocol/protocol.go
index f57ecdf6809bcabc2eeeecbb7bff52e3962a1077..4c669b2cee74b95ceb3bc8287f145ccd6b99bc0b 100644
--- a/registry/protocol/protocol.go
+++ b/registry/protocol/protocol.go
@@ -22,7 +22,6 @@ import (
 	"strings"
 	"sync"
 )
-
 import (
 	gxset "github.com/dubbogo/gost/container/set"
 )
@@ -44,16 +43,21 @@ import (
 )
 
 var (
-	regProtocol *registryProtocol
-	once        sync.Once
+	regProtocol   *registryProtocol
+	once          sync.Once
+	reserveParams = []string{
+		"application", "codec", "exchanger", "serialization", "cluster", "connections", "deprecated", "group",
+		"loadbalance", "mock", "path", "timeout", "token", "version", "warmup", "weight", "timestamp", "dubbo",
+		"release", "interface",
+	}
 )
 
 type registryProtocol struct {
 	invokers []protocol.Invoker
 	// Registry  Map<RegistryAddress, Registry>
 	registries *sync.Map
-	//To solve the problem of RMI repeated exposure port conflicts, the services that have been exposed are no longer exposed.
-	//providerurl <--> exporter
+	// To solve the problem of RMI repeated exposure port conflicts, the services that have been exposed are no longer exposed.
+	// providerurl <--> exporter
 	bounds                        *sync.Map
 	overrideListeners             *sync.Map
 	serviceConfigurationListeners *sync.Map
@@ -66,10 +70,8 @@ func init() {
 }
 
 func getCacheKey(url *common.URL) string {
-	newUrl := url.Clone()
 	delKeys := gxset.NewSet("dynamic", "enabled")
-	newUrl.RemoveParams(delKeys)
-	return newUrl.String()
+	return url.CloneExceptParams(delKeys).String()
 }
 
 func newRegistryProtocol() *registryProtocol {
@@ -88,12 +90,34 @@ func getRegistry(regUrl *common.URL) registry.Registry {
 	return reg
 }
 
+func getUrlToRegistry(providerUrl *common.URL, registryUrl *common.URL) *common.URL {
+	if registryUrl.GetParamBool("simplified", false) {
+		return providerUrl.CloneWithParams(reserveParams)
+	} else {
+		return filterHideKey(providerUrl)
+	}
+}
+
+// filterHideKey filter the parameters that do not need to be output in url(Starting with .)
+func filterHideKey(url *common.URL) *common.URL {
+
+	// be careful params maps in url is map type
+	removeSet := gxset.NewSet()
+	for k, _ := range url.GetParams() {
+		if strings.HasPrefix(k, ".") {
+			removeSet.Add(k)
+		}
+	}
+	return url.CloneExceptParams(removeSet)
+}
+
 func (proto *registryProtocol) initConfigurationListeners() {
 	proto.overrideListeners = &sync.Map{}
 	proto.serviceConfigurationListeners = &sync.Map{}
 	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
@@ -111,7 +135,7 @@ func (proto *registryProtocol) Refer(url common.URL) protocol.Invoker {
 		reg = regI.(registry.Registry)
 	}
 
-	//new registry directory for store service url from registry
+	// new registry directory for store service url from registry
 	directory, err := extension.GetDefaultRegistryDirectory(&registryUrl, reg)
 	if err != nil {
 		logger.Errorf("consumer service %v  create registry directory  error, error message is %s, and will return nil invoker!",
@@ -125,7 +149,7 @@ func (proto *registryProtocol) Refer(url common.URL) protocol.Invoker {
 			serviceUrl.String(), registryUrl.String(), err.Error())
 	}
 
-	//new cluster invoker
+	// new cluster invoker
 	cluster := extension.GetCluster(serviceUrl.GetParam(constant.CLUSTER_KEY, constant.DEFAULT_CLUSTER))
 
 	invoker := cluster.Join(directory)
@@ -133,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()
@@ -150,7 +175,6 @@ func (proto *registryProtocol) Export(invoker protocol.Invoker) protocol.Exporte
 	serviceConfigurationListener.OverrideUrl(providerUrl)
 
 	var reg registry.Registry
-
 	if regI, loaded := proto.registries.Load(registryUrl.Key()); !loaded {
 		reg = getRegistry(registryUrl)
 		proto.registries.Store(registryUrl.Key(), reg)
@@ -158,7 +182,8 @@ func (proto *registryProtocol) Export(invoker protocol.Invoker) protocol.Exporte
 		reg = regI.(registry.Registry)
 	}
 
-	err := reg.Register(*providerUrl)
+	registeredProviderUrl := getUrlToRegistry(providerUrl, registryUrl)
+	err := reg.Register(*registeredProviderUrl)
 	if err != nil {
 		logger.Errorf("provider service %v register registry %v error, error message is %s",
 			providerUrl.Key(), registryUrl.Key(), err.Error())
@@ -190,7 +215,7 @@ func (proto *registryProtocol) reExport(invoker protocol.Invoker, newUrl *common
 		oldExporter.(protocol.Exporter).Unexport()
 		proto.bounds.Delete(key)
 		proto.Export(wrappedNewInvoker)
-		//TODO:  unregister & unsubscribe
+		// TODO:  unregister & unsubscribe
 
 	}
 }
@@ -206,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))
@@ -273,7 +299,7 @@ func isMatched(providerUrl *common.URL, consumerUrl *common.URL) bool {
 	providerGroup := providerUrl.GetParam(constant.GROUP_KEY, "")
 	providerVersion := providerUrl.GetParam(constant.VERSION_KEY, "")
 	providerClassifier := providerUrl.GetParam(constant.CLASSIFIER_KEY, "")
-	//todo: public static boolean isContains(String values, String value) {
+	// todo: public static boolean isContains(String values, String value) {
 	//        return isNotEmpty(values) && isContains(COMMA_SPLIT_PATTERN.split(values), value);
 	//    }
 	return (consumerGroup == constant.ANY_VALUE || consumerGroup == providerGroup ||
@@ -302,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()
@@ -326,9 +353,9 @@ func (proto *registryProtocol) Destroy() {
 }
 
 func getRegistryUrl(invoker protocol.Invoker) *common.URL {
-	//here add * for return a new url
+	// here add * for return a new url
 	url := invoker.GetUrl()
-	//if the protocol == registry ,set protocol the registry value in url.params
+	// if the protocol == registry ,set protocol the registry value in url.params
 	if url.Protocol == constant.REGISTRY_PROTOCOL {
 		protocol := url.GetParam(constant.REGISTRY_KEY, "")
 		url.Protocol = protocol
@@ -338,7 +365,7 @@ func getRegistryUrl(invoker protocol.Invoker) *common.URL {
 
 func getProviderUrl(invoker protocol.Invoker) *common.URL {
 	url := invoker.GetUrl()
-	//be careful params maps in url is map type
+	// be careful params maps in url is map type
 	return url.SubURL.Clone()
 }
 
@@ -366,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())
@@ -388,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 {
@@ -412,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/protocol/protocol_test.go b/registry/protocol/protocol_test.go
index cee2a6a625368f655d1b9bc5fe8cc37031e1aef7..15fd3cacfacad36309e0ad4deb3c7c7441e47e26 100644
--- a/registry/protocol/protocol_test.go
+++ b/registry/protocol/protocol_test.go
@@ -284,3 +284,12 @@ func TestExportWithApplicationConfig(t *testing.T) {
 	v2, _ := regProtocol.bounds.Load(getCacheKey(newUrl))
 	assert.NotNil(t, v2)
 }
+
+func TestGetProviderUrlWithHideKey(t *testing.T) {
+	url, _ := common.NewURL("dubbo://127.0.0.1:1111?a=a1&b=b1&.c=c1&.d=d1&e=e1&protocol=registry")
+	providerUrl := getUrlToRegistry(&url, &url)
+	assert.NotContains(t, providerUrl.GetParams(), ".c")
+	assert.NotContains(t, providerUrl.GetParams(), ".d")
+	assert.Contains(t, providerUrl.GetParams(), "a")
+
+}
diff --git a/registry/registry.go b/registry/registry.go
index d673864700e6ba99e8f0283247d53760b85598aa..5b37aa684ca90d1f18898b9f62f27d86a2c0fba3 100644
--- a/registry/registry.go
+++ b/registry/registry.go
@@ -45,13 +45,16 @@ type Registry interface {
 	Subscribe(*common.URL, NotifyListener)
 }
 
-// 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..1d5a3593e392083d2115222e131974b941a391c3 100644
--- a/registry/service_discovery.go
+++ b/registry/service_discovery.go
@@ -26,8 +26,7 @@ import (
 	gxpage "github.com/dubbogo/gost/page"
 )
 
-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 2cc229ee3b056da2d9f1a1b70d3e0f5858c9da5f..247c8567659d1d512a6685ddb0404fecd9968bcd 100644
--- a/registry/service_instance.go
+++ b/registry/service_instance.go
@@ -17,6 +17,7 @@
 
 package registry
 
+// 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/zookeeper/registry.go b/registry/zookeeper/registry.go
index 88d5d6221b4bc7136ba4c3e7c95fb53ba35a9a58..1e7bd08adef5ac9920413fd198b726f49c11ecd4 100644
--- a/registry/zookeeper/registry.go
+++ b/registry/zookeeper/registry.go
@@ -86,12 +86,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) {
@@ -116,6 +116,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()
@@ -141,35 +142,43 @@ 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)
 }
 
+// DoSubscribe actually subscribes the provider URL
 func (r *zkRegistry) DoSubscribe(conf *common.URL) (registry.Listener, error) {
 	return r.getListener(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..b337c79584cc5058e89bd582b007e72fb10da7ee 100644
--- a/remoting/etcdv3/client.go
+++ b/remoting/etcdv3/client.go
@@ -45,13 +45,12 @@ const (
 )
 
 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 +59,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{
@@ -131,7 +130,7 @@ func ValidateClient(container clientFacade, opts ...Option) error {
 	return nil
 }
 
-// Client ...
+// Client represents etcd client Configuration
 type Client struct {
 	lock sync.RWMutex
 
@@ -142,7 +141,7 @@ 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{}
@@ -206,7 +205,7 @@ func (c *Client) stop() bool {
 	return false
 }
 
-// Close ...
+// nolint
 func (c *Client) Close() {
 
 	if c == nil {
@@ -265,8 +264,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()
@@ -325,7 +323,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 +423,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 +445,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 +455,7 @@ func (c *Client) Create(k string, v string) error {
 	return nil
 }
 
-// Delete ...
+// nolint
 func (c *Client) Delete(k string) error {
 
 	err := c.delete(k)
@@ -468,7 +466,7 @@ func (c *Client) Delete(k string) error {
 	return nil
 }
 
-// RegisterTemp ...
+// RegisterTemp registers a temporary node
 func (c *Client) RegisterTemp(basePath string, node string) (string, error) {
 
 	completeKey := path.Join(basePath, node)
@@ -481,7 +479,7 @@ func (c *Client) RegisterTemp(basePath string, node string) (string, error) {
 	return completeKey, 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 +489,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 +500,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 +510,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 895cc2954adf93b5899d0ae5daedbd35834b7ef4..9a5ef60993598cf93c469989d68c991657bd5fb8 100644
--- a/remoting/etcdv3/client_test.go
+++ b/remoting/etcdv3/client_test.go
@@ -29,11 +29,11 @@ import (
 )
 
 import (
+	"github.com/coreos/etcd/embed"
 	"github.com/coreos/etcd/mvcc/mvccpb"
 	perrors "github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/suite"
-	"go.etcd.io/etcd/embed"
 	"google.golang.org/grpc/connectivity"
 )
 
@@ -154,7 +154,7 @@ func (suite *ClientTestSuite) TestClientValid() {
 	c := suite.client
 	t := suite.T()
 
-	if c.Valid() != true {
+	if !c.Valid() {
 		t.Fatal("client is not valid")
 	}
 	c.Close()
@@ -174,7 +174,7 @@ func (suite *ClientTestSuite) TestClientDone() {
 
 	c.Wait.Wait()
 
-	if c.Valid() == true {
+	if c.Valid() {
 		suite.T().Fatal("client should be invalid then")
 	}
 }
diff --git a/remoting/etcdv3/facade.go b/remoting/etcdv3/facade.go
index 35befc85e449ec02a6377faec300aa6b46bcc8bf..2edbb6650890d6d655d8356e1c0a2979a022f0a8 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 (
@@ -85,10 +85,8 @@ LOOP:
 				)
 				logger.Infof("ETCDV3ProviderRegistry.validateETCDV3Client(etcd Addr{%s}) = error{%#v}",
 					endpoint, perrors.WithStack(err))
-				if err == nil {
-					if r.RestartCallBack() {
-						break
-					}
+				if err == nil && r.RestartCallBack() {
+					break
 				}
 				failTimes++
 				if MaxFailTimes <= failTimes {
diff --git a/remoting/etcdv3/listener.go b/remoting/etcdv3/listener.go
index e3cb74e4f676efa1f325ac45e32b21b39d1bbd6a..00b5b19b36d3baa8871efdd3d53e80f05d7aeac1 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..d6c5a2e88057459c0a87cd9a607e9c10970b07b2 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,255 +59,236 @@ var tests = []struct {
 // test dataset prefix
 const prefix = "name"
 
-var clientPodJsonData = `{
+var (
+	watcherStopLog = "the watcherSet watcher was stopped"
+)
+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 {
+	if !client.Valid() {
 		t.Fatal("client is not valid")
 	}
 
 	client.Close()
-	if client.Valid() != false {
+	if client.Valid() {
 		t.Fatal("client is valid")
 	}
 }
 
-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")
+	if client.Valid() {
+		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 +303,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{}
@@ -360,7 +334,7 @@ func (s *KubernetesClientTestSuite) TestClientGetChildrenKVList() {
 					return
 				}
 			case <-done:
-				t.Log("the watcherSet watcher was stopped")
+				t.Log(watcherStopLog)
 				return
 			}
 		}
@@ -407,11 +381,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)
@@ -430,7 +402,7 @@ func (s *KubernetesClientTestSuite) TestClientWatchPrefix() {
 			case e := <-wc:
 				t.Logf("got event %v k %s v %s", e.EventType, e.Key, e.Value)
 			case <-done:
-				t.Log("the watcherSet watcher was stopped")
+				t.Log(watcherStopLog)
 				return
 			}
 		}
@@ -452,22 +424,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)
@@ -485,7 +444,7 @@ func (s *KubernetesClientTestSuite) TestClientWatch() {
 			case e := <-wc:
 				t.Logf("got event %v k %s v %s", e.EventType, e.Key, e.Value)
 			case <-done:
-				t.Log("the watcherSet watcher was stopped")
+				t.Log(watcherStopLog)
 				return
 			}
 		}
@@ -507,7 +466,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..65c5d715a38bd0862245255e0276ff5e959de3a3 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,32 @@ 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() {
+	// TODO implementation me
+}
 
-	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/zookeeper/client.go b/remoting/zookeeper/client.go
index bd1da547766abb12dc742234787262212e3db314..226ec24085ddd0cfaea0c0d6a0ba6c91a9840ad0 100644
--- a/remoting/zookeeper/client.go
+++ b/remoting/zookeeper/client.go
@@ -47,11 +47,11 @@ var (
 	errNilNode         = perrors.Errorf("node does not exist")
 )
 
-// ZookeeperClient ...
+// ZookeeperClient represents zookeeper client Configuration
 type ZookeeperClient struct {
 	name          string
 	ZkAddrs       []string
-	sync.Mutex    // for conn
+	sync.RWMutex  // for conn
 	Conn          *zk.Conn
 	Timeout       time.Duration
 	exit          chan struct{}
@@ -59,7 +59,7 @@ type ZookeeperClient struct {
 	eventRegistry map[string][]*chan struct{}
 }
 
-// StateToString ...
+// nolint
 func StateToString(state zk.State) string {
 	switch state {
 	case zk.StateDisconnected:
@@ -87,11 +87,9 @@ func StateToString(state zk.State) string {
 	default:
 		return state.String()
 	}
-
-	return "zookeeper unknown state"
 }
 
-// Options ...
+// nolint
 type Options struct {
 	zkName string
 	client *ZookeeperClient
@@ -99,24 +97,22 @@ 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
-	)
-	opions := &Options{}
+	var err error
+	options := &Options{}
 	for _, opt := range opts {
-		opt(opions)
+		opt(options)
 	}
 	connected := false
 	err = nil
@@ -129,17 +125,18 @@ func ValidateZookeeperClient(container zkClientFacade, opts ...Option) error {
 
 	if container.ZkClient() == nil {
 		//in dubbo ,every registry only connect one node ,so this is []string{r.Address}
-		timeout, err := time.ParseDuration(url.GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT))
+		var timeout time.Duration
+		timeout, err = time.ParseDuration(url.GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT))
 		if err != nil {
 			logger.Errorf("timeout config %v is invalid ,err is %v",
 				url.GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT), err.Error())
 			return perrors.WithMessagef(err, "newZookeeperClient(address:%+v)", url.Location)
 		}
 		zkAddresses := strings.Split(url.Location, ",")
-		newClient, err := newZookeeperClient(opions.zkName, zkAddresses, timeout)
+		newClient, err := newZookeeperClient(options.zkName, zkAddresses, timeout)
 		if err != nil {
 			logger.Warnf("newZookeeperClient(name{%s}, zk address{%v}, timeout{%d}) = error{%v}",
-				opions.zkName, url.Location, timeout.String(), err)
+				options.zkName, url.Location, timeout.String(), err)
 			return perrors.WithMessagef(err, "newZookeeperClient(address:%+v)", url.Location)
 		}
 		container.SetZkClient(newClient)
@@ -157,7 +154,7 @@ func ValidateZookeeperClient(container zkClientFacade, opts ...Option) error {
 	}
 
 	if connected {
-		logger.Info("Connect to zookeeper successfully, name{%s}, zk address{%v}", opions.zkName, url.Location)
+		logger.Info("Connect to zookeeper successfully, name{%s}, zk address{%v}", options.zkName, url.Location)
 		container.WaitGroup().Add(1) //zk client start successful, then registry wg +1
 	}
 
@@ -190,14 +187,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
@@ -229,21 +226,15 @@ func NewMockZookeeperClient(name string, timeout time.Duration, opts ...Option)
 		}
 	}
 
-	//callbackChan := make(chan zk.Event)
-	//f := func(event zk.Event) {
-	//	callbackChan <- event
-	//}
-
 	z.Conn, event, err = ts.ConnectWithOptions(timeout)
 	if err != nil {
 		return nil, nil, nil, perrors.WithMessagef(err, "zk.Connect")
 	}
-	//z.wait.Add(1)
 
 	return ts, z, event, nil
 }
 
-// HandleZkEvent ...
+// HandleZkEvent handles zookeeper events
 func (z *ZookeeperClient) HandleZkEvent(session <-chan zk.Event) {
 	var (
 		state int
@@ -304,7 +295,7 @@ LOOP:
 	}
 }
 
-// RegisterEvent ...
+// RegisterEvent registers zookeeper events
 func (z *ZookeeperClient) RegisterEvent(zkPath string, event *chan struct{}) {
 	if zkPath == "" || event == nil {
 		return
@@ -319,7 +310,7 @@ func (z *ZookeeperClient) RegisterEvent(zkPath string, event *chan struct{}) {
 	z.Unlock()
 }
 
-// UnregisterEvent ...
+// UnregisterEvent unregisters zookeeper events
 func (z *ZookeeperClient) UnregisterEvent(zkPath string, event *chan struct{}) {
 	if zkPath == "" {
 		return
@@ -346,7 +337,7 @@ func (z *ZookeeperClient) UnregisterEvent(zkPath string, event *chan struct{}) {
 	}
 }
 
-// Done ...
+// nolint
 func (z *ZookeeperClient) Done() <-chan struct{} {
 	return z.exit
 }
@@ -362,7 +353,7 @@ func (z *ZookeeperClient) stop() bool {
 	return false
 }
 
-// ZkConnValid ...
+// ZkConnValid validates zookeeper connection
 func (z *ZookeeperClient) ZkConnValid() bool {
 	select {
 	case <-z.exit:
@@ -380,7 +371,7 @@ func (z *ZookeeperClient) ZkConnValid() bool {
 	return valid
 }
 
-// Close ...
+// nolint
 func (z *ZookeeperClient) Close() {
 	if z == nil {
 		return
@@ -439,7 +430,7 @@ func (z *ZookeeperClient) CreateWithValue(basePath string, value []byte) error {
 	return nil
 }
 
-// Delete ...
+// nolint
 func (z *ZookeeperClient) Delete(basePath string) error {
 	var (
 		err error
@@ -456,7 +447,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
@@ -475,7 +466,6 @@ func (z *ZookeeperClient) RegisterTemp(basePath string, node string) (string, er
 		tmpPath, err = conn.Create(zkPath, data, zk.FlagEphemeral, zk.WorldACL(zk.PermAll))
 	}
 
-	//if err != nil && err != zk.ErrNodeExists {
 	if err != nil {
 		logger.Warnf("conn.Create(\"%s\", zk.FlagEphemeral) = error(%v)\n", zkPath, perrors.WithStack(err))
 		return zkPath, perrors.WithStack(err)
@@ -485,7 +475,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
@@ -516,7 +506,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
@@ -553,7 +543,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
@@ -586,7 +576,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
@@ -614,7 +604,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 cb41eb326be95470e39694fc5df233fdf073b905..0f6899568ad4744dc58022c41e22db6f901ad5de 100644
--- a/remoting/zookeeper/client_test.go
+++ b/remoting/zookeeper/client_test.go
@@ -106,7 +106,6 @@ func TestCreateDelete(t *testing.T) {
 	assert.NoError(t, err)
 	err2 := z.Delete("/test1/test2/test3/test4")
 	assert.NoError(t, err2)
-	//verifyEventOrder(t, event, []zk.EventType{zk.EventNodeCreated}, "event channel")
 }
 
 func TestRegisterTemp(t *testing.T) {
diff --git a/remoting/zookeeper/facade.go b/remoting/zookeeper/facade.go
index 4e3945388ff402f60a02150615a8914f9cba2435..f9b9332504f445724a54b94356771e4ad49b62f0 100644
--- a/remoting/zookeeper/facade.go
+++ b/remoting/zookeeper/facade.go
@@ -40,7 +40,7 @@ type zkClientFacade interface {
 	common.Node
 }
 
-// HandleClientRestart ...
+// HandleClientRestart keeps the connection between client and server
 func HandleClientRestart(r zkClientFacade) {
 	var (
 		err error
@@ -78,10 +78,8 @@ LOOP:
 				err = ValidateZookeeperClient(r, WithZkName(zkName))
 				logger.Infof("ZkProviderRegistry.validateZookeeperClient(zkAddr{%s}) = error{%#v}",
 					zkAddress, perrors.WithStack(err))
-				if err == nil {
-					if r.RestartCallBack() {
-						break
-					}
+				if err == nil && r.RestartCallBack() {
+					break
 				}
 				failTimes++
 				if MaxFailTimes <= failTimes {
diff --git a/remoting/zookeeper/listener.go b/remoting/zookeeper/listener.go
index 84877667763ce870e76202844e9dc9dc1c3f008c..5188ce8c44355cf78eeb8c6078ab4f2f49e516db 100644
--- a/remoting/zookeeper/listener.go
+++ b/remoting/zookeeper/listener.go
@@ -18,7 +18,6 @@
 package zookeeper
 
 import (
-	"github.com/apache/dubbo-go/common"
 	"path"
 	"strings"
 	"sync"
@@ -32,12 +31,13 @@ import (
 )
 
 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/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,12 +53,12 @@ func NewZkEventListener(client *ZookeeperClient) *ZkEventListener {
 	}
 }
 
-// SetClient ...
+// nolint
 func (l *ZkEventListener) SetClient(client *ZookeeperClient) {
 	l.client = client
 }
 
-// ListenServiceNodeEvent ...
+// nolint
 func (l *ZkEventListener) ListenServiceNodeEvent(zkPath string, listener ...remoting.DataListener) bool {
 	defer l.wg.Done()
 	var zkEvent zk.Event
@@ -96,8 +96,6 @@ func (l *ZkEventListener) ListenServiceNodeEvent(zkPath string, listener ...remo
 			return false
 		}
 	}
-
-	return false
 }
 
 func (l *ZkEventListener) handleZkNodeEvent(zkPath string, children []string, listener remoting.DataListener) {
@@ -249,8 +247,14 @@ func (l *ZkEventListener) listenDirEvent(conf *common.URL, zkPath string, listen
 			l.pathMapLock.Lock()
 			l.pathMap[dubboPath] = struct{}{}
 			l.pathMapLock.Unlock()
-
+			//When Zk disconnected, the Conn will be set to nil, so here need check the value of Conn
+			l.client.RLock()
+			if l.client.Conn == nil {
+				l.client.RUnlock()
+				break
+			}
 			content, _, err := l.client.Conn.Get(dubboPath)
+			l.client.RUnlock()
 			if err != nil {
 				logger.Errorf("Get new node path {%v} 's content error,message is  {%v}", dubboPath, perrors.WithStack(err))
 			}
@@ -314,7 +318,7 @@ func (l *ZkEventListener) valid() bool {
 	return l.client.ZkConnValid()
 }
 
-// Close ...
+// nolint
 func (l *ZkEventListener) Close() {
 	l.wg.Wait()
 }
diff --git a/remoting/zookeeper/listener_test.go b/remoting/zookeeper/listener_test.go
index ba7d6ba81b6af97dc5ad3788e8399d08cbe5b2bb..37ef1b4b967d2f6708a4a099875ae90f273ae483 100644
--- a/remoting/zookeeper/listener_test.go
+++ b/remoting/zookeeper/listener_test.go
@@ -32,6 +32,10 @@ import (
 	"github.com/apache/dubbo-go/remoting"
 )
 
+var (
+	dubboPropertiesPath = "/dubbo/dubbo.properties"
+)
+
 func initZkData(t *testing.T) (*zk.TestCluster, *ZookeeperClient, <-chan zk.Event) {
 	ts, client, event, err := NewMockZookeeperClient("test", 15*time.Second)
 	assert.NoError(t, err)
@@ -58,10 +62,10 @@ func initZkData(t *testing.T) (*zk.TestCluster, *ZookeeperClient, <-chan zk.Even
 	dubbo.service.com.ikurento.user.UserProvider.cluster=failover
 `
 
-	err = client.Create("/dubbo/dubbo.properties")
+	err = client.Create(dubboPropertiesPath)
 	assert.NoError(t, err)
 
-	_, err = client.Conn.Set("/dubbo/dubbo.properties", []byte(data), 0)
+	_, err = client.Conn.Set(dubboPropertiesPath, []byte(data), 0)
 	assert.NoError(t, err)
 
 	return ts, client, event
@@ -99,7 +103,7 @@ func TestListener(t *testing.T) {
 	dataListener := &mockDataListener{client: client, changedData: changedData, wait: &wait}
 	listener.ListenServiceEvent(nil, "/dubbo", dataListener)
 	time.Sleep(1 * time.Second)
-	_, err := client.Conn.Set("/dubbo/dubbo.properties", []byte(changedData), 1)
+	_, err := client.Conn.Set(dubboPropertiesPath, []byte(changedData), 1)
 	assert.NoError(t, err)
 	wait.Wait()
 	assert.Equal(t, changedData, dataListener.eventList[1].Content)
diff --git a/test/integrate/dubbo/go-client/Dockerfile b/test/integrate/dubbo/go-client/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..d48df36dc72d7e75f8c2c8c91d5acbb01e39757d
--- /dev/null
+++ b/test/integrate/dubbo/go-client/Dockerfile
@@ -0,0 +1,36 @@
+#
+#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.
+#
+
+FROM golang
+
+WORKDIR /go/src/github.com/apache/dubbo-go/test/integrate/dubbo/go-client
+
+ENV CONF_CONSUMER_FILE_PATH "client.yml"
+ENV APP_LOG_CONF_FILE "log.yml"
+
+ARG PR_ORIGIN_REPO
+ARG PR_ORIGIN_COMMITID
+
+ADD . /go/src/github.com/apache/dubbo-go/test/integrate/dubbo/go-client
+
+# update dubbo-go to current commit id
+RUN test ${PR_ORIGIN_REPO} && echo "github.com/apache/dubbo-go will be replace to github.com/${PR_ORIGIN_REPO}@${PR_ORIGIN_COMMITID}" || echo 'go get github.com/apache/dubbo-go@develop'
+RUN test ${PR_ORIGIN_REPO} && go mod edit  -replace=github.com/apache/dubbo-go=github.com/${PR_ORIGIN_REPO}@${PR_ORIGIN_COMMITID} || go get -u github.com/apache/dubbo-go@develop
+
+RUN go install github.com/apache/dubbo-go/test/integrate/dubbo/go-client
+
+CMD go-client
\ No newline at end of file
diff --git a/test/integrate/dubbo/go-client/client.go b/test/integrate/dubbo/go-client/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..4c62674d33dba7caca72ca7552e73c4c0fdf14c9
--- /dev/null
+++ b/test/integrate/dubbo/go-client/client.go
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+	"context"
+	"fmt"
+	"time"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+	_ "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"
+
+	_ "github.com/apache/dubbo-go/filter/filter_impl"
+
+	_ "github.com/apache/dubbo-go/cluster/cluster_impl"
+	_ "github.com/apache/dubbo-go/cluster/loadbalance"
+	_ "github.com/apache/dubbo-go/registry/zookeeper"
+)
+
+var (
+	survivalTimeout int = 10e9
+)
+
+func println(format string, args ...interface{}) {
+	fmt.Printf("\033[32;40m"+format+"\033[0m\n", args...)
+}
+
+// they are necessary:
+// 		export CONF_CONSUMER_FILE_PATH="xxx"
+// 		export APP_LOG_CONF_FILE="xxx"
+func main() {
+	hessian.RegisterPOJO(&User{})
+	config.Load()
+	time.Sleep(3e9)
+
+	println("\n\n\nstart to test dubbo")
+
+	go func() {
+		select {
+		case <-time.After(time.Minute):
+			panic("provider not start after client already running 1min")
+		}
+	}()
+	user := &User{}
+	err := userProvider.GetUser(context.TODO(), []interface{}{"A001"}, user)
+	if err != nil {
+		panic(err)
+	}
+	println("response result: %v\n", user)
+}
diff --git a/test/integrate/dubbo/go-client/client.yml b/test/integrate/dubbo/go-client/client.yml
new file mode 100644
index 0000000000000000000000000000000000000000..df44a13da38a14fa4a81b6189aa05708cf6f5599
--- /dev/null
+++ b/test/integrate/dubbo/go-client/client.yml
@@ -0,0 +1,61 @@
+# dubbo client yaml configure file
+
+
+check: true
+# client
+request_timeout : "3s"
+# connect timeout
+connect_timeout : "3s"
+
+# application config
+application:
+  organization : "ikurento.com"
+  name  : "BDTService"
+  module : "dubbogo user-info client"
+  version : "0.0.1"
+  owner : "ZX"
+  environment : "dev"
+
+registries :
+  "demoZk":
+    protocol: "zookeeper"
+    timeout	: "3s"
+    address: "127.0.0.1:2181"
+    username: ""
+    password: ""
+
+
+references:
+  "UserProvider":
+    # 鍙互鎸囧畾澶氫釜registry锛屼娇鐢ㄩ€楀彿闅斿紑;涓嶆寚瀹氶粯璁ゅ悜鎵€鏈夋敞鍐屼腑蹇冩敞鍐�
+    registry: "demoZk"
+    protocol : "dubbo"
+    interface : "com.ikurento.user.UserProvider"
+    cluster: "failover"
+    methods :
+    - name: "GetUser"
+      retries: 3
+
+
+protocol_conf:
+  dubbo:
+    reconnect_interval: 0
+    connection_number: 2
+    heartbeat_period: "5s"
+    session_timeout: "20s"
+    pool_size: 64
+    pool_ttl: 600
+    getty_session_param:
+      compress_encoding: false
+      tcp_no_delay: true
+      tcp_keep_alive: true
+      keep_alive_period: "120s"
+      tcp_r_buf_size: 262144
+      tcp_w_buf_size: 65536
+      pkg_rq_size: 1024
+      pkg_wq_size: 512
+      tcp_read_timeout: "1s"
+      tcp_write_timeout: "5s"
+      wait_timeout: "1s"
+      max_msg_len: 1024000
+      session_name: "client"
diff --git a/test/integrate/dubbo/go-client/go.mod b/test/integrate/dubbo/go-client/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..4708eb1f0f48c10acc254880ecb6dad3a03529f2
--- /dev/null
+++ b/test/integrate/dubbo/go-client/go.mod
@@ -0,0 +1,3 @@
+module github.com/apache/dubbo-go/test/integrate/dubbo/go-client
+
+go 1.13
diff --git a/test/integrate/dubbo/go-client/log.yml b/test/integrate/dubbo/go-client/log.yml
new file mode 100644
index 0000000000000000000000000000000000000000..59fa4279ad85272c4c49d532beaf23b74d00f58a
--- /dev/null
+++ b/test/integrate/dubbo/go-client/log.yml
@@ -0,0 +1,28 @@
+
+level: "debug"
+development: true
+disableCaller: false
+disableStacktrace: false
+sampling:
+encoding: "console"
+
+# encoder
+encoderConfig:
+  messageKey: "message"
+  levelKey: "level"
+  timeKey: "time"
+  nameKey: "logger"
+  callerKey: "caller"
+  stacktraceKey: "stacktrace"
+  lineEnding: ""
+  levelEncoder: "capitalColor"
+  timeEncoder: "iso8601"
+  durationEncoder: "seconds"
+  callerEncoder: "short"
+  nameEncoder: ""
+
+outputPaths:
+  - "stderr"
+errorOutputPaths:
+  - "stderr"
+initialFields:
diff --git a/test/integrate/dubbo/go-client/user.go b/test/integrate/dubbo/go-client/user.go
new file mode 100644
index 0000000000000000000000000000000000000000..ff4486f07975ebbb0064a8c83b71c952e6311dbb
--- /dev/null
+++ b/test/integrate/dubbo/go-client/user.go
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+	"context"
+	"time"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+	"github.com/apache/dubbo-go/config"
+)
+
+var userProvider = new(UserProvider)
+
+func init() {
+	config.SetConsumerService(userProvider)
+	hessian.RegisterPOJO(&User{})
+}
+
+type User struct {
+	Id   string
+	Name string
+	Age  int32
+	Time time.Time
+}
+
+type UserProvider struct {
+	GetUser func(ctx context.Context, req []interface{}, rsp *User) error
+}
+
+func (u *UserProvider) Reference() string {
+	return "UserProvider"
+}
+
+func (User) JavaClassName() string {
+	return "com.ikurento.user.User"
+}
diff --git a/test/integrate/dubbo/go-client/version.go b/test/integrate/dubbo/go-client/version.go
new file mode 100644
index 0000000000000000000000000000000000000000..c6138584f1ddeab3a4927774f44f9e78a8f08da7
--- /dev/null
+++ b/test/integrate/dubbo/go-client/version.go
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+var (
+	Version = "2.6.0"
+)
diff --git a/test/integrate/dubbo/go-server/Dockerfile b/test/integrate/dubbo/go-server/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..c2f2d63462d94df7624ac100023e8b8c24e23e11
--- /dev/null
+++ b/test/integrate/dubbo/go-server/Dockerfile
@@ -0,0 +1,35 @@
+#
+#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.
+#
+
+FROM golang
+
+WORKDIR /go/src/github.com/apache/dubbo-go/test/integrate/dubbo/go-server
+
+ENV CONF_PROVIDER_FILE_PATH "server.yml"
+ENV APP_LOG_CONF_FILE "log.yml"
+
+ARG PR_ORIGIN_REPO
+ARG PR_ORIGIN_COMMITID
+
+ADD . /go/src/github.com/apache/dubbo-go/test/integrate/dubbo/go-server
+# update dubbo-go to current commit id
+RUN test ${PR_ORIGIN_REPO} && echo "github.com/apache/dubbo-go will be replace to github.com/${PR_ORIGIN_REPO}@${PR_ORIGIN_COMMITID}" || echo 'go get github.com/apache/dubbo-go@develop'
+RUN test ${PR_ORIGIN_REPO} && go mod edit  -replace=github.com/apache/dubbo-go=github.com/${PR_ORIGIN_REPO}@${PR_ORIGIN_COMMITID} || go get -u github.com/apache/dubbo-go@develop
+
+RUN go install github.com/apache/dubbo-go/test/integrate/dubbo/go-server
+
+CMD go-server
diff --git a/test/integrate/dubbo/go-server/go.mod b/test/integrate/dubbo/go-server/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..9e1162327de374fb131c2a0b89d1be3baa578a1b
--- /dev/null
+++ b/test/integrate/dubbo/go-server/go.mod
@@ -0,0 +1,3 @@
+module github.com/apache/dubbo-go/test/integrate/dubbo/go-server
+
+go 1.13
diff --git a/test/integrate/dubbo/go-server/log.yml b/test/integrate/dubbo/go-server/log.yml
new file mode 100644
index 0000000000000000000000000000000000000000..59fa4279ad85272c4c49d532beaf23b74d00f58a
--- /dev/null
+++ b/test/integrate/dubbo/go-server/log.yml
@@ -0,0 +1,28 @@
+
+level: "debug"
+development: true
+disableCaller: false
+disableStacktrace: false
+sampling:
+encoding: "console"
+
+# encoder
+encoderConfig:
+  messageKey: "message"
+  levelKey: "level"
+  timeKey: "time"
+  nameKey: "logger"
+  callerKey: "caller"
+  stacktraceKey: "stacktrace"
+  lineEnding: ""
+  levelEncoder: "capitalColor"
+  timeEncoder: "iso8601"
+  durationEncoder: "seconds"
+  callerEncoder: "short"
+  nameEncoder: ""
+
+outputPaths:
+  - "stderr"
+errorOutputPaths:
+  - "stderr"
+initialFields:
diff --git a/test/integrate/dubbo/go-server/server.go b/test/integrate/dubbo/go-server/server.go
new file mode 100644
index 0000000000000000000000000000000000000000..115bf0a4d78f171eb7f786808def91879ed93947
--- /dev/null
+++ b/test/integrate/dubbo/go-server/server.go
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+	"time"
+)
+
+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/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"
+	_ "github.com/apache/dubbo-go/registry/protocol"
+	_ "github.com/apache/dubbo-go/registry/zookeeper"
+)
+
+var (
+	stopC = make(chan struct{})
+)
+
+// they are necessary:
+// 		export CONF_PROVIDER_FILE_PATH="xxx"
+// 		export APP_LOG_CONF_FILE="xxx"
+func main() {
+
+	hessian.RegisterPOJO(&User{})
+	config.Load()
+
+	select {
+	case <-stopC:
+		// wait getty send resp to consumer
+		time.Sleep(3*time.Second)
+		return
+	case <-time.After(time.Minute):
+		panic("provider already running 1 min, but can't be call by consumer")
+	}
+}
diff --git a/test/integrate/dubbo/go-server/server.yml b/test/integrate/dubbo/go-server/server.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8a17297b10119c217e68b39d58a10493f6dfc7a7
--- /dev/null
+++ b/test/integrate/dubbo/go-server/server.yml
@@ -0,0 +1,57 @@
+# dubbo server yaml configure file
+
+
+# application config
+application:
+  organization : "ikurento.com"
+  name : "BDTService"
+  module : "dubbogo user-info server"
+  version : "0.0.1"
+  owner : "ZX"
+  environment : "dev"
+
+registries :
+  "demoZk":
+    protocol: "zookeeper"
+    timeout	: "3s"
+    address: "127.0.0.1:2181"
+
+services:
+  "UserProvider":
+    # 鍙互鎸囧畾澶氫釜registry锛屼娇鐢ㄩ€楀彿闅斿紑;涓嶆寚瀹氶粯璁ゅ悜鎵€鏈夋敞鍐屼腑蹇冩敞鍐�
+    registry: "demoZk"
+    protocol : "dubbo"
+    # 鐩稿綋浜巇ubbo.xml涓殑interface
+    interface : "com.ikurento.user.UserProvider"
+    loadbalance: "random"
+    warmup: "100"
+    cluster: "failover"
+    methods:
+    - name: "GetUser"
+      retries: 1
+      loadbalance: "random"
+
+protocols:
+  "dubbo":
+    name: "dubbo"
+    port: 20000
+
+
+protocol_conf:
+  dubbo:
+    session_number: 700
+    session_timeout: "20s"
+    getty_session_param:
+      compress_encoding: false
+      tcp_no_delay: true
+      tcp_keep_alive: true
+      keep_alive_period: "120s"
+      tcp_r_buf_size: 262144
+      tcp_w_buf_size: 65536
+      pkg_rq_size: 1024
+      pkg_wq_size: 512
+      tcp_read_timeout: "1s"
+      tcp_write_timeout: "5s"
+      wait_timeout: "1s"
+      max_msg_len: 1024000
+      session_name: "server"
diff --git a/test/integrate/dubbo/go-server/user.go b/test/integrate/dubbo/go-server/user.go
new file mode 100644
index 0000000000000000000000000000000000000000..7bff41566152940f885dec2eb256b261d04ad59a
--- /dev/null
+++ b/test/integrate/dubbo/go-server/user.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 main
+
+import (
+	"context"
+	"fmt"
+	"time"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+	"github.com/apache/dubbo-go/config"
+)
+
+func init() {
+	config.SetProviderService(new(UserProvider))
+	// ------for hessian2------
+	hessian.RegisterPOJO(&User{})
+}
+
+type User struct {
+	Id   string
+	Name string
+	Age  int32
+	Time time.Time
+}
+
+type UserProvider struct {
+}
+
+func (u *UserProvider) GetUser(ctx context.Context, req []interface{}) (*User, error) {
+	println("req:%#v", req)
+	rsp := User{"A001", "Alex Stocks", 18, time.Now()}
+	println("rsp:%#v", rsp)
+	close(stopC)
+	return &rsp, nil
+}
+
+func (u *UserProvider) Reference() string {
+	return "UserProvider"
+}
+
+func (u User) JavaClassName() string {
+	return "com.ikurento.user.User"
+}
+
+func println(format string, args ...interface{}) {
+	fmt.Printf("\033[32;40m"+format+"\033[0m\n", args...)
+}
diff --git a/test/integrate/dubbo/go-server/version.go b/test/integrate/dubbo/go-server/version.go
new file mode 100644
index 0000000000000000000000000000000000000000..c6138584f1ddeab3a4927774f44f9e78a8f08da7
--- /dev/null
+++ b/test/integrate/dubbo/go-server/version.go
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+var (
+	Version = "2.6.0"
+)