diff --git a/common/proxy/proxy.go b/common/proxy/proxy.go
index d511bc93cf0982cbaa2dfea6d63f26136943ad7b..8a2b65c6bf71271be77923da7baf766a770ea415 100644
--- a/common/proxy/proxy.go
+++ b/common/proxy/proxy.go
@@ -53,18 +53,26 @@ func (p *Proxy) Implement(v common.RPCService) {
 
 	makeDubboCallProxy := func(methodName string, outs []reflect.Type) func(in []reflect.Value) []reflect.Value {
 		return func(in []reflect.Value) []reflect.Value {
-
+			var (
+				err error
+				inv *invocation_impl.RPCInvocation
+			)
 			if methodName == "Echo" {
 				methodName = "$echo"
 			}
-			inv := invocation_impl.NewRPCInvocationForConsumer(methodName, nil, in[1].Interface().([]interface{}), in[2].Interface(), p.callBack, common.URL{}, nil)
+			if len(in) == 2 {
+				inv = invocation_impl.NewRPCInvocationForConsumer(methodName, nil, in[0].Interface().([]interface{}), in[1].Interface(), p.callBack, common.URL{}, nil)
+			}
+			if len(in) == 3 {
+				inv = invocation_impl.NewRPCInvocationForConsumer(methodName, nil, in[1].Interface().([]interface{}), in[2].Interface(), p.callBack, common.URL{}, nil)
+			}
 
 			for k, v := range p.attachments {
 				inv.SetAttachments(k, v)
 			}
 
 			result := p.invoke.Invoke(inv)
-			var err error
+
 			err = result.Error()
 			log.Info("[makeDubboCallProxy] err: %v", err)
 			return []reflect.Value{reflect.ValueOf(&err).Elem()}
@@ -76,20 +84,19 @@ func (p *Proxy) Implement(v common.RPCService) {
 		t := typeOf.Field(i)
 		f := valueOfElem.Field(i)
 		if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() {
-
-			if t.Type.NumIn() != 3 && t.Type.NumIn() != 4 {
+			if t.Type.NumIn() != 2 && t.Type.NumIn() != 3 {
 				log.Warn("method %s of mtype %v has wrong number of in parameters %d; needs exactly 3/4",
 					t.Name, t.Type.String(), t.Type.NumIn())
 				continue
 			}
 
-			if t.Type.NumIn() == 3 && t.Type.In(2).Kind() != reflect.Ptr {
-				log.Warn("reply type of method %q is not a pointer %v", t.Name, t.Type.In(2))
+			if t.Type.NumIn() == 2 && t.Type.In(1).Kind() != reflect.Ptr {
+				log.Warn("reply type of method %q is not a pointer %v", t.Name, t.Type.In(1))
 				continue
 			}
 
-			if t.Type.NumIn() == 4 && t.Type.In(3).Kind() != reflect.Ptr {
-				log.Warn("reply type of method %q is not a pointer %v", t.Name, t.Type.In(3))
+			if t.Type.NumIn() == 3 && t.Type.In(2).Kind() != reflect.Ptr {
+				log.Warn("reply type of method %q is not a pointer %v", t.Name, t.Type.In(2))
 				continue
 			}
 
diff --git a/common/proxy/proxy_test.go b/common/proxy/proxy_test.go
index 2335fa3c551efa9b9fd9c6d1c27f8f6e4a96d330..73a3fb8ba92bd673cfb8f1d89f04b0f245ed8bf5 100644
--- a/common/proxy/proxy_test.go
+++ b/common/proxy/proxy_test.go
@@ -34,7 +34,7 @@ func TestProxy_Implement(t *testing.T) {
 		return errors.New("errors")
 	}}
 	p.Implement(s)
-	err := s.MethodOne(nil, nil, nil)
+	err := p.Get().(*TestService).MethodOne(nil, nil, nil)
 	assert.NoError(t, err)
 
 	// inherit & lowercase
@@ -54,12 +54,11 @@ func TestProxy_Implement(t *testing.T) {
 	// args number
 	type S2 struct {
 		TestService
-		MethodOne func(context.Context, []interface{}) error
+		MethodOne func([]interface{}) error
 	}
 	s2 := &S2{TestService: *s}
 	p.Implement(s2)
 	assert.Nil(t, s2.MethodOne)
-	//assert.EqualError(t, err, "method MethodOne of mtype func(context.Context, []interface {}) error has wrong number of in parameters 2; needs exactly 3/4")
 
 	// returns number
 	type S3 struct {
@@ -69,7 +68,6 @@ func TestProxy_Implement(t *testing.T) {
 	s3 := &S3{TestService: *s}
 	p.Implement(s3)
 	assert.Nil(t, s3.MethodOne)
-	//assert.EqualError(t, err, "method \"MethodOne\" has 2 out parameters; needs exactly 1")
 
 	// returns type
 	type S4 struct {
@@ -79,9 +77,8 @@ func TestProxy_Implement(t *testing.T) {
 	s4 := &S4{TestService: *s}
 	p.Implement(s4)
 	assert.Nil(t, s4.MethodOne)
-	//assert.EqualError(t, err, "return type interface {} of method \"MethodOne\" is not error")
 
-	// reply type
+	// reply type for number 3
 	type S5 struct {
 		TestService
 		MethodOne func(context.Context, []interface{}, interface{}) error
@@ -89,6 +86,13 @@ func TestProxy_Implement(t *testing.T) {
 	s5 := &S5{TestService: *s}
 	p.Implement(s5)
 	assert.Nil(t, s5.MethodOne)
-	//assert.EqualError(t, err, "reply type of method \"MethodOne\" is not a pointer interface {}")
 
+	// reply type for number 2
+	type S6 struct {
+		TestService
+		MethodOne func([]interface{}, interface{}) error
+	}
+	s6 := &S6{TestService: *s}
+	p.Implement(s6)
+	assert.Nil(t, s5.MethodOne)
 }
diff --git a/common/rpc_service_test.go b/common/rpc_service_test.go
index 768c83ce47f2fa4915a47a216ed2b79bf3e813bd..6d72bf5e56f4eefe1404f92555dcb7fb91265d9f 100644
--- a/common/rpc_service_test.go
+++ b/common/rpc_service_test.go
@@ -2,6 +2,7 @@ package common
 
 import (
 	"context"
+	"reflect"
 	"testing"
 )
 
@@ -15,12 +16,10 @@ type TestService struct {
 func (s *TestService) MethodOne(ctx context.Context, args []interface{}, rsp *struct{}) error {
 	return nil
 }
-
-func (s *TestService) MethodTwo(ctx context.Context, args []interface{}, rsp *struct{}) error {
+func (s *TestService) MethodTwo(args []interface{}, rsp *struct{}) error {
 	return nil
 
 }
-
 func (s *TestService) Service() string {
 	return "com.test.Path"
 }
@@ -28,9 +27,132 @@ func (s *TestService) Version() string {
 	return ""
 }
 
+type testService struct {
+}
+
+func (s *testService) Method1(ctx context.Context, args testService, rsp *struct{}) error {
+	return nil
+}
+func (s *testService) Method2(ctx context.Context, args []interface{}, rsp struct{}) error {
+	return nil
+}
+func (s *testService) Method3(ctx context.Context, args []interface{}, rsp *testService) error {
+	return nil
+}
+func (s *testService) Method4(ctx context.Context, args []interface{}, rsp *struct{}) {
+}
+func (s *testService) Method5(ctx context.Context, args []interface{}, rsp *struct{}) *testService {
+	return nil
+}
+func (s *testService) Service() string {
+	return "com.test.Path"
+}
+func (s *testService) Version() string {
+	return ""
+}
+
+type TestService1 struct {
+}
+
+func (s *TestService1) Service() string {
+	return "com.test.Path1"
+}
+func (s *TestService1) Version() string {
+	return ""
+}
+
 func TestServiceMap_Register(t *testing.T) {
+	// lowercase
+	s0 := &testService{}
+	methods, err := ServiceMap.Register("testporotocol", s0)
+	assert.EqualError(t, err, "type testService is not exported")
+
+	// succ
 	s := &TestService{}
-	methods, err := ServiceMap.Register("testporotocol", s)
+	methods, err = ServiceMap.Register("testporotocol", s)
 	assert.NoError(t, err)
 	assert.Equal(t, "MethodOne,MethodTwo", methods)
+
+	// repeat
+	methods, err = ServiceMap.Register("testporotocol", s)
+	assert.EqualError(t, err, "service already defined: com.test.Path")
+
+	// no method
+	s1 := &TestService1{}
+	methods, err = ServiceMap.Register("testporotocol", s1)
+	assert.EqualError(t, err, "type com.test.Path1 has no exported methods of suitable type")
+}
+
+func TestMethodType_SuiteContext(t *testing.T) {
+	mt := &MethodType{ctxType: reflect.TypeOf(context.TODO())}
+	c := context.TODO()
+	c = context.WithValue(c, "key", "value")
+	assert.Equal(t, reflect.ValueOf(c), mt.SuiteContext(c))
+
+	assert.Equal(t, reflect.Zero(mt.ctxType), mt.SuiteContext(nil))
+}
+
+func TestSuiteMethod(t *testing.T) {
+	// 4
+	s := &TestService{}
+	method, ok := reflect.TypeOf(s).MethodByName("MethodOne")
+	assert.True(t, ok)
+	methodType := suiteMethod(method)
+	method = methodType.Method()
+	assert.Equal(t, "func(*common.TestService, context.Context, []interface {}, *struct {}) error", method.Type.String())
+	at := methodType.ArgType()
+	assert.Equal(t, "[]interface {}", at.String())
+	ct := methodType.CtxType()
+	assert.Equal(t, "context.Context", ct.String())
+	rt := methodType.ReplyType()
+	assert.Equal(t, "*struct {}", rt.String())
+
+	// 3
+	method, ok = reflect.TypeOf(s).MethodByName("MethodTwo")
+	assert.True(t, ok)
+	methodType = suiteMethod(method)
+	method = methodType.Method()
+	assert.Equal(t, "func(*common.TestService, []interface {}, *struct {}) error", method.Type.String())
+	at = methodType.ArgType()
+	assert.Equal(t, "[]interface {}", at.String())
+	assert.Nil(t, methodType.CtxType())
+	rt = methodType.ReplyType()
+	assert.Equal(t, "*struct {}", rt.String())
+
+	// wrong number of in parameters
+	s1 := &testService{}
+	method, ok = reflect.TypeOf(s1).MethodByName("Version")
+	assert.True(t, ok)
+	methodType = suiteMethod(method)
+	assert.Nil(t, methodType)
+
+	// args not exported
+	method, ok = reflect.TypeOf(s1).MethodByName("Method1")
+	assert.True(t, ok)
+	methodType = suiteMethod(method)
+	assert.Nil(t, methodType)
+
+	// replyType != Ptr
+	method, ok = reflect.TypeOf(s1).MethodByName("Method2")
+	assert.True(t, ok)
+	methodType = suiteMethod(method)
+	assert.Nil(t, methodType)
+
+	// Reply not exported
+	method, ok = reflect.TypeOf(s1).MethodByName("Method3")
+	assert.True(t, ok)
+	methodType = suiteMethod(method)
+	assert.Nil(t, methodType)
+
+	// no return
+	method, ok = reflect.TypeOf(s1).MethodByName("Method4")
+	assert.True(t, ok)
+	methodType = suiteMethod(method)
+	assert.Nil(t, methodType)
+
+	// return value is not error
+	method, ok = reflect.TypeOf(s1).MethodByName("Method5")
+	assert.True(t, ok)
+	methodType = suiteMethod(method)
+	assert.Nil(t, methodType)
 }
diff --git a/common/url.go b/common/url.go
index a24a03c1f10e447d66a6a5f0bdef5e878d58807d..e67a59e514a71c18751236c9f8cc454fba240cfd 100644
--- a/common/url.go
+++ b/common/url.go
@@ -216,9 +216,7 @@ func (c URL) String() string {
 	buildString := fmt.Sprintf(
 		"%s://%s:%s@%s:%s%s?",
 		c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Path)
-	for k, v := range c.Params {
-		buildString += "&" + k + "=" + v[0]
-	}
+	buildString += c.Params.Encode()
 	return buildString
 }
 
@@ -265,7 +263,7 @@ func (c URL) GetMethodParamInt(method string, key string, d int64) int64 {
 
 func (c URL) GetMethodParam(method string, key string, d string) string {
 	var r string
-	if r = c.Params.Get(c.Params.Get("methods." + method + "." + key)); r == "" {
+	if r = c.Params.Get("methods." + method + "." + key); r == "" {
 		r = d
 	}
 	return r
diff --git a/common/url_test.go b/common/url_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..336ec9ee7a93111514a72b2afae7683435173459
--- /dev/null
+++ b/common/url_test.go
@@ -0,0 +1,121 @@
+package common
+
+import (
+	"context"
+	"net/url"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewURLWithOptions(t *testing.T) {
+	methods := []string{"Methodone,methodtwo"}
+	params := url.Values{}
+	params.Set("key", "value")
+	u := NewURLWithOptions("com.test.Service",
+		WithUsername("username"),
+		WithPassword("password"),
+		WithProtocol("testprotocol"),
+		WithIp("127.0.0.1"),
+		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, "testprotocol", u.Protocol)
+	assert.Equal(t, "127.0.0.1", u.Ip)
+	assert.Equal(t, "8080", u.Port)
+	assert.Equal(t, methods, u.Methods)
+	assert.Equal(t, params, u.Params)
+}
+
+func TestURL(t *testing.T) {
+	u, err := NewURL(context.TODO(), "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
+		"side=provider&timeout=3000&timestamp=1556509797245")
+	assert.NoError(t, err)
+
+	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, "20000", u.Port)
+	assert.Equal(t, URL{}.Methods, u.Methods)
+	assert.Equal(t, "", u.Username)
+	assert.Equal(t, "", u.Password)
+	assert.Equal(t, "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&t"+
+		"imestamp=1556509797245", u.Params.Encode())
+
+	assert.Equal(t, "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&application=BDTServi"+
+		"ce&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&environment=dev&interface=com.ikure"+
+		"nto.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", u.String())
+}
+
+func TestURL_URLEqual(t *testing.T) {
+	u1, err := NewURL(context.TODO(), "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
+	assert.NoError(t, err)
+	u2, err := NewURL(context.TODO(), "dubbo://:@127.0.0.2:20001/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
+	assert.NoError(t, err)
+	assert.True(t, u1.URLEqual(u2))
+
+	u3, err := NewURL(context.TODO(), "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0")
+	assert.NoError(t, err)
+	assert.False(t, u1.URLEqual(u3))
+}
+
+func TestURL_GetParam(t *testing.T) {
+	params := url.Values{}
+	params.Set("key", "value")
+	u := URL{baseUrl: baseUrl{Params: params}}
+	v := u.GetParam("key", "default")
+	assert.Equal(t, "value", v)
+
+	u = URL{}
+	v = u.GetParam("key", "default")
+	assert.Equal(t, "default", v)
+}
+
+func TestURL_GetParamInt(t *testing.T) {
+	params := url.Values{}
+	params.Set("key", "3")
+	u := URL{baseUrl: baseUrl{Params: params}}
+	v := u.GetParamInt("key", 1)
+	assert.Equal(t, int64(3), v)
+
+	u = URL{}
+	v = u.GetParamInt("key", 1)
+	assert.Equal(t, int64(1), v)
+}
+
+func TestURL_GetMethodParamInt(t *testing.T) {
+	params := url.Values{}
+	params.Set("methods.GetValue.timeout", "3")
+	u := URL{baseUrl: baseUrl{Params: params}}
+	v := u.GetMethodParamInt("GetValue", "timeout", 1)
+	assert.Equal(t, int64(3), v)
+
+	u = URL{}
+	v = u.GetMethodParamInt("GetValue", "timeout", 1)
+	assert.Equal(t, int64(1), v)
+}
+
+func TestURL_GetMethodParam(t *testing.T) {
+	params := url.Values{}
+	params.Set("methods.GetValue.timeout", "3s")
+	u := URL{baseUrl: baseUrl{Params: params}}
+	v := u.GetMethodParam("GetValue", "timeout", "1s")
+	assert.Equal(t, "3s", v)
+
+	u = URL{}
+	v = u.GetMethodParam("GetValue", "timeout", "1s")
+	assert.Equal(t, "1s", v)
+}